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;
36 std::istringstream configFileStream(next_line());
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!");
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!");
50 if(referenceConfigFileName.empty())
51 referenceConfigFileName= currentConfigFileName;
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);
60 if (loweredLine.find(
"atoms") != std::string::npos && (std::stringstream(line) >> numberOfParticles) ) {
65 if (numberOfParticles < 0)
MY_ERROR(
"Error: Negative number of particles.\n");
68 body.
readLMP(currentConfigFileName,referenceConfigFileName);
72 std::istringstream pbStream(next_line());
73 pbStream >> pbc(0) >> pbc(1) >> pbc(2);
74 std::cout <<
"PBCs: " << pbc << std::endl;
77 std::ofstream writeConfigReference(
"reference.txt");
78 std::ofstream writeConfigCurrent(
"current.txt");
79 for (
int i=0; i<body.numberOfParticles; ++i)
81 writeConfigReference << body.species[i] <<
" " << body.coordinates[
Reference].row(i) << std::endl;
82 writeConfigCurrent << body.species[i] <<
" " << body.coordinates[
Current].row(i) << std::endl;
86 std::string kimID = next_line();
87 std::cout <<
"KIM ID: " << kimID << std::endl;
91 std::istringstream atomStream(next_line());
92 std::vector<std::string> atomTypes;
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;
100 int numGrids = std::stoi(next_line());
101 std::cout <<
"Number of grids: " << numGrids <<
"\n";
103 int ngridx, ngridy, ngridz;
104 double deltax, deltay, deltaz;
105 std::string outPrefix;
107 for (
int i = 0; i < numGrids; ++i) {
109 MY_HEADING(
"Reading stress and grid parameters from input file");
111 std::istringstream stressStream(next_line());
112 std::string stressMethod, averagingDomain, averagingDomainParameter;
113 double averagingDomainSize;
115 stressStream >> stressMethod >> averagingDomain ;
116 std::cout <<
"stress method: " << stressMethod <<
"\n";
117 std::cout <<
"averaging domain: " << averagingDomain <<
"\n";
118 if (stressMethod ==
"project")
124 if (averagingDomain==
"ldad")
126 stressStream >> averagingDomainParameter;
127 std::cout <<
"averaging domain parameter: " << averagingDomainParameter <<
"\n";
130 if (averagingDomainParameter==
"bcc" || averagingDomainParameter==
"fcc")
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";
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;
141 else if (averagingDomainParameter==
"fcc"){
142 basis1 << 0,0.5,0.5; basis2 << 0.5,0,0.5; basis3 << 0.5,0.5,0;
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;
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);
162 else if (averagingDomain==
"sphere"){
163 stressStream >> averagingDomainSize;
164 std::cout <<
"averaging domain size : " << averagingDomainSize <<
"\n";
168 std::istringstream gridStream(next_line());
169 std::string token[9];
170 for (
auto & j : token) {
175 auto parseOrFallback = [](
const std::string& s,
double fallback) ->
double {
176 return (s ==
"*") ? fallback : std::stod(s);
180 deltax = std::stod(token[6]);
181 deltay = std::stod(token[7]);
182 deltaz = std::stod(token[8]);
184 auto configureCellAlignedGrid = [&](
const Vector3d& origin,
const Matrix3d& cell) {
186 Vector3d upperCorner= origin + cell.col(0).transpose() +
187 cell.col(1).transpose() + cell.col(2).transpose();
189 lowerLimit[0]= parseOrFallback(token[0],lowerCorner[0]);
190 lowerLimit[1]= parseOrFallback(token[1],lowerCorner[1]);
191 lowerLimit[2]= parseOrFallback(token[2],lowerCorner[2]);
193 upperLimit[0]= parseOrFallback(token[3],upperCorner[0]);
194 upperLimit[1]= parseOrFallback(token[4],upperCorner[1]);
195 upperLimit[2]= parseOrFallback(token[5],upperCorner[2]);
198 if ((cellDisplacement.array() < -
epsilon).any())
199 MY_ERROR(
"ERROR: Grid upperLimit-lowerLimit has negative components in the cell-vector basis.");
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)));
207 ngridx= gridCount(cellDisplacement(0)*cellVectorLengths(0),deltax);
208 ngridy= gridCount(cellDisplacement(1)*cellVectorLengths(1),deltay);
209 ngridz= gridCount(cellDisplacement(2)*cellVectorLengths(2),deltaz);
211 std::cout <<
"Grid Limits: ";
212 std::cout << lowerLimit <<
" " << upperLimit << std::endl;
213 std::cout <<
"Number of grid points: " << ngridx <<
" " << ngridy <<
" " << ngridz << std::endl;
217 outPrefix= next_line();
218 std::cout <<
"Output file: " << outPrefix <<
"\n";
221 if (averagingDomain==
"ldad") {
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);
231 std::tie(ldadTrigonometricStress),
232 std::tie(), project);
234 double mlsRadius= 10.0;
235 Mls mls(body,&grid,mlsRadius,outPrefix);
236 std::vector<Matrix3d> cauchyPushedField;
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;
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);
257 std::tie(hardyStress), project);
258 hardyStress.
write(outPrefix);
259 hardyStress.
write_voxel_grid(outPrefix,ngridx,ngridy,ngridz,lowerLimit,upperLimit);
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;
267 MY_ERROR(
"Unknown stress method: " + stressMethod);