29 MY_WARNING(
"No stress calculation requested. Returning to caller.");
33 template<
typename ...BF,
StressType stressType>
38 std::tuple<> emptyTuple;
39 if (stressType ==
Piola)
44 else if (stressType ==
Cauchy)
50 MY_ERROR(
"Unrecognized stress type " + std::to_string(stressType));
54 template<
typename ...TStressPiola,
typename ...TStressCauchy>
57 std::tuple<TStressPiola&...> piolaStress,
58 std::tuple<TStressCauchy&...> cauchyStress)
61 int numberOfPiolaStresses=
sizeof...(TStressPiola);
62 int numberOfCauchyStresses=
sizeof...(TStressCauchy);
65 if (numberOfPiolaStresses == 0 && numberOfCauchyStresses == 0)
67 MY_WARNING(
"No stress calculation requested. Returning to caller.");
73 auto start = std::chrono::system_clock::now();
74 std::time_t startTime = std::chrono::system_clock::to_time_t(start);
75 std::cout <<
"Time stamp: " << std::ctime(&startTime) << std::endl;
78 recursiveNullifyStress(piolaStress);
79 recursiveNullifyStress(cauchyStress);
81 if (numberOfPiolaStresses > 0)
83 std::cout <<
"Number of Piola stresses requested : " << numberOfPiolaStresses << std::endl;
84 std::cout << std::endl;
85 std::cout << std::setw(25) <<
"Grid" << std::setw(25) <<
"Averaging domain size" << std::endl;
86 auto referenceGridDomainSizePairs= getTGridDomainSizePairs(piolaStress);
87 for (
const auto& pair : referenceGridDomainSizePairs)
88 std::cout << std::setw(25) << (
GridBase*) pair.first << std::setw(25) << pair.second << std::endl;
92 MY_WARNING(
"No reference coordinates detected to compute Piola stress.");
93 if (numberOfCauchyStresses>0)
95 MY_WARNING(
"Restarting stress calculation with only Cauchy stress.");
100 MY_ERROR(
"Error in stress computation.");
110 if (numberOfCauchyStresses>0)
112 std::cout <<
"Number of Cauchy stresses requested: " << numberOfCauchyStresses << std::endl;
113 std::cout << std::endl;
114 std::cout << std::setw(25) <<
"Grid" << std::setw(25) <<
"Averaging domain size" << std::endl;
115 auto currentGridDomainSizePairs= getTGridDomainSizePairs(cauchyStress);
116 for (
const auto& pair : currentGridDomainSizePairs)
117 std::cout << std::setw(25) << (
GridBase*) pair.first << std::setw(25) << pair.second << std::endl;
121 std::cout << std::endl;
124 double maxAveragingDomainSize= std::max(averagingDomainSize_max(piolaStress),averagingDomainSize_max(cauchyStress));
125 std::cout <<
"Maximum averaging domain size across all stresses = " << maxAveragingDomainSize << std::endl;
127 if (body.
pbc.any() == 1)
129 std::unique_ptr<const Configuration> pconfig;
130 MY_HEADING(
"Generating padding atoms for periodic boundary conditions");
133 pconfig.reset(body.
getConfiguration(2*influenceDistance+maxAveragingDomainSize));
134 std::cout <<
"Thickness of padding = 2 influence distance + maximum averaging domain size = " 135 << 2*influenceDistance+maxAveragingDomainSize << std::endl;
136 std::cout <<
"Total number of atoms including padding atoms = " << pconfig->
numberOfParticles << std::endl;
137 std::cout << std::endl;
143 recursiveFold(origin,step,body.
pbc,piolaStress);
144 recursiveFold(origin,step,body.
pbc,cauchyStress);
158 std::cout << std::endl;
159 std::cout << std::endl;
160 std::cout << std::endl;
161 std::cout << std::endl;
162 auto end= std::chrono::system_clock::now();
163 std::time_t endTime= std::chrono::system_clock::to_time_t(end);
164 std::chrono::duration<double> elapsedSeconds(end-start);
165 std::cout <<
"Elapsed time: " << elapsedSeconds.count() <<
" seconds" << std::endl;
166 std::cout <<
"End of simulation" << std::endl;
171 MY_ERROR(
"Error in stress computation.");
175 template<
typename ...TStressPiola,
typename ...TStressCauchy>
178 std::tuple<TStressPiola&...> piolaStress,
179 std::tuple<TStressCauchy&...> cauchyStress)
181 assert(!(kim.
kim_ptr==
nullptr) &&
"Model not initialized");
183 int numberOfPiolaStresses=
sizeof...(TStressPiola);
184 int numberOfCauchyStresses=
sizeof...(TStressCauchy);
192 const auto referenceGridAveragingDomainSizeMap=
193 recursiveGridMaxAveragingDomainSizeMap(piolaStress);
194 const auto currentGridAveragingDomainSizeMap=
195 recursiveGridMaxAveragingDomainSizeMap(cauchyStress);
199 if (numberOfPiolaStresses>0)
201 std::cout <<
"Piola Stress" << std::endl;
202 std::cout << std::setw(25) <<
"Unique grid" << std::setw(30) <<
"Max. Averaging domain size" << std::endl;
203 std::cout << std::setw(25) <<
"-----------" << std::setw(30) <<
"--------------------------" << std::endl;
204 for(
const auto& [pgrid,domainSize] : referenceGridAveragingDomainSizeMap)
206 std::cout << std::setw(25) << (
GridBase*)pgrid << std::setw(25) << domainSize << std::endl;
207 stencil.
expandStencil(pgrid,domainSize+influenceDistance,influenceDistance);
211 if (numberOfCauchyStresses>0)
213 std::cout <<
"Cauchy Stress" << std::endl;
214 std::cout << std::setw(25) <<
"Unique grid" << std::setw(30) <<
"Max. Averaging domain size" << std::endl;
215 std::cout << std::setw(25) <<
"-----------" << std::setw(30) <<
"--------------------------" << std::endl;
216 for(
const auto& [pgrid,domainSize] : currentGridAveragingDomainSizeMap)
218 std::cout << std::setw(25) << (
GridBase*)pgrid << std::setw(25) << domainSize << std::endl;
219 stencil.
expandStencil(pgrid,domainSize+influenceDistance,influenceDistance);
223 std::cout << std::endl;
224 std::cout <<
"Creating a local configuration using the above grids." << std::endl;
226 int numberOfParticles= subconfig.numberOfParticles;
227 if (numberOfParticles == 0)
229 MY_ERROR(
"All grids away from the current material. Stresses are identically zero. Returning to the caller.")
232 std::cout <<
"Number of particle in the local configuration = " << numberOfParticles << std::endl;
233 std::cout <<
"Number of contributing particles = " << subconfig.particleContributing.sum() << std::endl;
239 std::vector<std::vector<std::set<int>>> neighborListsOfGridsOne,neighborListsOfGridsTwo;
241 auto referenceGridDomainSizePairs= getTGridDomainSizePairs(piolaStress);
242 assert(numberOfPiolaStresses==referenceGridDomainSizePairs.size());
244 auto currentGridDomainSizePairs= getTGridDomainSizePairs(cauchyStress);
245 assert(numberOfCauchyStresses == currentGridDomainSizePairs.size());
247 for(
const auto& gridDomainSizePair : referenceGridDomainSizePairs)
249 const auto& pgrid= gridDomainSizePair.first;
250 const auto& domainSize= gridDomainSizePair.second;
251 neighborListsOfGridsOne.push_back(pgrid->getGridNeighborLists(subconfig,domainSize+influenceDistance));
252 neighborListsOfGridsTwo.push_back(pgrid->getGridNeighborLists(subconfig,domainSize+2*influenceDistance));
254 for(
const auto& gridDomainSizePair : currentGridDomainSizePairs)
256 const auto& pgrid= gridDomainSizePair.first;
257 const auto& domainSize= gridDomainSizePair.second;
258 neighborListsOfGridsOne.push_back(pgrid->getGridNeighborLists(subconfig,domainSize+influenceDistance));
259 neighborListsOfGridsTwo.push_back(pgrid->getGridNeighborLists(subconfig,domainSize+2*influenceDistance));
261 assert(neighborListsOfGridsOne.size() == numberOfPiolaStresses + numberOfCauchyStresses &&
262 neighborListsOfGridsTwo.size() == numberOfPiolaStresses + numberOfCauchyStresses);
264 std::vector<GridBase*> pgridListPiola= getBaseGridList(piolaStress);
265 std::vector<GridBase*> pgridListCauchy= getBaseGridList(cauchyStress);
266 std::vector<GridBase*> pgridList;
267 pgridList.reserve( pgridListPiola.size() + pgridListCauchy.size() );
268 pgridList.insert( pgridList.end(), pgridListPiola.begin(), pgridListPiola.end() );
269 pgridList.insert( pgridList.end(), pgridListCauchy.begin(), pgridListCauchy.end() );
270 assert(pgridList.size() == numberOfPiolaStresses + numberOfCauchyStresses);
285 subconfig.coordinates.at(
Current).data(),
287 numberOfNeighborLists,
289 subconfig.particleContributing.data());
291 int neighborListSize= 0;
292 for (
int i_particle=0; i_particle<numberOfParticles; i_particle++)
294 std::cout <<
"Size of neighbor list = " <<neighborListSize << std::endl;
300 double bondCutoff= 2.0*influenceDistance;
304 subconfig.coordinates.at(
Current).data(),
308 subconfig.particleContributing.data());
316 subconfig.particleContributing,
321 std::cout <<
"Done" << std::endl;
328 std::cout <<
"Done" << std::endl;
336 ra= rA= rb= rB= rab= rAB= Vector3d::Zero();
338 for(
const auto& pgrid : pgridList)
340 const std::vector<std::set<int>>& neighborListsOne= neighborListsOfGridsOne[i_grid];
341 const std::vector<std::set<int>>& neighborListsTwo= neighborListsOfGridsTwo[i_grid];
345 int numberOfGridPoints= pgrid->coordinates.size();
346 std::cout << i_grid+1 <<
". Number of grid points: " << numberOfGridPoints << std::endl;
347 for (
const auto& gridPoint : pgrid->coordinates)
349 if ( numberOfGridPoints<10 || (i_gridPoint+1)%(numberOfGridPoints/10) == 0)
351 progress= (double)(i_gridPoint+1)/numberOfGridPoints;
354 const std::set<int>& neighborListOne= neighborListsOne[i_gridPoint];
355 const std::set<int>& neighborListTwo= neighborListsTwo[i_gridPoint];
356 for (
const auto& particle1 : neighborListOne)
358 if(numberOfPiolaStresses>0) rA= subconfig.coordinates.at(
Reference).row(particle1) - gridPoint;
359 ra= subconfig.coordinates.at(
Current).row(particle1) - gridPoint;
361 int numberOfNeighborsOf1= bonds.nlOne_ptr->Nneighbors[particle1];
364 for(
int i_neighborOf1= 0; i_neighborOf1<numberOfNeighborsOf1; i_neighborOf1++)
366 index= bonds.nlOne_ptr->beginIndex[particle1]+i_neighborOf1;
367 double fij= bonds.fij[index];
368 if (fij == 0)
continue;
371 int particle2= bonds.nlOne_ptr->neighborList[index];
372 if(numberOfPiolaStresses>0) rB= subconfig.coordinates.at(
Reference).row(particle2) - gridPoint;
373 rb= subconfig.coordinates.at(
Current).row(particle2) - gridPoint;
376 if ( (neighborListOne.find(particle2) != neighborListOne.end() && particle1 < particle2))
383 if ( neighborListOne.find(particle2) != neighborListOne.end() ||
384 neighborListTwo.find(particle2) != neighborListTwo.end())
386 if(numberOfPiolaStresses>0) rAB= subconfig.coordinates.at(
Reference).row(particle1)-subconfig.coordinates.at(
Reference).row(particle2);
387 rab= subconfig.coordinates.at(
Current).row(particle1)-subconfig.coordinates.at(
Current).row(particle2);
388 if (i_grid<numberOfPiolaStresses)
391 recursiveBuildStress(fij,ra,rA,rb,rB,rab,rAB,i_gridPoint,i_grid-numberOfPiolaStresses,cauchyStress);
397 std::cout <<
"Done with grid " << pgrid << std::endl;
398 std::cout << std::endl;
411 int process_DEDr(
const void* dataObject,
const double de,
const double r,
const double*
const dx,
const int i,
const int j)
421 for(
int i_neighborOfi= 0; i_neighborOfi<numberOfNeighborsOfi; i_neighborOfi++)
426 bonds_ptr->
fij[index]+= de;
432 for(
int i_neighborOfj= 0; i_neighborOfj<numberOfNeighborsOfj; i_neighborOfj++)
437 bonds_ptr->
fij[index]+= de;
#define MY_HEADING(heading)
std::enable_if< I==sizeof...(TStress), void >::type recursiveBuildStress(const double &fij, const Vector3d &ra, const Vector3d &rA, const Vector3d &rb, const Vector3d &rB, const Vector3d &rab, const Vector3d &rAB, const int &i_gridPoint, const int &i_stress, std::tuple< TStress &... > t)
std::map< ConfigType, MatrixXd > coordinates
void nbl_initialize(NeighList **const nl)
void broadcastToModel(const Configuration *config_ptr, const VectorXi &particleContributing, NeighList *nl_ptr, KIM::Function *get_neigh_ptr, InteratomicForces *bonds, KIM::Function *processDEDr_ptr)
#define MY_WARNING(message)
void progressBar(const double &progress)
Configuration * getConfiguration(double) const
void nbl_clean(NeighList **const nl)
#define MY_BANNER(announcement)
const double * getCutoffs() const
void expandStencil(const Grid< configType > *pgrid, const double &contributingNeighborhoodSize, const double &noncontributingNeighborhoodSize)
#define MY_ERROR(message)
std::vector< double > fij
int calculateStress(const BoxConfiguration &body, Kim &kim, std::tuple<> stress)
Eigen::Matrix< double, 1, DIM, Eigen::RowMajor > Vector3d
int nbl_get_neigh(void const *const dataObject, int const numberOfCutoffs, double const *const cutoffs, int const neighborListIndex, int const particleNumber, int *const numberOfNeighbors, int const **const neighborsOfParticle)
const NeighListOne * nlOne_ptr
int getNumberOfNeighborLists() const
int nbl_build(NeighList *const nl, int const numberOfParticles, double const *coordinates, double const influenceDistance, int const numberOfCutoffs, double const *cutoffs, int const *needNeighbors)
int process_DEDr(const void *dataObject, const double de, const double r, const double *const dx, const int i, const int j)