82 std::tuple<TStressPiola&...> piolaStress,
83 std::tuple<TStressCauchy&...> cauchyStress,
84 const bool& projectForces=
false)
87 int numberOfPiolaStresses=
sizeof...(TStressPiola);
88 int numberOfCauchyStresses=
sizeof...(TStressCauchy);
91 if (numberOfPiolaStresses == 0 && numberOfCauchyStresses == 0)
93 MY_WARNING(
"No stress calculation requested. Returning to caller.");
99 auto start = std::chrono::system_clock::now();
100 std::time_t startTime = std::chrono::system_clock::to_time_t(start);
101 std::cout <<
"Time stamp: " << std::ctime(&startTime) << std::endl;
104 recursiveNullifyStress(piolaStress);
105 recursiveNullifyStress(cauchyStress);
107 if (numberOfPiolaStresses > 0)
109 std::cout <<
"Number of Piola stresses requested : " << numberOfPiolaStresses << std::endl;
110 std::cout << std::endl;
111 std::cout << std::setw(25) <<
"Grid" << std::setw(25) <<
"Averaging domain size" << std::endl;
113 for (
const auto& pair : referenceGridDomainSizePairs)
114 std::cout << std::setw(25) << (
GridBase*) pair.first << std::setw(25) << pair.second << std::endl;
118 MY_WARNING(
"No reference coordinates detected to compute Piola stress.");
119 if (numberOfCauchyStresses>0)
121 MY_WARNING(
"Restarting stress calculation with only Cauchy stress.");
126 MY_ERROR(
"Error in stress computation.");
136 if (numberOfCauchyStresses>0)
138 std::cout <<
"Number of Cauchy stresses requested: " << numberOfCauchyStresses << std::endl;
139 std::cout << std::endl;
140 std::cout << std::setw(25) <<
"Grid" << std::setw(25) <<
"Averaging domain size" << std::endl;
142 for (
const auto& pair : currentGridDomainSizePairs)
143 std::cout << std::setw(25) << (
GridBase*) pair.first << std::setw(25) << pair.second << std::endl;
147 std::cout << std::endl;
151 std::cout <<
"Maximum averaging domain size across all stresses = " << maxAveragingDomainSize << std::endl;
153 if (body.
pbc.any() == 1)
155 std::unique_ptr<const Configuration> pconfig;
156 MY_HEADING(
"Generating padding atoms for periodic boundary conditions");
159 pconfig.reset(body.
getConfiguration(2*influenceDistance+maxAveragingDomainSize));
160 std::cout <<
"Thickness of padding = 2 influence distance + maximum averaging domain size = "
161 << 2*influenceDistance+maxAveragingDomainSize << std::endl;
162 std::cout <<
"Total number of atoms including padding atoms = " << pconfig->numberOfParticles << std::endl;
163 std::cout << std::endl;
172 status=
calculateStress(pconfig.get(),kim,piolaStress,cauchyStress,projectForces);
176 status=
calculateStress(&body,kim,piolaStress,cauchyStress,projectForces);
184 std::cout << std::endl;
185 std::cout << std::endl;
186 std::cout << std::endl;
187 std::cout << std::endl;
188 auto end= std::chrono::system_clock::now();
189 std::time_t endTime= std::chrono::system_clock::to_time_t(end);
190 std::chrono::duration<double> elapsedSeconds(end-start);
191 std::cout <<
"Elapsed time: " << elapsedSeconds.count() <<
" seconds" << std::endl;
192 std::cout <<
"End of simulation" << std::endl;
197 MY_ERROR(
"Error in stress computation.");
204 std::tuple<TStressPiola&...> piolaStress,
205 std::tuple<TStressCauchy&...> cauchyStress,
206 const bool& projectForces=
false)
208 assert(!(kim.
kim_ptr==
nullptr) &&
"Model not initialized");
210 int numberOfPiolaStresses=
sizeof...(TStressPiola);
211 int numberOfCauchyStresses=
sizeof...(TStressCauchy);
219 const auto referenceGridAveragingDomainSizeMap=
221 const auto currentGridAveragingDomainSizeMap=
226 if (numberOfPiolaStresses>0)
228 std::cout <<
"Piola Stress" << std::endl;
229 std::cout << std::setw(25) <<
"Unique grid" << std::setw(30) <<
"Max. Averaging domain size" << std::endl;
230 std::cout << std::setw(25) <<
"-----------" << std::setw(30) <<
"--------------------------" << std::endl;
231 for(
const auto& [pgrid,domainSize] : referenceGridAveragingDomainSizeMap)
233 std::cout << std::setw(25) << (
GridBase*)pgrid << std::setw(25) << domainSize << std::endl;
234 stencil.
expandStencil(pgrid,domainSize+influenceDistance,influenceDistance);
238 if (numberOfCauchyStresses>0)
240 std::cout <<
"Cauchy Stress" << std::endl;
241 std::cout << std::setw(25) <<
"Unique grid" << std::setw(30) <<
"Max. Averaging domain size" << std::endl;
242 std::cout << std::setw(25) <<
"-----------" << std::setw(30) <<
"--------------------------" << std::endl;
243 for(
const auto& [pgrid,domainSize] : currentGridAveragingDomainSizeMap)
245 std::cout << std::setw(25) << (
GridBase*)pgrid << std::setw(25) << domainSize << std::endl;
246 stencil.
expandStencil(pgrid,domainSize+influenceDistance,influenceDistance);
250 std::cout << std::endl;
251 std::cout <<
"Creating a local configuration using the above grids." << std::endl;
253 int numberOfParticles= subconfig.numberOfParticles;
254 if (numberOfParticles == 0)
256 std::string message=
"All grids away from the current material. Stresses are identically zero. Returning to the caller.";
258 throw(std::runtime_error(message));
260 std::cout <<
"Number of particle in the local configuration = " << numberOfParticles << std::endl;
261 std::cout <<
"Number of contributing particles = " << subconfig.particleContributing.sum() << std::endl;
267 std::vector<GridSubConfiguration<Reference>> neighborListsOfReferenceGridsOne;
268 std::vector<GridSubConfiguration<Reference>> neighborListsOfReferenceGridsTwo;
269 std::vector<GridSubConfiguration<Current>> neighborListsOfCurrentGridsOne;
270 std::vector<GridSubConfiguration<Current>> neighborListsOfCurrentGridsTwo;
273 assert(numberOfPiolaStresses==referenceGridDomainSizePairs.size());
276 assert(numberOfCauchyStresses == currentGridDomainSizePairs.size());
278 for(
const auto& gridDomainSizePair : referenceGridDomainSizePairs)
280 const auto& pgrid= gridDomainSizePair.first;
281 const auto& domainSize= gridDomainSizePair.second;
282 neighborListsOfReferenceGridsOne.emplace_back( *pgrid,subconfig,domainSize+influenceDistance);
283 neighborListsOfReferenceGridsTwo.emplace_back( *pgrid,subconfig,domainSize+2*influenceDistance);
285 for(
const auto& gridDomainSizePair : currentGridDomainSizePairs)
287 const auto& pgrid= gridDomainSizePair.first;
288 const auto& domainSize= gridDomainSizePair.second;
289 neighborListsOfCurrentGridsOne.emplace_back(*pgrid,subconfig,domainSize+influenceDistance);
290 neighborListsOfCurrentGridsTwo.emplace_back(*pgrid,subconfig,domainSize+2*influenceDistance);
292 assert(neighborListsOfCurrentGridsOne.size() == numberOfCauchyStresses &&
293 neighborListsOfCurrentGridsTwo.size() == numberOfCauchyStresses &&
294 neighborListsOfReferenceGridsOne.size() == numberOfPiolaStresses &&
295 neighborListsOfReferenceGridsTwo.size() == numberOfPiolaStresses);
299 std::vector<GridBase*> pgridList;
300 pgridList.reserve( pgridListPiola.size() + pgridListCauchy.size() );
301 pgridList.insert( pgridList.end(), pgridListPiola.begin(), pgridListPiola.end() );
302 pgridList.insert( pgridList.end(), pgridListCauchy.begin(), pgridListCauchy.end() );
303 assert(pgridList.size() == numberOfPiolaStresses + numberOfCauchyStresses);
311 bondCutoff= 2.0*influenceDistance;
312 std::cout <<
"bond cutoff = " << bondCutoff << std::endl;
317 subconfig.coordinates.at(
Current).data(),
321 subconfig.particleContributing.data());
335 subconfig.coordinates.at(
Current).data(),
337 numberOfNeighborLists,
339 subconfig.particleContributing.data());
341 int neighborListSize= 0;
342 for (
int i_particle=0; i_particle<numberOfParticles; i_particle++)
344 std::cout <<
"Size of neighbor list = " <<neighborListSize << std::endl;
350 if (!projectForces) {
356 subconfig.particleContributing,
362 std::cout <<
"Done" << std::endl;
369 std::cout <<
"Done" << std::endl;
375 subconfig.particleContributing,
387 std::ofstream null_stream(
"/dev/null");
388 std::streambuf* cout_buf = std::cout.rdbuf();
389 std::cout.rdbuf(null_stream.rdbuf());
396 std::vector<double> fijCopy(bonds.
fij.size(),0.0);
398 for (
int i_particlei = 0; i_particlei < subconfig.numberOfParticles; ++i_particlei) {
400 if (subconfig.particleContributing[i_particlei] == 0)
continue;
402 std::cout << i_particlei << std::endl;
404 Stencil singleParticleStencil(subconfig);
405 std::vector<Vector3d> centerParticleCoordinates;
406 centerParticleCoordinates.push_back(subconfig.coordinates.at(
Current).row(i_particlei));
407 singleParticleStencil.
expandStencil(centerParticleCoordinates, subconfig.coordinates.at(
Current), 0.0,
412 const double *cutoffs = p_kimLocal->
getCutoffs();
418 nbl_build(nlOfParticle, subconfigOfParticle.numberOfParticles,
419 subconfigOfParticle.coordinates.at(
Current).data(),
421 numberOfNeighborLists,
423 subconfigOfParticle.particleContributing.data());
425 MatrixXd localForces(subconfigOfParticle.numberOfParticles,
DIM);
426 localForces.setZero();
430 subconfigOfParticle.particleContributing,
457 double forceMax= localForces.cwiseAbs().maxCoeff();
459 std::vector<double> fij = rigidity.
project(localForces.reshaped<Eigen::RowMajor>()/forceMax);
463 for(
int kLocal= 0; kLocal<subconfigOfParticle.numberOfParticles; ++kLocal) {
464 int i_particlek = subconfigOfParticle.localGlobalMap.at(kLocal);
465 for (
int jLocal= kLocal+1; jLocal < subconfigOfParticle.numberOfParticles; ++jLocal) {
467 int i_particlej = subconfigOfParticle.localGlobalMap.at(jLocal);
469 for (
int i_neighborOfk = 0; i_neighborOfk < bonds.
nlOne_ptr->
Nneighbors[i_particlek]; ++i_neighborOfk) {
472 fijCopy[index] -= fij[indexLocal]*forceMax;
478 for (
int i_neighborOfj = 0;
482 fijCopy[index] -= fij[indexLocal]*forceMax;
496 for(
const auto& elem : fijCopy)
498 bonds.
fij[i_fijCopy]+= elem;
504 std::cout.rdbuf(cout_buf);
505 std::cout <<
"Done with local force calculations" << std::endl;
511 MY_HEADING(
"Checking error in interatomic forces");
515 for(
int i_particlei=0; i_particlei<subconfig.numberOfParticles; ++i_particlei) {
516 if (subconfig.particleContributing[i_particlei] == 0)
continue;
517 Vector3d particlei = subconfig.coordinates.at(
Current).row(i_particlei);
518 for (
int i_neighborOfi = 0; i_neighborOfi < bonds.
nlOne_ptr->
Nneighbors[i_particlei]; ++i_neighborOfi) {
521 Vector3d particlej = subconfig.coordinates.at(
Current).row(i_particlej);
522 Vector3d eij = (particlei - particlej).normalized();
523 fi.row(i_particlei) -= bonds.
fij[index] * eij;
529 for(
int i_particlei=0; i_particlei<subconfig.numberOfParticles; ++i_particlei) {
530 if (subconfig.particleContributing[i_particlei] == 0)
continue;
531 maxError= std::max(maxError,(forces.row(i_particlei)-fi.row(i_particlei)).norm());
533 std::cout <<
"Maximum error in f_i - sum_j f_ij: " << maxError << std::endl;
534 std::cout <<
"Done" << std::endl;
542 for(
const auto& pgrid : pgridList)
546 int numberOfGridPoints= pgrid->coordinates.size();
547 std::cout << i_grid+1 <<
". Number of grid points: " << numberOfGridPoints << std::endl;
549 #pragma omp parallel for
551 for(
int i_gridPoint=0; i_gridPoint<numberOfGridPoints; i_gridPoint++)
553 const auto& gridPoint= pgrid->coordinates[i_gridPoint];
554 if ( numberOfGridPoints<10 || (i_gridPoint+1)%(numberOfGridPoints/10) == 0)
556 progress= (double)(i_gridPoint+1)/numberOfGridPoints;
559 std::set<int> neighborListOne, neighborListTwo;
560 if (i_grid<numberOfPiolaStresses)
562 neighborListOne= neighborListsOfReferenceGridsOne[i_grid].getGridPointNeighbors(i_gridPoint);
563 neighborListTwo= neighborListsOfReferenceGridsTwo[i_grid].getGridPointNeighbors(i_gridPoint);
567 neighborListOne= neighborListsOfCurrentGridsOne[i_grid-numberOfPiolaStresses].getGridPointNeighbors(i_gridPoint);
568 neighborListTwo= neighborListsOfCurrentGridsTwo[i_grid-numberOfPiolaStresses].getGridPointNeighbors(i_gridPoint);
570 for (
const auto& particle1 : neighborListOne)
573 ra= rA= rb= rB= rab= rAB= Vector3d::Zero();
575 if(numberOfPiolaStresses>0) rA= subconfig.coordinates.at(
Reference).row(particle1) - gridPoint;
576 ra= subconfig.coordinates.at(
Current).row(particle1) - gridPoint;
581 for(
int i_neighborOf1= 0; i_neighborOf1<numberOfNeighborsOf1; i_neighborOf1++)
584 double fij= bonds.
fij[index];
585 if (fij == 0)
continue;
589 if(numberOfPiolaStresses>0) rB= subconfig.coordinates.at(
Reference).row(particle2) - gridPoint;
590 rb= subconfig.coordinates.at(
Current).row(particle2) - gridPoint;
593 if ( (neighborListOne.find(particle2) != neighborListOne.end() && particle1 < particle2))
600 if ( neighborListOne.find(particle2) != neighborListOne.end() ||
601 neighborListTwo.find(particle2) != neighborListTwo.end())
603 if(numberOfPiolaStresses>0) rAB= subconfig.coordinates.at(
Reference).row(particle1)-subconfig.coordinates.at(
Reference).row(particle2);
604 rab= subconfig.coordinates.at(
Current).row(particle1)-subconfig.coordinates.at(
Current).row(particle2);
605 if (i_grid<numberOfPiolaStresses)
608 recursiveBuildStress(fij,ra,rA,rb,rB,rab,rAB,i_gridPoint,i_grid-numberOfPiolaStresses,cauchyStress);
614 std::cout <<
"Done with grid " << pgrid << std::endl;
615 std::cout << std::endl;