oILAB
Loading...
Searching...
No Matches
GbMesoStateImplementation.h
Go to the documentation of this file.
1//
2// Created by Nikhil Chandra Admal on 5/27/24.
3//
4
5#ifndef OILAB_GBMESOSTATEIMPLEMENTATION_H
6#define OILAB_GBMESOSTATEIMPLEMENTATION_H
7
8#include<Lammps.h>
9#include <iostream>
10#include <Python.h>
12
13namespace gbLAB {
14 template<int dim>
17 const std::deque<std::tuple<LatticeVector<dim>,VectorDimD,int>>& bs,
18 const std::vector<LatticeVector<dim>>& mesoStateCslVectors,
19 const BicrystalLatticeVectors& bicrystalConfig)
20 try :
21 GbContinuum<dim>(getMesoStateGbDomain(mesoStateCslVectors),
22 get_xuPairs(gb,mesoStateCslVectors,bs),
23 discretize(mesoStateCslVectors,gb),
24 bicrystalCoordsMap(gb,bicrystalConfig)),
25 gb(gb),
26 axis(axis),
27 mesoStateCslVectors(mesoStateCslVectors),
28 bicrystalConfig(bicrystalConfig),
29 bs(bs)
30 {
31 // check
32 /*
33 auto xuPairs= get_xuPairs(bs);
34 for(const auto& pair : xuPairs)
35 std::cout << (pair.second-this->displacement(pair.first)).norm() << std::endl;
36 */
37 }
38 catch(std::runtime_error& e)
39 {
40 //throw(std::runtime_error("GB Mesostate construction failed"));
41 }
42
43
44 template<int dim>
45 Eigen::Matrix<double, dim,dim-1> GbMesoState<dim>::getMesoStateGbDomain(const std::vector<LatticeVector<dim>>& mesoStateCslVectors)
46 {
47 Eigen::Matrix<double, dim,dim-1> mesoStateGbDomain;
48 for(int i=1; i<dim; ++i)
49 mesoStateGbDomain.col(i-1)= mesoStateCslVectors[i].cartesian();
50 return mesoStateGbDomain;
51 }
52
53 template<int dim>
54 std::map<OrderedTuplet<dim+1>, typename GbMesoState<dim>::VectorDimD>
56 const std::vector<LatticeVector<dim>>& mesoStateCslVectors,
57 const std::deque<std::tuple<LatticeVector<dim>,VectorDimD,int>>& bs)
58 {
59 auto normal= gb.nA.cartesian().normalized();
60 std::map<OrderedTuplet<dim+1>,VectorDimD> xuPairs;
61 std::vector<LatticeVector<dim>> bicrystalBoxVectors(mesoStateCslVectors);
62 bicrystalBoxVectors[0]= 2*mesoStateCslVectors[0];
63 VectorDimD shift;
64 shift << -0.5-FLT_EPSILON,-FLT_EPSILON,-FLT_EPSILON;
65
66
67 for(const auto& [b,s,include] : bs)
68 {
70 VectorDimD valueu;
71 // value = b/2
72 valueu= b.cartesian()/2;
73 VectorDimD tempx= s-valueu;
74
75
76 /*
77 if(tempx.dot(normal)<FLT_EPSILON) // tempx is in lattice A
78 {
79 // modulo tempx w.r.t the bicrystal box
80 LatticeVector<dim>::modulo(tempx,bicrystalBoxVectors,shift);
81 try {
82 keyx << gb.bc.getLatticeVectorInD(gb.bc.A.latticeVector(tempx)),1;
83 }
84 catch(std::runtime_error& e)
85 {
86 std::cout << e.what() << std::endl;
87 std::cout << "x key = " << keyx.transpose() << "; " << tempx.transpose() << std::endl;
88 std::cout << "b = " << b.cartesian().transpose() << " ; s= " << s.transpose() << std::endl;
89 exit(0);
90 }
91
92 }
93 else // tempx is in lattice B
94 {
95 tempx= tempx + 2*valueu.dot(normal) * normal;
96 // modulo tempx w.r.t the bicrystal box
97 LatticeVector<dim>::modulo(tempx,bicrystalBoxVectors,shift);
98
99 try {
100 keyx << gb.bc.getLatticeVectorInD(gb.bc.B.latticeVector(tempx)),2;
101 }
102 catch(std::runtime_error& e)
103 {
104 std::cout << e.what() << std::endl;
105 std::cout << "x key = " << keyx.transpose() << "; " << tempx.transpose() << std::endl;
106 std::cout << "b = " << b.cartesian().transpose() << " ; s= " << s.transpose() << std::endl;
107 exit(0);
108 }
109
110 }
111 */
112 // modulo tempx w.r.t the bicrystal box
113 LatticeVector<dim>::modulo(tempx,bicrystalBoxVectors,shift);
114 try {
115 if (tempx.dot(normal) < FLT_EPSILON) // tempx is in lattice A
116 keyx << gb.bc.getLatticeVectorInD(gb.bc.A.latticeVector(tempx)), 1;
117 else // tempx is in lattice B region
118 keyx << gb.bc.getLatticeVectorInD(gb.bc.A.latticeVector(tempx)), -1;
119 }
120 catch(std::runtime_error& e) {
121 std::cout << e.what() << std::endl;
122 std::cout << "x key = " << keyx.transpose() << "; " << tempx.transpose() << std::endl;
123 std::cout << "b = " << b.cartesian().transpose() << " ; s= " << s.transpose() << std::endl;
124 exit(0);
125 }
126 xuPairs[keyx]=valueu;
127 }
128 if(xuPairs.size() != bs.size())
129 throw(std::runtime_error("Clash in constraints."));
130 return xuPairs;
131 }
132
133 template<int dim>
134 std::array<Eigen::Index,dim-1> GbMesoState<dim>::discretize(const std::vector<LatticeVector<dim>>& mesoStateCslVectors, const Gb<dim>& gb)
135 {
136 std::array<Eigen::Index,dim-1> n{};
137 for(int i=1; i<dim; ++i)
138 n[i-1]= 10*ceil(mesoStateCslVectors[i].cartesian().norm()/gb.bc.A.latticeBasis.col(0).norm());
139 //n[i-1]= 4*IntegerMath<int>::gcd(gb.bc.getLatticeVectorInD(mesoStateCslVectors[i]));
140 return n;
141
142 }
143
144
145 template<int dim>
146 std::map<OrderedTuplet<dim+1>,typename GbMesoState<dim>::VectorDimD> GbMesoState<dim>::bicrystalCoordsMap(const Gb<dim>& gb, const BicrystalLatticeVectors& bicrystalConfig)
147 {
148 std::map<OrderedTuplet<dim+1>,VectorDimD> idCoordsMap;
149
150 for(const auto& latticeVector : bicrystalConfig) {
151 auto latticeVectorInD= gb.bc.getLatticeVectorInD(latticeVector);
153 if (&latticeVector.lattice == &gb.bc.A) {
154 if (latticeVector.dot(gb.nA) <= 0)
155 key << latticeVectorInD, 1;
156 else
157 key << latticeVectorInD, -1;
158 }
159 else if (&latticeVector.lattice == &gb.bc.B) {
160 if (latticeVector.dot(gb.nB) <= 0)
161 key << latticeVectorInD, 2;
162 else
163 key << latticeVectorInD, -2;
164 }
165 idCoordsMap[key]= latticeVectorInD.cartesian();
166 }
167 return idCoordsMap;
168
169 }
170
171 /*-------------------------------------*/
172 template<int dim>
173 std::tuple<double,double,PeriodicFunction<double,dim>> GbMesoState<dim>::densityEnergy(const std::string& lmpLocation,
174 const std::string& potentialName,
175 bool relax,
176 const std::array<Eigen::Index,dim>& n) const
177 {
178 box("temp" + std::to_string(omp_get_thread_num()));
179 std::pair<double,double> densityEnergyPair= energy(lmpLocation,
180 "temp" + std::to_string(omp_get_thread_num()) + "_reference1.txt",
181 potentialName);
182
183
184 // the columns of rhoCell defined the box in which rho is calculated
185 Eigen::Matrix3d rhoCell;
186 PeriodicFunction<double,dim> rho(n,rhoCell);
187 for (int i=0; i<n[0]; ++i)
188 {
189 for (int j=0; j<n[1]; ++j) {
190 for (int k = 0; k < n[2]; ++k)
191 {
192 Eigen::Vector<double,Eigen::Dynamic> x= i*rho.unitCell.col(0)/n[0] +
193 j*rho.unitCell.col(1)/n[1] +
194 k*rho.unitCell.col(2)/n[2];
195 // rho(i,j,k) is the density at point x
196 // calculate rho by first reading the relaxed configuration
197
198 }
199 }
200
201 }
202
203 return {densityEnergyPair.first,densityEnergyPair.second,rho};
204
205 }
206
207
208 /*-------------------------------------*/
209 template<int dim>
210 std::pair<double,double> GbMesoState<dim>::densityEnergyPython() const
211 {
212 // form box
213 // run a python script to calculate energy
214
215 setenv("PYTHONPATH", ".", 1);
216 if(!Py_IsInitialized()) {
217 std::cout << "Initializing Python Interpreter" << std::endl;
218 Py_Initialize();
219 }
220
221 box("temp");
222 PyObject* pyModuleString = PyUnicode_FromString((char*)"lammps");
223 PyObject* pyModule = PyImport_Import(pyModuleString);
224 if (pyModule == nullptr)
225 {
226 PyErr_Print();
227 std::cout << "cannot import python script" << std::endl;
228 std::exit(0);
229 }
230 PyObject* pDict = PyModule_GetDict(pyModule);
231 PyObject* pyFunction= PyDict_GetItemString(pDict, (char*)"energy");
232 //PyObject* pyEnergy= PyObject_CallObject(pyFunction,NULL);
233 PyObject* pyValue= PyObject_CallObject(pyFunction,NULL);
234 double energy, density;
235
236 PyArg_ParseTuple(pyValue, "dd", &energy, &density);
237 //double energy= PyFloat_AsDouble(pyEnergy);
238
239 Py_DECREF(pyModule);
240 Py_DECREF(pyModuleString);
241
242 return std::make_pair(density,energy);
243 }
244
245 template<int dim>
246 //template<int dm=dim>
247 typename std::enable_if<dim==3,void>::type
248 GbMesoState<dim>::box(const std::string& name) const
249 {
250 const auto& config= this->bicrystalConfig;
251 std::vector<LatticeVector<3>> boxVectors;
252 boxVectors.push_back(this->mesoStateCslVectors[0]);
253 boxVectors.push_back(this->mesoStateCslVectors[1]);
254 boxVectors.push_back(this->mesoStateCslVectors[2]);
255
256 std::vector<VectorDimD> referenceConfigA, deformedConfigA;
257 std::vector<VectorDimD> referenceConfigB, deformedConfigB;
258 std::vector<VectorDimD> configDscl;
259
260 double bmax= 0.0;
261 for(const auto& [b,s,include] : bs)
262 bmax= max(bmax,b.cartesian().norm());
263
264 int numberOfIgnoredPoints= 0;
265 for (const auto &latticeVector: config) {
266 VectorDimD x;
268 if (&(latticeVector.lattice) == &(this->gb.bc.A)) {
269 double height= latticeVector.cartesian().dot(gb.nA.cartesian().normalized());
270 if (height<FLT_EPSILON)
271 temp << gb.bc.getLatticeVectorInD(latticeVector),1;
272 else
273 temp << gb.bc.getLatticeVectorInD(latticeVector),-1;
274 }
275 else if (&(latticeVector.lattice) == &(this->gb.bc.B)) {
276 double height = latticeVector.cartesian().dot(gb.nB.cartesian().normalized());
277 if (height<FLT_EPSILON)
278 temp << gb.bc.getLatticeVectorInD(latticeVector),2;
279 else
280 temp << gb.bc.getLatticeVectorInD(latticeVector),-2;
281 }
282
283 //x = latticeVector.cartesian() + this->displacement(latticeVector.cartesian());
284
285 if (&(latticeVector.lattice) == &(this->gb.bc.A)) {
286 x = latticeVector.cartesian() + this->displacement(temp) + this->uAverage;
287 }
288 else if (&(latticeVector.lattice) == &(this->gb.bc.B) )
289 x = latticeVector.cartesian() + this->displacement(temp) - this->uAverage;
290 else
291 x = latticeVector.cartesian() + this->displacement(temp);
292
293 // ignore x if it occupies a deleted CSL position
294 bool ignore= false;
295 VectorDimD cslShift;
296 cslShift << -0.5, -FLT_EPSILON, -FLT_EPSILON;
297 VectorDimD xModulo= x;
298 std::vector<LatticeVector<3>> localBoxVectors(boxVectors);
299 localBoxVectors[0]=5*boxVectors[0];
300 LatticeVector<dim>::modulo(xModulo, localBoxVectors, cslShift);
301 for(const auto& [b,s, include] : bs) {
302 if (include == 2 && (s - xModulo).norm() < 1e-6) {
303 ignore = true;
304 numberOfIgnoredPoints++;
305 break;
306 }
307 }
308 if (ignore==true) {
309 continue;
310 }
311
312
313 if (&(latticeVector.lattice) == &(this->gb.bc.A) && x.dot(this->gb.nA.cartesian().normalized()) <= 1e-6)
314 //if (&(latticeVector.lattice) == &(this->gb.bc.A) && x.dot(this->gb.nA.cartesian().normalized()) <= FLT_EPSILON)
315 //if (&(latticeVector.lattice) == &(this->gb.bc.A))
316 {
317 referenceConfigA.push_back(latticeVector.cartesian());
318 deformedConfigA.push_back(x);
319 }
320 else if (&(latticeVector.lattice) == &(this->gb.bc.B) && x.dot(this->gb.nB.cartesian().normalized()) <= 1e-6)
321 //else if (&(latticeVector.lattice) == &(this->gb.bc.B) && x.dot(this->gb.nB.cartesian().normalized()) <= FLT_EPSILON)
322 //else if (&(latticeVector.lattice) == &(this->gb.bc.B))
323 {
324 referenceConfigB.push_back(latticeVector.cartesian());
325 deformedConfigB.push_back(x);
326 }
327
328 }
329
330
331 int numberOfIgnoredCSLPoints= 0;
332 for(const auto& [b,s, include] : bs)
333 {
334 if (include==2) numberOfIgnoredCSLPoints++;
335 }
336 if(numberOfIgnoredPoints != 2*numberOfIgnoredCSLPoints)
337 throw(std::runtime_error("GB Mesostate construction failed: incorrect number of points"));
338
339
340 int nAtoms= referenceConfigA.size()+referenceConfigB.size()+configDscl.size();
341
342 std::string referenceFile= name + "_reference0.txt";
343 std::string deformedFile= name + "_reference1.txt";
344
345 std::ofstream reference, deformed;
346 reference.open(referenceFile);
347 deformed.open(deformedFile);
348 if (!reference || !deformed) std::cerr << "Unable to open files";
349 reference << nAtoms << std::endl; deformed << nAtoms << std::endl;
350 reference << "Lattice=\" "; deformed << "Lattice=\" ";
351
352 reference << std::setprecision(15) << (2*boxVectors[0].cartesian()).transpose() << " ";
353 deformed << std::setprecision(15) << (2*boxVectors[0].cartesian()).transpose() << " ";
354 reference << std::setprecision(15) << (boxVectors[1].cartesian()).transpose() << " ";
355 deformed << std::setprecision(15) << (boxVectors[1].cartesian()).transpose() << " ";
356 reference << std::setprecision(15) << (boxVectors[2].cartesian()).transpose();
357 deformed << std::setprecision(15) << (boxVectors[2].cartesian()).transpose();
358 reference << "\" Properties=atom_types:I:1:pos:R:3:radius:R:1 PBC=\"F T T\" origin=\" "; deformed << "\" Properties=atom_types:I:1:pos:R:3:radius:R:1 PBC=\" F T T\" origin=\" ";
359 reference << std::setprecision(15) << (-1 * boxVectors[0].cartesian()).transpose() << "\"" << std::endl;
360 deformed << std::setprecision(15) << (-1 * boxVectors[0].cartesian()).transpose() << "\"" << std::endl;
361
362 for(const auto& position : referenceConfigA)
363 reference << 1 << " " << std::setprecision(15) << position.transpose() << " " << 0.05 << std::endl;
364 for(const auto& position : referenceConfigB)
365 reference << 2 << " " << std::setprecision(15) << position.transpose() << " " << 0.05 << std::endl;
366 for(const auto& position : deformedConfigA)
367 deformed << 1 << " " << std::setprecision(15) << position.transpose() << " " << 0.05 << std::endl;
368 for(const auto& position : deformedConfigB)
369 deformed << 2 << " " << std::setprecision(15) << position.transpose() << " " << 0.05 << std::endl;
370 for(const auto& position : configDscl) {
371 reference << 4 << " " << std::setprecision(15) << position.transpose() << " " << 0.01 << std::endl;
372 deformed << 4 << " " << std::setprecision(15) << position.transpose() << " " << 0.01 << std::endl;
373 }
374
375 reference.close();
376 deformed.close();
377 }
378
379}
380
381#endif
std::pair< double, double > energy(const std::string &lammpsLocation, const std::string &oilabConfigFile, const std::string &potentialFile)
Definition Lammps.h:239
Definition Gb.h:16
const ReciprocalLatticeDirection< dim > nA
Definition Gb.h:33
const BiCrystal< dim > & bc
Definition Gb.h:29
const ReciprocalLatticeDirection< dim > nB
Definition Gb.h:37
static Eigen::Matrix< double, dim, dim-1 > getMesoStateGbDomain(const std::vector< LatticeVector< dim > > &mesoStateCslVectors)
Returns the cartesian coordinates of the CSL vectors that define a mesostate's GB.
GbMesoState(const Gb< dim > &gb, const ReciprocalLatticeVector< dim > &axis, const std::deque< std::tuple< LatticeVector< dim >, VectorDimD, int > > &bs, const std::vector< LatticeVector< dim > > &mesoStateCslVectors, const BicrystalLatticeVectors &bicrystalConfig)
std::enable_if< dim==3, void >::type box(const std::string &filename) const
std::vector< LatticeVector< dim > > BicrystalLatticeVectors
Definition GbMesoState.h:22
static std::map< OrderedTuplet< dim+1 >, VectorDimD > get_xuPairs(const Gb< dim > &gb, const std::vector< LatticeVector< dim > > &mesoStateCslVectors, const std::deque< std::tuple< LatticeVector< dim >, VectorDimD, int > > &bs)
Returns the displacement constraints for the GB continuum model from the translation-shift pairs def...
std::pair< double, double > densityEnergyPython() const
std::tuple< double, double, PeriodicFunction< double, dim > > densityEnergy(const std::string &lmpLocation, const std::string &potentialName, bool relax, const std::array< Eigen::Index, dim > &n=std::array< Eigen::Index, dim >{}) const
Calculate the energy of a mesostate using lammps.
typename LatticeCore< dim >::VectorDimD VectorDimD
Definition GbMesoState.h:21
static std::map< OrderedTuplet< dim+1 >, VectorDimD > bicrystalCoordsMap(const Gb< dim > &gb, const BicrystalLatticeVectors &bicrystalConfig)
Returns the Cartesian coordinates of the lattice vectors of the mesostates's bicrystal in the form of...
static std::array< Eigen::Index, dim-1 > discretize(const std::vector< LatticeVector< dim > > &mesoStateCslVectors, const Gb< dim > &gb)
Returns the discretization of the grain boundary domain.
LatticeVector class.
static std::enable_if< dm==2, void >::type modulo(LatticeVector< dim > &input, const std::vector< LatticeVector< dim > > &basis, const VectorDimD &shift=VectorDimD::Zero())
const Eigen::Matrix< double, Eigen::Dynamic, dim > unitCell