MDStressLab++
Loading...
Searching...
No Matches
readScript.cpp
Go to the documentation of this file.
1/*
2 * main.cpp
3 *
4 * Created on: Nov 3, 2019
5 * Author: Nikhil Admal
6 */
7#include "Mls.h"
8#include "MethodLdad.h"
9#include "MethodSphere.h"
10#include <string>
11#include <iostream>
12#include <tuple>
13#include <cfloat>
14#include <fstream>
15#include "BoxConfiguration.h"
16#include "calculateStress.h"
17#include "Grid.h"
18#include "typedef.h"
19#include <regex>
20#include <algorithm>
21#include <cmath>
22
23
24int main()
25{
26 std::string line;
27 auto next_line = [&]() -> std::string {
28 while (std::getline(std::cin, line)) {
29 if (line.empty() || line[0] == '#' || line.find_first_not_of(" \t\r\n") == std::string::npos) continue;
30 return line;
31 }
32 return ""; // EOF
33 };
34
35 // Read LAMMPS data file
36 std::istringstream configFileStream(next_line());
37
38 std::string currentConfigFileName, referenceConfigFileName;
39 std::ifstream referenceConfigFile, currentConfigFile;
40 if (configFileStream >> currentConfigFileName) {
41 std::cout << "LAMMPS data file for current configuration: " << currentConfigFileName << std::endl;
42 currentConfigFile.open(currentConfigFileName);
43 if(!currentConfigFile) MY_ERROR("ERROR: current configuration file could not be opened for reading!");
44 }
45 if (configFileStream >> referenceConfigFileName) {
46 std::cout << "LAMMPS data file for reference configuration: " << referenceConfigFileName << std::endl;
47 referenceConfigFile.open(referenceConfigFileName);
48 if(!referenceConfigFile) MY_ERROR("ERROR: reference configuration file could not be opened for reading!");
49 }
50 if(referenceConfigFileName.empty())
51 referenceConfigFileName= currentConfigFileName;
52
53
54 // get number of particles
55 int numberOfParticles= -1;
56 while (std::getline(currentConfigFile, line)) {
57 std::string loweredLine = line;
58 std::transform(loweredLine.begin(), loweredLine.end(), loweredLine.begin(), ::tolower);
59
60 if (loweredLine.find("atoms") != std::string::npos && (std::stringstream(line) >> numberOfParticles) ) {
61 break;
62 }
63 }
64
65 if (numberOfParticles < 0) MY_ERROR("Error: Negative number of particles.\n");
66
67 BoxConfiguration body{numberOfParticles, 1};
68 body.readLMP(currentConfigFileName,referenceConfigFileName);
69
70 // Read periodic boundaries
71 Vector3i pbc;
72 std::istringstream pbStream(next_line());
73 pbStream >> pbc(0) >> pbc(1) >> pbc(2);
74 std::cout << "PBCs: " << pbc << std::endl;
75 body.pbc= pbc;
76
77 std::ofstream writeConfigReference("reference.txt");
78 std::ofstream writeConfigCurrent("current.txt");
79 for (int i=0; i<body.numberOfParticles; ++i)
80 {
81 writeConfigReference << body.species[i] << " " << body.coordinates[Reference].row(i) << std::endl;
82 writeConfigCurrent << body.species[i] << " " << body.coordinates[Current].row(i) << std::endl;
83 }
84
85 // Read KIM ID
86 std::string kimID = next_line();
87 std::cout << "KIM ID: " << kimID << std::endl;
88 Kim kim(kimID);
89
90 // Read atom types
91 std::istringstream atomStream(next_line());
92 std::vector<std::string> atomTypes;
93 std::string atom;
94 while (atomStream >> atom) atomTypes.push_back(atom);
95 std::cout << "Atom types: ";
96 for (const auto& a : atomTypes) std::cout << a << " ";
97 std::cout << std::endl;
98
99 // Number of grids
100 int numGrids = std::stoi(next_line());
101 std::cout << "Number of grids: " << numGrids << "\n";
102 Vector3d lowerLimit, upperLimit;
103 int ngridx, ngridy, ngridz;
104 double deltax, deltay, deltaz;
105 std::string outPrefix;
106
107 for (int i = 0; i < numGrids; ++i) {
108 //-------- Read stress method
109 MY_HEADING("Reading stress and grid parameters from input file");
110 bool project= false;
111 std::istringstream stressStream(next_line());
112 std::string stressMethod, averagingDomain, averagingDomainParameter;
113 double averagingDomainSize;
114
115 stressStream >> stressMethod >> averagingDomain ;
116 std::cout << "stress method: " << stressMethod << "\n";
117 std::cout << "averaging domain: " << averagingDomain << "\n";
118 if (stressMethod == "project")
119 project= true;
120
121 Vector3d xdir, ydir, zdir;
122 Matrix3d ldadVectors;
123
124 if (averagingDomain=="ldad")
125 {
126 stressStream >> averagingDomainParameter;
127 std::cout << "averaging domain parameter: " << averagingDomainParameter << "\n";
128
129 // read crystallographic directions and domain size to calculate ldadVectors
130 if (averagingDomainParameter=="bcc" || averagingDomainParameter=="fcc")
131 {
132 stressStream >> averagingDomainSize >> xdir(0) >> xdir(1) >> xdir(2) >>
133 ydir(0) >> ydir(1) >> ydir(2) >>
134 zdir(0) >> zdir(1) >> zdir(2);
135 std::cout << "averaging domain size : " << averagingDomainSize << "\n";
136
137 Vector3d basis1, basis2, basis3;
138 if (averagingDomainParameter=="bcc"){
139 basis1 << -0.5,0.5,0.5; basis2 << 0.5,-0.5,0.5; basis3 << 0.5,0.5,-0.5;
140 }
141 else if (averagingDomainParameter== "fcc"){
142 basis1 << 0,0.5,0.5; basis2 << 0.5,0,0.5; basis3 << 0.5,0.5,0;
143 }
144 Matrix3d rotation;
145
146 // calculate lattice vectors
147 rotation.row(0)= xdir.normalized();
148 rotation.row(1)= ydir.normalized();
149 rotation.row(2)= zdir.normalized();
150 assert((rotation.transpose()*rotation).isIdentity());
151 ldadVectors.col(0)= rotation*basis1.transpose();
152 ldadVectors.col(1)= rotation*basis2.transpose();
153 ldadVectors.col(2)= rotation*basis3.transpose();
154 ldadVectors= ldadVectors* averagingDomainSize;
155 }
156 // instead directly read ldad lattice vectors
157 else if (averagingDomainParameter=="lat")
158 stressStream >> ldadVectors(0,0) >> ldadVectors(1,0) >> ldadVectors(2,0) >>
159 ldadVectors(0,1) >> ldadVectors(1,1) >> ldadVectors(2,1) >>
160 ldadVectors(0,2) >> ldadVectors(1,2) >> ldadVectors(2,2);
161 }
162 else if (averagingDomain=="sphere"){
163 stressStream >> averagingDomainSize;
164 std::cout << "averaging domain size : " << averagingDomainSize << "\n";
165 }
166
167 //------------ Read grid
168 std::istringstream gridStream(next_line());
169 std::string token[9];
170 for (auto & j : token) {
171 gridStream >> j;
172 }
173
174 // Lambda to convert token or use fallback
175 auto parseOrFallback = [](const std::string& s, double fallback) -> double {
176 return (s == "*") ? fallback : std::stod(s);
177 };
178
179 // Parse delta values and diameter directly
180 deltax = std::stod(token[6]);
181 deltay = std::stod(token[7]);
182 deltaz = std::stod(token[8]);
183
184 auto configureCellAlignedGrid = [&](const Vector3d& origin, const Matrix3d& cell) {
185 Vector3d lowerCorner= origin;
186 Vector3d upperCorner= origin + cell.col(0).transpose() +
187 cell.col(1).transpose() + cell.col(2).transpose();
188
189 lowerLimit[0]= parseOrFallback(token[0],lowerCorner[0]);
190 lowerLimit[1]= parseOrFallback(token[1],lowerCorner[1]);
191 lowerLimit[2]= parseOrFallback(token[2],lowerCorner[2]);
192
193 upperLimit[0]= parseOrFallback(token[3],upperCorner[0]);
194 upperLimit[1]= parseOrFallback(token[4],upperCorner[1]);
195 upperLimit[2]= parseOrFallback(token[5],upperCorner[2]);
196
197 Vector3d cellDisplacement= (cell.inverse()*(upperLimit-lowerLimit).transpose()).transpose();
198 if ((cellDisplacement.array() < -epsilon).any())
199 MY_ERROR("ERROR: Grid upperLimit-lowerLimit has negative components in the cell-vector basis.");
200
201 Vector3d cellVectorLengths(cell.col(0).norm(),cell.col(1).norm(),cell.col(2).norm());
202 auto gridCount = [](double length, double delta) -> int {
203 if (std::abs(delta) <= FLT_EPSILON) return 1;
204 return std::max(1,static_cast<int>(floor((length+FLT_EPSILON)/delta)));
205 };
206
207 ngridx= gridCount(cellDisplacement(0)*cellVectorLengths(0),deltax);
208 ngridy= gridCount(cellDisplacement(1)*cellVectorLengths(1),deltay);
209 ngridz= gridCount(cellDisplacement(2)*cellVectorLengths(2),deltaz);
210
211 std::cout << "Grid Limits: ";
212 std::cout << lowerLimit << " " << upperLimit << std::endl;
213 std::cout << "Number of grid points: " << ngridx << " " << ngridy << " " << ngridz << std::endl;
214 };
215
216 // ----------- Output prefix
217 outPrefix= next_line();
218 std::cout << "Output file: " << outPrefix << "\n";
219
220
221 if (averagingDomain=="ldad") {
222 try {
223 configureCellAlignedGrid(body.reference_box_origin,body.reference_box);
224 Grid<Reference> grid(body.reference_box_origin,body.reference_box,lowerLimit,upperLimit,
225 ngridx,ngridy,ngridz);
226 //Matrix3d ldadVectors= averagingDomainSize*Matrix3d::Identity();
227
228 MethodLdadTrigonometric ldadDomain(ldadVectors);
229 Stress<MethodLdadTrigonometric, Piola> ldadTrigonometricStress(ldadDomain, &grid);
230 calculateStress(body, kim,
231 std::tie(ldadTrigonometricStress),
232 std::tie(), project);
233
234 double mlsRadius= 10.0;
235 Mls mls(body,&grid,mlsRadius,outPrefix);
236 std::vector<Matrix3d> cauchyPushedField;
237 mls.pushToCauchy(ldadTrigonometricStress.field,cauchyPushedField);
238 mls.writePushedCauchyStress(cauchyPushedField);
240 }
241 catch (const std::runtime_error &e) {
242 std::cout << e.what() << std::endl;
243 std::cout << "Compute stress with projected forces failed. Moving on" << std::endl;
244 }
245 }
246 else if(averagingDomain=="sphere"){
247 configureCellAlignedGrid(body.box_origin,body.box);
248 Grid<Current> grid(body.box_origin,body.box,lowerLimit,upperLimit,ngridx,ngridy,ngridz);
249 MethodSphere hardy(averagingDomainSize, "hardy");
250
251 // stress calculation using projected forces
252 try {
253 Stress<MethodSphere, Cauchy> hardyStress(hardy, &grid);
254
255 calculateStress(body, kim,
256 std::tie(),
257 std::tie(hardyStress), project);
258 hardyStress.write(outPrefix);
259 hardyStress.write_voxel_grid(outPrefix,ngridx,ngridy,ngridz,lowerLimit,upperLimit);
260 }
261 catch (const std::runtime_error &e) {
262 std::cout << e.what() << std::endl;
263 std::cout << "Compute stress with projected forces failed. Moving on" << std::endl;
264 }
265 }
266 else
267 MY_ERROR("Unknown stress method: " + stressMethod);
268 }
269
270 return 0;
271}
int calculateStress(const BoxConfiguration &body, Kim &kim, std::tuple<> stress, const bool &projectForces=false)
Represents a particle configuration including simulation box information.
void readLMP(const std::string &, const ConfigType &configType)
Reads a configuration from a LAMMPS data file.
Definition Grid.h:38
Definition kim.h:21
Lattice-dependent averaging-domain method.
Definition MethodLdad.h:39
Implements radially symmetric weighting functions (Hardy, Virial) and its associated bond function fo...
Computes deformation gradients and stress tensors using Moving Least Squares (MLS) interpolation on a...
Definition Mls.h:26
void writeDeformationGradient()
Writes the deformation gradient at each grid point to a file.
Definition Mls.cpp:832
void pushToCauchy(const std::vector< Matrix3d > &piolaStress, std::vector< Matrix3d > &cauchyStress)
Converts Piola-Kirchhoff stress to Cauchy stress at grid points.
Definition Mls.cpp:796
void writePushedCauchyStress(std::vector< Matrix3d > &cauchyStress)
Writes Cauchy stresses at grid points to a file.
Definition Mls.cpp:887
Three-dimensional stress field on a grid.
Definition Stress.h:42
std::vector< Matrix3d > field
A three-dimensional stress field.
Definition Stress.h:47
void write()
Write stress and, for Cauchy stress, density fields.
Definition Stress.h:146
void write_voxel_grid(const int nx, const int ny, const int nz, const Vector3d &lowerLimit, const Vector3d &upperLimit)
Write structured grid fields in LAMMPS dump-grid format.
Definition Stress.h:227
void transpose(double const *mat, double *const trans)
Definition helper.hpp:59
int main()
#define MY_ERROR(message)
Definition typedef.h:17
Eigen::Matrix< double, DIM, DIM, Eigen::RowMajor > Matrix3d
Definition typedef.h:56
Eigen::Matrix< double, 1, DIM, Eigen::RowMajor > Vector3d
Definition typedef.h:60
Eigen::Matrix< int, 1, DIM, Eigen::RowMajor > Vector3i
Definition typedef.h:61
@ Current
Definition typedef.h:70
@ Reference
Definition typedef.h:69
const double epsilon
Definition typedef.h:73
#define MY_HEADING(heading)
Definition typedef.h:36