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