1313#include <string.h>
1414#include <math.h>
1515
16+ #ifdef USE_MKL
17+ #include <mkl.h>
18+ #else
19+ #include <cblas.h>
20+ #include <lapacke.h>
21+ #endif
22+
1623#include "md.h"
1724#include "isddft.h"
1825#include "orbitalElecDensInit.h"
@@ -2135,11 +2142,68 @@ void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) {
21352142 //*avgdis = pow((pSPARC->range_x * pSPARC->range_y * pSPARC->range_z)/pSPARC->n_atom,1/3.0);
21362143 int atm2 , ityp2 , cc2 , pairIndex ;
21372144 cc = 0 ;
2145+
2146+ // Store the cell as a 3x3 lattice vector
2147+ double * lattice = (double * )calloc (sizeof (double ), 9 );
2148+ double cell [3 ] = {pSPARC -> range_x , pSPARC -> range_y , pSPARC -> range_z };
2149+ double dr [3 ];
2150+ int row , col ;
2151+ for (row = 0 ; row < 3 ; row ++ ) {
2152+ lattice [row * 3 ] = pSPARC -> LatUVec [row * 3 ] * cell [row ];
2153+ lattice [row * 3 + 1 ] = pSPARC -> LatUVec [row * 3 + 1 ] * cell [row ];
2154+ lattice [row * 3 + 2 ] = pSPARC -> LatUVec [row * 3 + 2 ] * cell [row ];
2155+ }
2156+
2157+ // Calculate the inverse of lattice-vector
2158+ double LV_inv [9 ], U [9 ], S [3 ], VT [9 ], superb [2 ], temp_mat [9 ], LatVec [9 ];
2159+ double S_inv [9 ] = {0 };
2160+ int m = 3 ;
2161+
2162+ for (int JJ = 0 ; JJ < 9 ; JJ ++ ) {
2163+ LatVec [JJ ] = lattice [JJ ];
2164+ }
2165+
2166+ /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */
2167+ // Compute SVD of LatVec(LV) first: LV = U * S * V^T
2168+ LAPACKE_dgesvd (LAPACK_ROW_MAJOR , 'A' , 'A' , m , m , LatVec , m , S , U , m , VT , m , superb );
2169+
2170+ // First compute S^{-1}
2171+ for (int i = 0 ; i < 3 ; i ++ ) {
2172+ if (S [i ] > 1e-12 ) S_inv [i * 3 + i ] = 1.0 /S [i ];
2173+ }
2174+
2175+ // Compute LV^{-1} = V * S^{-1} * U^T
2176+ cblas_dgemm (CblasRowMajor , CblasTrans , CblasNoTrans , m , m , m , 1.0 , VT , m , S_inv , m , 0.0 , temp_mat , m );
2177+ cblas_dgemm (CblasRowMajor , CblasNoTrans , CblasTrans , m , m , m , 1.0 , temp_mat , m , U , m , 0.0 , LV_inv , m );
2178+
21382179 for (ityp = 0 ; ityp < pSPARC -> Ntypes ; ityp ++ ){
21392180 mindis [ityp ] = 1000000000.0 ;
21402181 for (atm = 0 ; atm < pSPARC -> nAtomv [ityp ] - 1 ; atm ++ ){
21412182 for (atm2 = atm + 1 ; atm2 < pSPARC -> nAtomv [ityp ]; atm2 ++ ){
2142- 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 ) ));
2183+ // 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) ));
2184+
2185+ // Vector connecting atoms atm and atm2
2186+ dr [0 ] = pSPARC -> atom_pos [3 * (atm + cc )] - pSPARC -> atom_pos [3 * (atm2 + cc )];
2187+ dr [1 ] = pSPARC -> atom_pos [3 * (atm + cc ) + 1 ] - pSPARC -> atom_pos [3 * (atm2 + cc ) + 1 ];
2188+ dr [2 ] = pSPARC -> atom_pos [3 * (atm + cc ) + 2 ] - pSPARC -> atom_pos [3 * (atm2 + cc ) + 2 ];
2189+
2190+ double frac [3 ], dr_pbc [3 ];
2191+
2192+ // Minimum Image Convention (MIC) in fractional coordinates
2193+ // frac = LV^{-1} * dr
2194+ cblas_dgemv (CblasRowMajor , CblasNoTrans , m , m , 1.0 , LV_inv , m , dr , 1 , 0.0 , frac , 1 );
2195+
2196+ // Wrap into [-0.5, 0.5)
2197+ frac [0 ] -= round (frac [0 ]);
2198+ frac [1 ] -= round (frac [1 ]);
2199+ frac [2 ] -= round (frac [2 ]);
2200+
2201+ // dr_pbc = lattice * frac
2202+ cblas_dgemv (CblasRowMajor , CblasNoTrans , m , m , 1.0 , lattice , 3 , frac , 1 , 0.0 , dr_pbc , 1 );
2203+
2204+ // Calculate distance
2205+ temp = sqrt (dr_pbc [0 ]* dr_pbc [0 ] + dr_pbc [1 ]* dr_pbc [1 ] + dr_pbc [2 ]* dr_pbc [2 ]);
2206+
21432207 if (temp < mindis [ityp ])
21442208 mindis [ityp ] = temp ;
21452209 }
@@ -2155,7 +2219,30 @@ void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) {
21552219 mindis [pairIndex ] = 1000000000.0 ;
21562220 for (atm = 0 ; atm < pSPARC -> nAtomv [ityp ]; atm ++ ){
21572221 for (atm2 = 0 ; atm2 < pSPARC -> nAtomv [ityp2 ]; atm2 ++ ){
2158- 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 ) ));
2222+ // 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) ));
2223+
2224+ // Vector connecting atoms atm and atm2
2225+ dr [0 ] = pSPARC -> atom_pos [3 * (atm + cc )] - pSPARC -> atom_pos [3 * (atm2 + cc2 )];
2226+ dr [1 ] = pSPARC -> atom_pos [3 * (atm + cc ) + 1 ] - pSPARC -> atom_pos [3 * (atm2 + cc2 ) + 1 ];
2227+ dr [2 ] = pSPARC -> atom_pos [3 * (atm + cc ) + 2 ] - pSPARC -> atom_pos [3 * (atm2 + cc2 ) + 2 ];
2228+
2229+ double frac [3 ], dr_pbc [3 ];
2230+
2231+ // Minimum Image Convention (MIC) in fractional coordinates
2232+ // frac = LV^{-1} * dr
2233+ cblas_dgemv (CblasRowMajor , CblasNoTrans , m , m , 1.0 , LV_inv , m , dr , 1 , 0.0 , frac , 1 );
2234+
2235+ // Wrap into [-0.5, 0.5)
2236+ frac [0 ] -= round (frac [0 ]);
2237+ frac [1 ] -= round (frac [1 ]);
2238+ frac [2 ] -= round (frac [2 ]);
2239+
2240+ // dr_pbc = lattice * frac
2241+ cblas_dgemv (CblasRowMajor , CblasNoTrans , m , m , 1.0 , lattice , 3 , frac , 1 , 0.0 , dr_pbc , 1 );
2242+
2243+ // Calculate distance
2244+ temp = sqrt (dr_pbc [0 ]* dr_pbc [0 ] + dr_pbc [1 ]* dr_pbc [1 ] + dr_pbc [2 ]* dr_pbc [2 ]);
2245+
21592246 if (temp < mindis [pairIndex ])
21602247 mindis [pairIndex ] = temp ;
21612248 }
@@ -2165,6 +2252,7 @@ void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) {
21652252 }
21662253 cc += pSPARC -> nAtomv [ityp ];
21672254 }
2255+ free (lattice );
21682256}
21692257
21702258/*
0 commit comments