4 torch::jit::script::Module Model;
7 std::vector<Atoms> UCAtoms;
8 std::vector<Atoms> ReplicaAtoms;
10 double Cutoffsq = 0.0;
12 int3 NReplicacell = {1,1,1};
14 size_t DNN_Molsize = 0;
18 void GetSQ_From_Cutoff()
20 Cutoffsq = Cutoff * Cutoff;
23 double dot(double3 a, double3 b)
25 return a.x * b.x + a.y * b.y + a.z * b.z;
27 double matrix_determinant(
double* x)
29 double m11 = x[0*3+0];
double m21 = x[1*3+0];
double m31 = x[2*3+0];
30 double m12 = x[0*3+1];
double m22 = x[1*3+1];
double m32 = x[2*3+1];
31 double m13 = x[0*3+2];
double m23 = x[1*3+2];
double m33 = x[2*3+2];
32 double determinant = +m11 * (m22 * m33 - m23 * m32) - m12 * (m21 * m33 - m23 * m31) + m13 * (m21 * m32 - m22 * m31);
36 void inverse_matrix(
double* x,
double **inverse_x)
38 double m11 = x[0*3+0];
double m21 = x[1*3+0];
double m31 = x[2*3+0];
39 double m12 = x[0*3+1];
double m22 = x[1*3+1];
double m32 = x[2*3+1];
40 double m13 = x[0*3+2];
double m23 = x[1*3+2];
double m33 = x[2*3+2];
41 double determinant = +m11 * (m22 * m33 - m23 * m32) - m12 * (m21 * m33 - m23 * m31) + m13 * (m21 * m32 - m22 * m31);
42 double* result = (
double*) malloc(9 *
sizeof(
double));
43 result[0] = +(m22 * m33 - m32 * m23) / determinant;
44 result[3] = -(m21 * m33 - m31 * m23) / determinant;
45 result[6] = +(m21 * m32 - m31 * m22) / determinant;
46 result[1] = -(m12 * m33 - m32 * m13) / determinant;
47 result[4] = +(m11 * m33 - m31 * m13) / determinant;
48 result[7] = -(m11 * m32 - m31 * m12) / determinant;
49 result[2] = +(m12 * m23 - m22 * m13) / determinant;
50 result[5] = -(m11 * m23 - m21 * m13) / determinant;
51 result[8] = +(m11 * m22 - m21 * m12) / determinant;
55 __host__ double3 GetFractionalCoord(
double* InverseCell,
bool Cubic, double3 posvec)
57 double3 s = {0.0, 0.0, 0.0};
58 s.x=InverseCell[0*3+0]*posvec.x + InverseCell[1*3+0]*posvec.y + InverseCell[2*3+0]*posvec.z;
59 s.y=InverseCell[0*3+1]*posvec.x + InverseCell[1*3+1]*posvec.y + InverseCell[2*3+1]*posvec.z;
60 s.z=InverseCell[0*3+2]*posvec.x + InverseCell[1*3+2]*posvec.y + InverseCell[2*3+2]*posvec.z;
64 __host__ double3 GetRealCoordFromFractional(
double* Cell,
bool Cubic, double3 s)
66 double3 posvec = {0.0, 0.0, 0.0};
67 posvec.x=Cell[0*3+0]*s.x+Cell[1*3+0]*s.y+Cell[2*3+0]*s.z;
68 posvec.y=Cell[0*3+1]*s.x+Cell[1*3+1]*s.y+Cell[2*3+1]*s.z;
69 posvec.z=Cell[0*3+2]*s.x+Cell[1*3+2]*s.y+Cell[2*3+2]*s.z;
73 std::vector<std::string> split(
const std::string txt,
char ch)
75 size_t pos = txt.find(ch);
76 size_t initialPos = 0;
77 std::vector<std::string> strs{};
80 while (pos != std::string::npos) {
82 std::string s = txt.substr(initialPos, pos - initialPos);
89 pos = txt.find(ch, initialPos);
93 std::string s = txt.substr(initialPos, std::min(pos, txt.size()) - initialPos + 1);
102 bool caseInSensStringCompare(
const std::string& str1,
const std::string& str2)
104 return str1.size() == str2.size() && std::equal(str1.begin(), str1.end(), str2.begin(), [](
auto a,
auto b) {return std::tolower(a) == std::tolower(b); });
107 void Split_Tab_Space(std::vector<std::string>& termsScannedLined, std::string& str)
109 if (str.find(
"\t", 0) != std::string::npos)
111 termsScannedLined = split(str,
'\t');
115 termsScannedLined = split(str,
' ');
148 void AllocateUCSpace(
size_t comp)
150 UCAtoms[comp].pos = (double3*) malloc(UCAtoms[comp].size *
sizeof(double3));
151 UCAtoms[comp].Type = (
size_t*) malloc(UCAtoms[comp].size *
sizeof(
size_t));
154 void GenerateUCBox(
double* SuperCell, int3 Ncell)
156 UCBox.Cell = (
double*) malloc(9 *
sizeof(
double));
157 UCBox.InverseCell = (
double*) malloc(9 *
sizeof(
double));
158 for(
size_t i = 0; i < 9; i++) UCBox.Cell[i] = SuperCell[i];
159 UCBox.Cell[0] /= Ncell.x; UCBox.Cell[1] = 0.0; UCBox.Cell[2] = 0.0;
160 UCBox.Cell[3] /= Ncell.y; UCBox.Cell[4] /= Ncell.y; UCBox.Cell[5] = 0.0;
161 UCBox.Cell[6] /= Ncell.z; UCBox.Cell[7] /= Ncell.z; UCBox.Cell[8] /= Ncell.z;
162 inverse_matrix(UCBox.Cell, &UCBox.InverseCell);
172 void CopyAtomsFromFirstUnitcell(
Atoms& HostAtoms,
size_t comp, int3 NSupercell,
PseudoAtomDefinitions& PseudoAtoms,
bool* ConsiderThisAdsorbateAtom)
174 size_t NAtoms = HostAtoms.Molsize / (NSupercell.x * NSupercell.y * NSupercell.z);
175 if(HostAtoms.size % NAtoms != 0)
throw std::runtime_error(
"SuperCell size cannot be divided by number of supercell atoms!!!!");
176 UCAtoms[comp].size = NAtoms;
180 for(
size_t i = 0; i < NAtoms; i++)
181 if(ConsiderThisAdsorbateAtom[i])
184 if(comp != 0) UCAtoms[comp].size = DNN_Molsize;
185 AllocateUCSpace(comp);
188 for(
size_t i = 0; i < NAtoms; i++)
191 if(!ConsiderThisAdsorbateAtom[i])
continue;
192 UCAtoms[comp].pos[update_i] = HostAtoms.pos[i];
193 size_t SymbolIdx = PseudoAtoms.GetSymbolIdxFromPseudoAtomTypeIdx(HostAtoms.Type[i]);
194 UCAtoms[comp].Type[update_i] = SymbolIdx;
220 void ReadModel(std::string Name)
225 auto device = torch::kCUDA;
227 std::unordered_map<std::string, std::string> metadata =
230 {
"nequip_version",
""},
234 {
"_jit_bailout_depth",
""},
235 {
"_jit_fusion_strategy",
""},
238 Model = torch::jit::load(ModelName, device, metadata);
241 Model = torch::jit::freeze(Model);
247 size_t nAtoms = 0;
for(
size_t i = 0; i < UCAtoms.size(); i++) nAtoms += UCAtoms[i].size;
248 size_t ntotal = 0;
for(
size_t i = 0; i < ReplicaAtoms.size(); i++) ntotal += ReplicaAtoms[i].size;
250 torch::Tensor edges_tensor = torch::zeros({2,NL.nedges}, torch::TensorOptions().dtype(torch::kInt64));
251 auto edges = edges_tensor.accessor<long, 2>();
253 torch::Tensor pos_tensor = torch::zeros({ntotal, 3});
254 auto pos = pos_tensor.accessor<float, 2>();
256 torch::Tensor ij2type_tensor = torch::zeros({ntotal}, torch::TensorOptions().dtype(torch::kInt64));
257 auto ij2type = ij2type_tensor.accessor<long, 1>();
260 for(
size_t comp = 0; comp < ReplicaAtoms.size(); comp++)
261 for(
size_t i = 0; i < ReplicaAtoms[comp].size; i++)
263 pos[counter][0] = ReplicaAtoms[comp].pos[i].x;
264 pos[counter][1] = ReplicaAtoms[comp].pos[i].y;
265 pos[counter][2] = ReplicaAtoms[comp].pos[i].z;
266 ij2type[counter]= ReplicaAtoms[comp].Type[i];
271 size_t N_Replica_FrameworkAtoms = 0;
size_t NFrameworkAtoms = 0;
272 N_Replica_FrameworkAtoms = ReplicaAtoms[0].size;
273 NFrameworkAtoms = UCAtoms[0].size;
274 for(
size_t i = 0; i < nAtoms; i++)
276 for(
size_t j = 0; j < NL.List[i].size(); j++)
278 size_t edge_counter = NL.List[i][j].z;
279 edges[0][edge_counter] = NL.List[i][j].x;
282 if(NL.List[i][j].x >= NFrameworkAtoms)
284 edges[0][edge_counter] -= NFrameworkAtoms;
285 edges[0][edge_counter] += (N_Replica_FrameworkAtoms);
287 edges[1][edge_counter] = NL.List[i][j].y;
295 auto device = torch::kCUDA;
296 c10::Dict<std::string, torch::Tensor> input;
297 input.insert(
"pos", pos_tensor.to(device));
298 input.insert(
"edge_index", edges_tensor.to(device));
299 input.insert(
"atom_types", ij2type_tensor.to(device));
300 std::vector<torch::IValue> input_vector(1, input);
302 auto output = Model.forward(input_vector).toGenericDict();
304 torch::Tensor atomic_energy_tensor = output.at(
"atomic_energy").toTensor().cpu();
305 auto atomic_energies = atomic_energy_tensor.accessor<float, 2>();
307 float atomic_energy_sum = atomic_energy_tensor.sum().data_ptr<
float>()[0];
309 float nAtomSum = 0.0;
310 for(
size_t i = 0; i < nAtoms; i++)
312 size_t AtomIndex = i;
313 if(i >= NFrameworkAtoms)
315 AtomIndex -= NFrameworkAtoms;
316 AtomIndex += N_Replica_FrameworkAtoms;
318 nAtomSum += atomic_energies[AtomIndex][0];
322 return static_cast<double>(nAtomSum);
325 void ReplicateAtomsPerComponent(
size_t comp,
bool Allocate)
328 std::vector<double3>fpos;
329 for(
size_t i = 0; i < UCAtoms[comp].size; i++)
331 fpos.push_back(GetFractionalCoord(UCBox.InverseCell, UCBox.Cubic, UCAtoms[comp].pos[i]));
334 size_t NTotalCell =
static_cast<size_t>(NReplicacell.x * NReplicacell.y * NReplicacell.z);
335 double3 Shift = {(double)1/NReplicacell.x, (
double)1/NReplicacell.y, (double)1/NReplicacell.z};
336 if(NReplicacell.x % 2 == 0)
throw std::runtime_error(
"Ncell in x needs to be an odd number (so that original unit cell sits in the center\n");
337 if(NReplicacell.y % 2 == 0)
throw std::runtime_error(
"Ncell in y needs to be an odd number (so that original unit cell sits in the center\n");
338 if(NReplicacell.z % 2 == 0)
throw std::runtime_error(
"Ncell in z needs to be an odd number (so that original unit cell sits in the center\n");
339 int Minx = (NReplicacell.x - 1)/2 * -1;
int Maxx = (NReplicacell.x - 1)/2;
340 int Miny = (NReplicacell.y - 1)/2 * -1;
int Maxy = (NReplicacell.y - 1)/2;
341 int Minz = (NReplicacell.z - 1)/2 * -1;
int Maxz = (NReplicacell.z - 1)/2;
342 std::vector<int>xs; std::vector<int>ys; std::vector<int>zs;
346 for(
int i = Minx; i <= Maxx; i++)
349 for(
int i = Miny; i <= Maxy; i++)
352 for(
int i = Minz; i <= Maxz; i++)
358 ReplicaAtoms[comp].pos = (double3*) malloc(NTotalCell * UCAtoms[comp].size *
sizeof(double3));
359 ReplicaAtoms[comp].Type = (
size_t*) malloc(NTotalCell * UCAtoms[comp].size *
sizeof(
size_t));
362 for(
size_t a = 0; a < static_cast<size_t>(NReplicacell.x); a++)
363 for(
size_t b = 0; b < static_cast<size_t>(NReplicacell.y); b++)
364 for(
size_t c = 0; c < static_cast<size_t>(NReplicacell.z); c++)
370 double3 NCellID = {(double) ix, (
double) jy, (double) kz};
371 for(
size_t i = 0; i < UCAtoms[comp].size; i++)
373 double3 temp = {fpos[i].x + NCellID.x,
374 fpos[i].y + NCellID.y,
375 fpos[i].z + NCellID.z};
376 double3 super_fpos = {temp.x * Shift.x,
381 Replica_pos.x = super_fpos.x*ReplicaBox.Cell[0]+super_fpos.y*ReplicaBox.Cell[3]+super_fpos.z*ReplicaBox.Cell[6];
382 Replica_pos.y = super_fpos.x*ReplicaBox.Cell[1]+super_fpos.y*ReplicaBox.Cell[4]+super_fpos.z*ReplicaBox.Cell[7];
383 Replica_pos.z = super_fpos.x*ReplicaBox.Cell[2]+super_fpos.y*ReplicaBox.Cell[5]+super_fpos.z*ReplicaBox.Cell[8];
384 ReplicaAtoms[comp].pos[counter] = Replica_pos;
385 ReplicaAtoms[comp].Type[counter] = UCAtoms[comp].Type[i];
389 ReplicaAtoms[comp].size = NTotalCell * UCAtoms[comp].size;
394 void GenerateReplicaCells(
bool Allocate)
396 size_t NComp = UCAtoms.size();
397 size_t N_UCAtom = 0;
for(
size_t comp = 0; comp < NComp; comp++) N_UCAtom += UCAtoms[comp].size;
400 ReplicaBox.Cell = (
double*) malloc(9 *
sizeof(
double));
401 ReplicaBox.InverseCell = (
double*) malloc(9 *
sizeof(
double));
402 for(
size_t i = 0; i < 9; i++) ReplicaBox.Cell[i] = UCBox.Cell[i];
404 ReplicaBox.Cell[0] *= NReplicacell.x; ReplicaBox.Cell[1] *= 0.0; ReplicaBox.Cell[2] *= 0.0;
405 ReplicaBox.Cell[3] *= NReplicacell.y; ReplicaBox.Cell[4] *= NReplicacell.y; ReplicaBox.Cell[5] *= 0.0;
406 ReplicaBox.Cell[6] *= NReplicacell.z; ReplicaBox.Cell[7] *= NReplicacell.z; ReplicaBox.Cell[8] *= NReplicacell.z;
408 printf(
"a: %f, b: %f, c: %f\n", ReplicaBox.Cell[0], ReplicaBox.Cell[4], ReplicaBox.Cell[8]);
409 inverse_matrix(ReplicaBox.Cell, &ReplicaBox.InverseCell);
412 for(
size_t comp = 0; comp < UCAtoms.size(); comp++)
413 if(Allocate || comp != 0)
414 ReplicateAtomsPerComponent(comp, Allocate);
416 void Get_Neighbor_List_Replica(
bool Initialize)
418 if(Initialize) GetSQ_From_Cutoff();
419 size_t AtomCount = 0;
420 for(
size_t comp = 0; comp < UCAtoms.size(); comp++)
422 for(
size_t j = 0; j < UCAtoms[comp].size; j++)
424 std::vector<int3>Neigh_per_atom;
427 NL.List.push_back(Neigh_per_atom);
428 NL.cumsum_neigh_per_atom.push_back(0);
432 NL.List[AtomCount] = Neigh_per_atom;
433 NL.cumsum_neigh_per_atom[AtomCount] = 0;
439 if(!Initialize) Copy_From_Rigid_Framework_Edges(UCAtoms[0].size);
442 for(
size_t compi = 0; compi < UCAtoms.size(); compi++)
445 for(
size_t compj = 0; compj < ReplicaAtoms.size(); compj++)
447 if(Initialize || (compi != 0 || compj != 0))
450 bool SameComponent =
false;
if(compi == compj) SameComponent =
true;
451 Count_Edges_Replica(compi, compj, i_start, j_start, SameComponent);
452 if(Initialize && compi == 0 && compj == 0) Copy_To_Rigid_Framework_Edges(UCAtoms[0].size);
454 j_start += ReplicaAtoms[compj].size;
456 i_start += UCAtoms[compi].size;
459 for(
size_t i = 0; i < NL.List.size(); i++)
461 size_t nedge_perAtom = NL.List[i].size();
462 if(i != 0) prev = NL.cumsum_neigh_per_atom[i-1];
463 NL.cumsum_neigh_per_atom[i] = prev + nedge_perAtom;
468 void Count_Edges_Replica(
size_t compi,
size_t compj,
size_t i_start,
size_t j_start,
bool SameComponent)
471 for(
size_t i = 0; i < UCAtoms[compi].size; i++)
473 size_t i_idx = i_start + i;
474 for(
size_t j = 0; j < ReplicaAtoms[compj].size; j++)
476 size_t j_idx = j_start + j;
477 if(i == j && SameComponent)
continue;
479 double3 dist = {UCAtoms[compi].pos[i].x - ReplicaAtoms[compj].pos[j].x,
480 UCAtoms[compi].pos[i].y - ReplicaAtoms[compj].pos[j].y,
481 UCAtoms[compi].pos[i].z - ReplicaAtoms[compj].pos[j].z};
483 double dsq = dot(dist, dist);
486 NL.List[i_idx].push_back({(int)i_idx, (
int)j_idx, (int) NL.nedges});
495 void Copy_To_Rigid_Framework_Edges(
size_t NFrameworkAtom)
497 for(
size_t i = 0; i < NFrameworkAtom; i++)
499 NL.FrameworkList.push_back(NL.List[i]);
502 void Copy_From_Rigid_Framework_Edges(
size_t NFrameworkAtom)
504 for(
size_t i = 0; i < NFrameworkAtom; i++)
506 NL.List[i] = NL.FrameworkList[i];
507 NL.nedges += NL.FrameworkList[i].size();
510 void WrapSuperCellAtomIntoUCBox(
size_t comp)
512 std::vector<double>Bonds;
513 std::vector<double3>newpos;
514 for(
size_t i = 0; i < UCAtoms[comp].size; i++)
516 double3 FPOS = GetFractionalCoord(UCBox.InverseCell, UCBox.Cubic, UCAtoms[comp].pos[i]);
518 double3 FLOOR = {(double)floor(FPOS.x), (double)floor(FPOS.y), (double)floor(FPOS.z)};
519 double3 New_fpos = {FPOS.x - FLOOR.x,
523 newpos.push_back(New_fpos);
526 double3 dist = {UCAtoms[comp].pos[i].x - UCAtoms[comp].pos[i - 1].x,
527 UCAtoms[comp].pos[i].y - UCAtoms[comp].pos[i - 1].y,
528 UCAtoms[comp].pos[i].z - UCAtoms[comp].pos[i - 1].z};
529 double dsq = dot(dist, dist);
530 Bonds.push_back(dsq);
532 for(
size_t i = 0; i < UCAtoms[comp].size; i++)
534 double3 Real_Pos = GetRealCoordFromFractional(UCBox.Cell, UCBox.Cubic, newpos[i]);
535 UCAtoms[comp].pos[i] = Real_Pos;
549 double MCEnergyWrapper(
size_t comp,
bool Initialize,
double DNNEnergyConversion)
551 WrapSuperCellAtomIntoUCBox(comp);
552 GenerateReplicaCells(Initialize);
553 Get_Neighbor_List_Replica(Initialize);
554 double DNN_E = Predict();
557 return DNN_E * DNNEnergyConversion;