MDStressLab++
Loading...
Searching...
No Matches
calculateStress.cpp
Go to the documentation of this file.
1/*
2 * calculateStress.cpp
3 *
4 * Created on: Nov 7, 2019
5 * Author: Nikhil
6 */
7
8#include <string>
9#include <iostream>
10#include <vector>
11#include "neighbor_list.h"
12#include "InteratomicForces.h"
13#include "kim.h"
14#include "BoxConfiguration.h"
15#include "Configuration.h"
16#include "SubConfiguration.h"
17#include "Stress.h"
18#include "typedef.h"
19#include "StressTuple.h"
20#include "helper.hpp"
21#include "Rigidity.h"
22#include <tuple>
23#include <chrono>
24#include <omp.h>
25
27 Kim& kim,
28 std::tuple<> stress,
29 const bool& projectForces=false)
30{
31
32 MY_WARNING("No stress calculation requested. Returning to caller.");
33 return 1;
34
35}
36
37template<typename ...BF>
39 Kim& kim,
40 std::tuple<Stress<BF,Cauchy>&...> stress,
41 const bool& projectForces=false)
42{
43 std::tuple<> emptyTuple;
44 return calculateStress(body,
45 kim,
46 emptyTuple,
47 stress,
48 projectForces);
49 /*
50 if (stressType == Piola)
51 return calculateStress(body,
52 kim,
53 stress,
54 emptyTuple);
55 else if (stressType == Cauchy)
56 return calculateStress(body,
57 kim,
58 emptyTuple,
59 stress);
60 else
61 MY_ERROR("Unrecognized stress type " + std::to_string(stressType));
62 */
63}
64template<typename ...BF>
66 Kim& kim,
67 std::tuple<Stress<BF,Piola>&...> stress,
68 const bool& projectForces=false)
69{
70 std::tuple<> emptyTuple;
71 return calculateStress(body,
72 kim,
73 stress,
74 emptyTuple,
75 projectForces);
76}
77
78// This is the main driver of stress calculation
79template<typename ...TStressPiola, typename ...TStressCauchy>
81 Kim& kim,
82 std::tuple<TStressPiola&...> piolaStress,
83 std::tuple<TStressCauchy&...> cauchyStress,
84 const bool& projectForces=false)
85{
86 int status= 0;
87 int numberOfPiolaStresses= sizeof...(TStressPiola);
88 int numberOfCauchyStresses= sizeof...(TStressCauchy);
89
90
91 if (numberOfPiolaStresses == 0 && numberOfCauchyStresses == 0)
92 {
93 MY_WARNING("No stress calculation requested. Returning to caller.");
94 return 1;
95 }
96
97 // At least one stress is being requested
98 MY_BANNER("Begin stress calculation");
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;
102
103 // nullify the stress fields before starting
104 recursiveNullifyStress(piolaStress);
105 recursiveNullifyStress(cauchyStress);
106
107 if (numberOfPiolaStresses > 0)
108 {
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;
112 auto referenceGridDomainSizePairs= getTGridDomainSizePairs(std::move(piolaStress));
113 for (const auto& pair : referenceGridDomainSizePairs)
114 std::cout << std::setw(25) << (GridBase*) pair.first << std::setw(25) << pair.second << std::endl;
115
116 if (body.coordinates.at(Reference).rows() == 0)
117 {
118 MY_WARNING("No reference coordinates detected to compute Piola stress.");
119 if (numberOfCauchyStresses>0)
120 {
121 MY_WARNING("Restarting stress calculation with only Cauchy stress.");
122 status= calculateStress(body,kim,cauchyStress,projectForces);
123 if (status==1)
124 return status;
125 else
126 MY_ERROR("Error in stress computation.");
127 }
128 else
129 {
130 MY_BANNER("End of stress calculation");
131 return 1;
132 }
133 }
134 }
135
136 if (numberOfCauchyStresses>0)
137 {
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;
141 auto currentGridDomainSizePairs= getTGridDomainSizePairs(cauchyStress);
142 for (const auto& pair : currentGridDomainSizePairs)
143 std::cout << std::setw(25) << (GridBase*) pair.first << std::setw(25) << pair.second << std::endl;
144
145
146 }
147 std::cout << std::endl;
148
149
150 double maxAveragingDomainSize= std::max(averagingDomainSize_max(piolaStress),averagingDomainSize_max(cauchyStress));
151 std::cout << "Maximum averaging domain size across all stresses = " << maxAveragingDomainSize << std::endl;
152
153 if (body.pbc.any() == 1)
154 {
155 std::unique_ptr<const Configuration> pconfig;
156 MY_HEADING("Generating padding atoms for periodic boundary conditions");
157
158 double influenceDistance= kim.influenceDistance;
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;
164
165
166 // TODO Change step to accommodate non-orthogonal boundary conditions
167 Vector3d origin= Vector3d::Zero();
168 Vector3d step= body.box.diagonal();
169 //recursiveFold(origin,step,body.pbc,piolaStress);
170 //recursiveFold(origin,step,body.pbc,cauchyStress);
171
172 status= calculateStress(pconfig.get(),kim,piolaStress,cauchyStress,projectForces);
173 }
174 else
175 {
176 status= calculateStress(&body,kim,piolaStress,cauchyStress,projectForces);
177 }
178
179// recursiveWriteStressAndGrid(piolaStress);
180// recursiveWriteStressAndGrid(cauchyStress);
181
182 if (status==1)
183 {
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;
193 MY_BANNER("End of stress calculation");
194 return status;
195 }
196 else
197 MY_ERROR("Error in stress computation.");
198
199}
200
201template<typename ...TStressPiola,typename ...TStressCauchy>
203 Kim& kim,
204 std::tuple<TStressPiola&...> piolaStress,
205 std::tuple<TStressCauchy&...> cauchyStress,
206 const bool& projectForces=false)
207{
208 assert(!(kim.kim_ptr==nullptr) && "Model not initialized");
209 double influenceDistance= kim.influenceDistance;
210 int numberOfPiolaStresses= sizeof...(TStressPiola);
211 int numberOfCauchyStresses= sizeof...(TStressCauchy);
212
213// ------------------------------------------------------------------
214// Generate a local configuration
215// ------------------------------------------------------------------
216 MY_HEADING("Building a local configuration");
217
218// Mappings from set of unique grids to the set of maximum averaging domain sizes
219 const auto referenceGridAveragingDomainSizeMap=
221 const auto currentGridAveragingDomainSizeMap=
223
224 Stencil stencil(*pconfig);
225
226 if (numberOfPiolaStresses>0)
227 {
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)
232 {
233 std::cout << std::setw(25) << (GridBase*)pgrid << std::setw(25) << domainSize << std::endl;
234 stencil.expandStencil(pgrid,domainSize+influenceDistance,influenceDistance);
235 }
236 }
237
238 if (numberOfCauchyStresses>0)
239 {
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)
244 {
245 std::cout << std::setw(25) << (GridBase*)pgrid << std::setw(25) << domainSize << std::endl;
246 stencil.expandStencil(pgrid,domainSize+influenceDistance,influenceDistance);
247 }
248 }
249
250 std::cout << std::endl;
251 std::cout << "Creating a local configuration using the above grids." << std::endl;
252 SubConfiguration subconfig{stencil};
253 int numberOfParticles= subconfig.numberOfParticles;
254 if (numberOfParticles == 0)
255 {
256 std::string message= "All grids away from the current material. Stresses are identically zero. Returning to the caller.";
257 //MY_ERROR(message);
258 throw(std::runtime_error(message));
259 }
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;
262
263
264// ------------------------------------------------------------------
265// Generate neighbor lists for all the grids
266// ------------------------------------------------------------------
267 std::vector<GridSubConfiguration<Reference>> neighborListsOfReferenceGridsOne;
268 std::vector<GridSubConfiguration<Reference>> neighborListsOfReferenceGridsTwo;
269 std::vector<GridSubConfiguration<Current>> neighborListsOfCurrentGridsOne;
270 std::vector<GridSubConfiguration<Current>> neighborListsOfCurrentGridsTwo;
271
272 auto referenceGridDomainSizePairs= getTGridDomainSizePairs(std::move(piolaStress));
273 assert(numberOfPiolaStresses==referenceGridDomainSizePairs.size());
274
275 auto currentGridDomainSizePairs= getTGridDomainSizePairs(cauchyStress);
276 assert(numberOfCauchyStresses == currentGridDomainSizePairs.size());
277
278 for(const auto& gridDomainSizePair : referenceGridDomainSizePairs)
279 {
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);
284 }
285 for(const auto& gridDomainSizePair : currentGridDomainSizePairs)
286 {
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);
291 }
292 assert(neighborListsOfCurrentGridsOne.size() == numberOfCauchyStresses &&
293 neighborListsOfCurrentGridsTwo.size() == numberOfCauchyStresses &&
294 neighborListsOfReferenceGridsOne.size() == numberOfPiolaStresses &&
295 neighborListsOfReferenceGridsTwo.size() == numberOfPiolaStresses);
296
297 std::vector<GridBase*> pgridListPiola= getBaseGridList(piolaStress);
298 std::vector<GridBase*> pgridListCauchy= getBaseGridList(cauchyStress);
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);
304
305
306
307// ------------------------------------------------------------------
308// Building neighbor list for bonds
309// ------------------------------------------------------------------
310 double bondCutoff;
311 bondCutoff= 2.0*influenceDistance;
312 std::cout << "bond cutoff = " << bondCutoff << std::endl;
313
314 NeighList* nlForBonds;
315 nbl_initialize(&nlForBonds);
316 nbl_build(nlForBonds,numberOfParticles,
317 subconfig.coordinates.at(Current).data(),
318 bondCutoff,
319 1,
320 &bondCutoff,
321 subconfig.particleContributing.data());
322 InteratomicForces bonds(nlForBonds);
323
324 // ------------------------------------------------------------------
325 // Build neighbor list of particles
326 // ------------------------------------------------------------------
327 MY_HEADING("Building neighbor list");
328 const double* cutoffs= kim.getCutoffs();
329 int numberOfNeighborLists= kim.getNumberOfNeighborLists();
330
331 // TODO: assert whenever the subconfiguration is empty
332 NeighList* nl;
333 nbl_initialize(&nl);
334 nbl_build(nl,numberOfParticles,
335 subconfig.coordinates.at(Current).data(),
336 influenceDistance,
337 numberOfNeighborLists,
338 cutoffs,
339 subconfig.particleContributing.data());
340
341 int neighborListSize= 0;
342 for (int i_particle=0; i_particle<numberOfParticles; i_particle++)
343 neighborListSize+= nl->lists->Nneighbors[i_particle];
344 std::cout << "Size of neighbor list = " <<neighborListSize << std::endl;
345
346
347 MatrixXd forces(numberOfParticles,DIM);
348 forces.setZero();
349
350 if (!projectForces) {
351 // ------------------------------------------------------------------
352 // Broadcast to model
353 // ------------------------------------------------------------------
354 MY_HEADING("Broadcasting to model");
355 kim.broadcastToModel(&subconfig,
356 subconfig.particleContributing,
357 &forces,
358 nl,
359 (KIM::Function *) &nbl_get_neigh,
360 &bonds,
361 (KIM::Function *) &process_DEDr);
362 std::cout << "Done" << std::endl;
363
364 // ------------------------------------------------------------------
365 // Compute forces
366 // ------------------------------------------------------------------
367 MY_HEADING("Computing forces");
368 kim.compute();
369 std::cout << "Done" << std::endl;
370 //nbl_clean(&nl);
371 }
372 else
373 {
374 kim.broadcastToModel(&subconfig,
375 subconfig.particleContributing,
376 &forces,
377 nl,
378 (KIM::Function *) &nbl_get_neigh,
379 nullptr,
380 nullptr);
381 kim.compute();
382
383 // ------------------------------------------------------------------
384 // Beginning force projection
385 // ------------------------------------------------------------------
386 MY_HEADING("Beginning force projection")
387 std::ofstream null_stream("/dev/null"); // For Unix/Linux/macOS
388 std::streambuf* cout_buf = std::cout.rdbuf(); // Save original buffer
389 std::cout.rdbuf(null_stream.rdbuf()); // Redirect std::cout to null
390 #pragma omp parallel
391 {
392 Kim* p_kimLocal;
393 #pragma omp critical
394 p_kimLocal= new Kim(kim.modelname);
395 //Kim kimLocal(kim.modelname);
396 std::vector<double> fijCopy(bonds.fij.size(),0.0);
397 #pragma omp for
398 for (int i_particlei = 0; i_particlei < subconfig.numberOfParticles; ++i_particlei) {
399 // consider only contributing particles
400 if (subconfig.particleContributing[i_particlei] == 0) continue;
401
402 std::cout << i_particlei << std::endl;
403 // stencil out particle and its neighborhood
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,
408 influenceDistance);
409 SubConfiguration subconfigOfParticle{singleParticleStencil};
410
411 // form neighborlist of the particle
412 const double *cutoffs = p_kimLocal->getCutoffs();
413 int numberOfNeighborLists = p_kimLocal->getNumberOfNeighborLists();
414
415 // TODO: assert whenever the subconfiguration is empty
416 NeighList *nlOfParticle;
417 nbl_initialize(&nlOfParticle);
418 nbl_build(nlOfParticle, subconfigOfParticle.numberOfParticles,
419 subconfigOfParticle.coordinates.at(Current).data(),
420 influenceDistance,
421 numberOfNeighborLists,
422 cutoffs,
423 subconfigOfParticle.particleContributing.data());
424
425 MatrixXd localForces(subconfigOfParticle.numberOfParticles, DIM);
426 localForces.setZero();
427
428 // broadcast to model
429 p_kimLocal->broadcastToModel(&subconfigOfParticle,
430 subconfigOfParticle.particleContributing,
431 &localForces,
432 nlOfParticle,
433 (KIM::Function *) &nbl_get_neigh,
434 nullptr,
435 nullptr);
436 // compute partial forces
437 p_kimLocal->compute();
438
439 /*
440 // check moment
441 Vector3d moment, totalForce;
442 moment.setZero(); totalForce.setZero();
443 for(int i_row=0; i_row<forces.rows(); ++i_row)
444 {
445 Vector3d pos= subconfigOfParticle.coordinates.at(Current).row(i_row);
446 Vector3d f= forces.row(i_row);
447 moment= moment+pos.cross(f);
448 totalForce= totalForce + f;
449 }
450 std::cout << "moment = " << std::endl;
451 std::cout << moment << std::endl;
452 std::cout << "total force = " << std::endl;
453 std::cout << totalForce << std::endl;
454 */
455
456 Rigidity rigidity(subconfigOfParticle.coordinates.at(Current));
457 double forceMax= localForces.cwiseAbs().maxCoeff();
458
459 std::vector<double> fij = rigidity.project(localForces.reshaped<Eigen::RowMajor>()/forceMax);
460
461 // loop over the local bonds and collect all interatomic forces
462 int indexLocal= -1;
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) {
466 indexLocal++;
467 int i_particlej = subconfigOfParticle.localGlobalMap.at(jLocal);
468 // look for particlej in the neighborhood of particlek in bonds
469 for (int i_neighborOfk = 0; i_neighborOfk < bonds.nlOne_ptr->Nneighbors[i_particlek]; ++i_neighborOfk) {
470 int index = bonds.nlOne_ptr->beginIndex[i_particlek] + i_neighborOfk;
471 if (i_particlej == bonds.nlOne_ptr->neighborList[index]) {
472 fijCopy[index] -= fij[indexLocal]*forceMax;
473 break;
474 }
475 }
476
477 // look for particlek in the neighborhood of particlej
478 for (int i_neighborOfj = 0;
479 i_neighborOfj < bonds.nlOne_ptr->Nneighbors[i_particlej]; ++i_neighborOfj) {
480 int index = bonds.nlOne_ptr->beginIndex[i_particlej] + i_neighborOfj;
481 if (i_particlek == bonds.nlOne_ptr->neighborList[index]) {
482 fijCopy[index] -= fij[indexLocal]*forceMax;
483 break;
484 }
485 }
486 }
487 }
488 nbl_clean(&nlOfParticle);
489 }
490
491 delete p_kimLocal;
492 p_kimLocal= nullptr;
493 #pragma omp critical
494 {
495 int i_fijCopy= 0;
496 for(const auto& elem : fijCopy)
497 {
498 bonds.fij[i_fijCopy]+= elem;
499 i_fijCopy++;
500 }
501 }
502 }
503
504 std::cout.rdbuf(cout_buf); // Restore the original stream buffer
505 std::cout << "Done with local force calculations" << std::endl;
506 }
507
508 // ------------------------------------------------------------------
509 // Checking error in interatomic forces
510 // ------------------------------------------------------------------
511 MY_HEADING("Checking error in interatomic forces");
512 // fi: total force from the interatomic force projection
513 MatrixXd fi(numberOfParticles,DIM);
514 fi.setZero();
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) {
519 int index = bonds.nlOne_ptr->beginIndex[i_particlei] + i_neighborOfi;
520 int i_particlej = bonds.nlOne_ptr->neighborList[index];
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;
524 }
525 }
526
527 // check if gi~fi
528 double maxError=0;
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());
532 }
533 std::cout << "Maximum error in f_i - sum_j f_ij: " << maxError << std::endl;
534 std::cout << "Done" << std::endl;
535 nbl_clean(&nl);
536// ------------------------------------------------------------------
537// Loop over local grid points and accumulate stress
538// ------------------------------------------------------------------
539 MY_HEADING("Looping over grids");
540
541 int i_grid= 0;
542 for(const auto& pgrid : pgridList)
543 {
544 //int i_gridPoint= 0;
545 double progress= 0;
546 int numberOfGridPoints= pgrid->coordinates.size();
547 std::cout << i_grid+1 << ". Number of grid points: " << numberOfGridPoints << std::endl;
548
549 #pragma omp parallel for
550 //for (const auto& gridPoint : pgrid->coordinates)
551 for(int i_gridPoint=0; i_gridPoint<numberOfGridPoints; i_gridPoint++)
552 {
553 const auto& gridPoint= pgrid->coordinates[i_gridPoint];
554 if ( numberOfGridPoints<10 || (i_gridPoint+1)%(numberOfGridPoints/10) == 0)
555 {
556 progress= (double)(i_gridPoint+1)/numberOfGridPoints;
557 progressBar(progress);
558 }
559 std::set<int> neighborListOne, neighborListTwo;
560 if (i_grid<numberOfPiolaStresses)
561 {
562 neighborListOne= neighborListsOfReferenceGridsOne[i_grid].getGridPointNeighbors(i_gridPoint);
563 neighborListTwo= neighborListsOfReferenceGridsTwo[i_grid].getGridPointNeighbors(i_gridPoint);
564 }
565 else
566 {
567 neighborListOne= neighborListsOfCurrentGridsOne[i_grid-numberOfPiolaStresses].getGridPointNeighbors(i_gridPoint);
568 neighborListTwo= neighborListsOfCurrentGridsTwo[i_grid-numberOfPiolaStresses].getGridPointNeighbors(i_gridPoint);
569 }
570 for (const auto& particle1 : neighborListOne)
571 {
572 Vector3d ra,rA,rb,rB,rab,rAB;
573 ra= rA= rb= rB= rab= rAB= Vector3d::Zero();
574
575 if(numberOfPiolaStresses>0) rA= subconfig.coordinates.at(Reference).row(particle1) - gridPoint;
576 ra= subconfig.coordinates.at(Current).row(particle1) - gridPoint;
577 int index;
578 int numberOfNeighborsOf1= bonds.nlOne_ptr->Nneighbors[particle1];
579
580// Loop through the bond neighbors of particle1
581 for(int i_neighborOf1= 0; i_neighborOf1<numberOfNeighborsOf1; i_neighborOf1++)
582 {
583 index= bonds.nlOne_ptr->beginIndex[particle1]+i_neighborOf1;
584 double fij= bonds.fij[index];
585 if (fij == 0) continue;
586
587// At this point, the force in the bond connecting particles 1 and 2 is nonzero
588 int particle2= bonds.nlOne_ptr->neighborList[index];
589 if(numberOfPiolaStresses>0) rB= subconfig.coordinates.at(Reference).row(particle2) - gridPoint;
590 rb= subconfig.coordinates.at(Current).row(particle2) - gridPoint;
591// Ignore if (particle2 is in neighborListOne and particle 1 > particle 2) as this pair
592// is encountered twice
593 if ( (neighborListOne.find(particle2) != neighborListOne.end() && particle1 < particle2))
594 continue;
595
596// Since neighborListOne \subset of neighborListTwo, the following condition if(A||B)
597// is equivalent if(B). Nevertheless, we have if(A||B) since B is expensive, and it is never
598// evaluated if A is true.
599
600 if ( neighborListOne.find(particle2) != neighborListOne.end() ||
601 neighborListTwo.find(particle2) != neighborListTwo.end())
602 {
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)
606 recursiveBuildStress(fij,ra,rA,rb,rB,rab,rAB,i_gridPoint,i_grid,piolaStress);
607 else
608 recursiveBuildStress(fij,ra,rA,rb,rB,rab,rAB,i_gridPoint,i_grid-numberOfPiolaStresses,cauchyStress);
609 }
610 }
611 }
612 //i_gridpoint++;
613 }
614 std::cout << "Done with grid " << pgrid << std::endl;
615 std::cout << std::endl;
616
617 i_grid++;
618 }
619
620 // Collect all the stress fields in processor 0
621
622 nbl_clean(&nlForBonds);
623 return 1;
624}
625
626
627int process_DEDr(const void* dataObject, const double de, const double r, const double* const dx, const int i, const int j)
628 {
629 InteratomicForces* bonds_ptr= (InteratomicForces*) dataObject;
630 int index;
631 int numberOfNeighborsOfi = bonds_ptr->nlOne_ptr->Nneighbors[i];
632 int numberOfNeighborsOfj = bonds_ptr->nlOne_ptr->Nneighbors[j];
633 bool iFound= false;
634 bool jFound= false;
635
636 // Look for j in the neighbor list of i
637 for(int i_neighborOfi= 0; i_neighborOfi<numberOfNeighborsOfi; i_neighborOfi++)
638 {
639 index= bonds_ptr->nlOne_ptr->beginIndex[i]+i_neighborOfi;
640 if(bonds_ptr->nlOne_ptr->neighborList[index] == j)
641 {
642 bonds_ptr->fij[index]+= de;
643 jFound= true;
644 break;
645 }
646 }
647 // Look for i in the neighbor list of j
648 for(int i_neighborOfj= 0; i_neighborOfj<numberOfNeighborsOfj; i_neighborOfj++)
649 {
650 index= bonds_ptr->nlOne_ptr->beginIndex[j]+i_neighborOfj;
651 if(bonds_ptr->nlOne_ptr->neighborList[index] == i)
652 {
653 bonds_ptr->fij[index]+= de;
654 iFound= true;
655 break;
656 }
657
658 }
659 return 0;
660 }
double averagingDomainSize_max(const std::tuple<> t)
Definition StressTuple.h:72
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)
Definition StressTuple.h:14
std::enable_if< I< sizeof...(BF), std::map< TGrid *, double > >::type recursiveGridMaxAveragingDomainSizeMap(const std::tuple< Stress< BF, stressType > &... > t){ std::map< TGrid *, double > map;const std::map< TGrid *, double > &rmap=recursiveGridMaxAveragingDomainSizeMap< I+1 >(t);map[std::get< I >(t).pgrid]=std::get< I >(t).method.getAveragingDomainSize();for(const auto &pair :rmap) if(std::get< I >(t).pgrid==pair.first) { map[pair.first]=std::max(map.at(std::get< I >(t).pgrid), pair.second);} else { auto result=map.insert(pair);assert(result.second==true);} return map;}inline std::vector< std::pair< Grid< Current > *, double > getTGridDomainSizePairs(const std::tuple<> &emptyTuple)
std::vector< GridBase * > getBaseGridList(const std::tuple<> t)
std::enable_if< I< sizeof...(TStress) -1, double >::type averagingDomainSize_max(const std::tuple< TStress &... > t){ return std::max(std::get< I >(t).method.getAveragingDomainSize(), averagingDomainSize_max< I+1 >(t));}std::map< Grid< Reference > double recursiveGridMaxAveragingDomainSizeMap(const std::tuple<> &t)
Definition StressTuple.h:91
int calculateStress(const BoxConfiguration &body, Kim &kim, std::tuple<> stress, const bool &projectForces=false)
int process_DEDr(const void *dataObject, const double de, const double r, const double *const dx, const int i, const int j)
Represents a particle configuration including simulation box information.
Vector3i pbc
Periodic boundary conditions. pbc=(1,0,1) implies periodicity along the and -directions.
Configuration * getConfiguration(double padding) const
This function returns a padded configuration by adding padding atoms originating due to pbcs.
Matrix3d box
The current and reference box vectors stored as columns of respective matrices.
Represents atomic configuration data including coordinates, velocities, and species.
std::map< ConfigType, MatrixXd > coordinates
Map from configuration type (Reference or Current) to coordinate matrices.
const NeighListOne * nlOne_ptr
std::vector< double > fij
Definition kim.h:21
const double * getCutoffs() const
Definition kim.cpp:48
double influenceDistance
Definition kim.h:25
void compute()
Definition kim.cpp:303
void broadcastToModel(const Configuration *config_ptr, const VectorXi &particleContributing, const MatrixXd *forces_ptr, NeighList *nl_ptr, KIM::Function *get_neigh_ptr, InteratomicForces *bonds, KIM::Function *processDEDr_ptr)
Definition kim.cpp:254
std::string modelname
Definition kim.h:24
int getNumberOfNeighborLists() const
Definition kim.cpp:59
KIM::Model * kim_ptr
Definition kim.h:26
std::vector< double > project(const Eigen::VectorXd &gi) const
Definition Rigidity.cpp:40
void expandStencil(const std::vector< Vector3d > &gridCoordinates, const MatrixXd &coordinates, const double &contributingNeighborhoodSize, const double &noncontributingNeighborhoodSize)
Definition Stencil.h:30
void progressBar(const double &progress)
Definition helper.hpp:116
void nbl_initialize(NeighList **const nl)
int nbl_build(NeighList *const nl, int const numberOfParticles, double const *coordinates, double const influenceDistance, int const numberOfCutoffs, double const *cutoffs, int const *needNeighbors)
void nbl_clean(NeighList **const nl)
#define DIM
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)
NeighListOne * lists
#define MY_ERROR(message)
Definition typedef.h:17
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > MatrixXd
Definition typedef.h:54
Eigen::Matrix< double, 1, DIM, Eigen::RowMajor > Vector3d
Definition typedef.h:60
@ Current
Definition typedef.h:70
@ Reference
Definition typedef.h:69
#define MY_HEADING(heading)
Definition typedef.h:36
#define MY_WARNING(message)
Definition typedef.h:24
#define MY_BANNER(announcement)
Definition typedef.h:30