Mechanics of Defect Evolution Library
Loading...
Searching...
No Matches
toleranceStudy.cpp
Go to the documentation of this file.
1// Build with EllipsoidalInclusion.cpp, reference/SphericalInclusion.cpp,
2// and the MoDELib base (or tests/support headers). Use -O3 -DNDEBUG.
5#include <Eigen/Geometry>
6#include <algorithm>
7#include <chrono>
8#include <iomanip>
9#include <iostream>
10#include <random>
11#include <vector>
12#include <string>
13
14using V = Eigen::Vector3d;
15using M = Eigen::Matrix3d;
17using Clock = std::chrono::steady_clock;
18volatile double benchmarkSink = 0.0;
19
20// Separate translation units and no LTO keep stress() calls out of the timing loop.
21double measure(const Base &inclusion, const std::vector<V> &points)
22{
23 const auto start = Clock::now();
24 double checksum = 0.0;
25 std::size_t calls = 0;
26 double seconds = 0.0;
27 do
28 {
29 for(const auto &point : points)
30 {
31 checksum += inclusion.stress(point).sum();
32 }
33 calls += points.size();
34 seconds = std::chrono::duration<double>(Clock::now() - start).count();
35 } while(seconds < 0.02);
36 benchmarkSink = checksum;
37 return seconds * 1.e9 / calls;
38}
39
40struct Errors
41{
42 std::vector<double> loose;
43 double defaultMaximum = 0.0;
44 double sphereMaximum = 0.0;
45 double interiorMaximum = 0.0;
46 double worstFactor = 0.0;
47 double worstNu = 0.0;
48 int worstMode = 0;
49};
50int main(int argc, char **argv)
51{
52 const double trialTolerance = argc > 1 ? std::stod(argv[1]) : 1.e-4;
53 const M Q = Eigen::AngleAxisd(0.71, V(1, 2, 3).normalized()).toRotationMatrix();
54 const std::vector<V> geometries = {V(1, 1, 1), V(3, 2, 1), V(10, 1, 0.1), V(100, 1, 1), V(1, 1, 0.01)};
55 std::mt19937 rng(123);
56 std::normal_distribution<double> normal;
57 std::vector<V> directions;
58 for(int k = 0; k < 512; ++k)
59 {
60 const V direction(normal(rng), normal(rng), normal(rng));
61 directions.push_back(direction.normalized());
62 }
63 M mixed;
64 mixed << 0.01, 0.003, -0.002, 0.003, -0.006, 0.001, -0.002, 0.001, 0.004;
65 std::cout << "SPEED\naxes,region,sphere_ns,baseline_1e10_ns,loose_ns,speedup,loose_over_sphere\n";
66 for(const V &lengths : geometries)
67 {
68 model::SphericalInclusion<3> sphere(V::Zero(), lengths.minCoeff(), mixed, 0.31, 43.0, 1, 0, nullptr);
69 model::EllipsoidalInclusion<3> fine(V::Zero(), Q * lengths.asDiagonal(), mixed, 0.31, 43.0, 1, 0, nullptr,
70 1.e-10);
71 model::EllipsoidalInclusion<3> loose(V::Zero(), Q * lengths.asDiagonal(), mixed, 0.31, 43.0, 1, 0, nullptr,
72 trialTolerance);
73 for(double factor : {0.5, 1.000001, 2.0, 10.0})
74 {
75 std::vector<V> points;
76 for(const V &direction : directions)
77 {
78 if(factor < 1)
79 {
80 points.push_back(0.5 * lengths.minCoeff() * direction);
81 }
82 else
83 {
84 points.push_back(Q * (factor * lengths.cwiseProduct(direction)));
85 }
86 }
87 measure(sphere, points);
88 measure(fine, points);
89 measure(loose, points);
90 std::vector<double> st, ft, lt;
91 for(int trial = 0; trial < 7; ++trial)
92 {
93 st.push_back(measure(sphere, points));
94 if(trial % 2 == 0)
95 {
96 ft.push_back(measure(fine, points));
97 lt.push_back(measure(loose, points));
98 }
99 else
100 {
101 lt.push_back(measure(loose, points));
102 ft.push_back(measure(fine, points));
103 }
104 }
105 std::sort(st.begin(), st.end());
106 std::sort(ft.begin(), ft.end());
107 std::sort(lt.begin(), lt.end());
108 const char *region = factor < 1 ? "interior"
109 : factor < 1.1 ? "near_surface"
110 : factor < 3 ? "2x_surface"
111 : "10x_surface";
112 std::cout << lengths.transpose() << ',' << region << ',' << std::setprecision(8) << st[3] << ',' << ft[3]
113 << ',' << lt[3] << ',' << ft[3] / lt[3] << ',' << lt[3] / st[3] << std::endl;
114 }
115 }
116 std::cout
117 << "ACCURACY\naxes,count,max_relative,p95_relative,baseline_1e10_max_relative,interior_max_relative,sphere_max_"
118 "relative,worst_factor,worst_nu,worst_mode\n";
119 for(const V &lengths : geometries)
120 {
121 Errors errors;
122 for(double nu : {-0.8, 0.31, 0.49})
123 {
124 for(int mode = 0; mode < 8; ++mode)
125 {
126 M strain = M::Zero();
127 if(mode < 3)
128 {
129 strain(mode, mode) = 0.01;
130 }
131 else if(mode < 6)
132 {
133 const int i = mode == 5 ? 1 : 0;
134 const int j = mode == 3 ? 1 : 2;
135 strain(i, j) = strain(j, i) = 0.01;
136 }
137 else if(mode == 6)
138 {
139 strain = 0.01 * M::Identity();
140 }
141 else
142 {
143 strain = mixed;
144 }
145 model::EllipsoidalInclusion<3> ref(V::Zero(), Q * lengths.asDiagonal(), strain, nu, 43.0, 1, 0, nullptr,
146 1.e-12, 40);
147 model::EllipsoidalInclusion<3> fine(V::Zero(), Q * lengths.asDiagonal(), strain, nu, 43.0, 1, 0,
148 nullptr, 1.e-10);
149 model::EllipsoidalInclusion<3> loose(V::Zero(), Q * lengths.asDiagonal(), strain, nu, 43.0, 1, 0,
150 nullptr, trialTolerance);
151 model::SphericalInclusion<3> sphere(V::Zero(), 1.0, strain, nu, 43.0, 1, 0, nullptr);
152 for(double factor : {0.0, 1.0 + 1.e-12, 1.0 + 1.e-8, 1.001, 1.1, 2.0, 10.0, 1.e3, 1.e6})
153 {
154 const int samples = factor == 0 ? 1 : 32;
155 for(int k = 0; k < samples; ++k)
156 {
157 V direction;
158 if(k < 3)
159 {
160 direction = V::Unit(k);
161 }
162 else
163 {
164 direction = directions[k];
165 }
166 const V point = Q * (factor * lengths.cwiseProduct(direction));
167 const M reference = ref.stress(point), approx = loose.stress(point);
168 const double norm = std::max(1.e-300, reference.norm());
169 const double error = (approx - reference).norm() / norm;
170 const double defaultError = (fine.stress(point) - reference).norm() / norm;
171 if(!std::isfinite(error) || !std::isfinite(defaultError))
172 {
173 throw std::runtime_error("Nonfinite accuracy metric");
174 }
175 if(factor == 0)
176 {
177 errors.interiorMaximum = std::max(errors.interiorMaximum, error);
178 }
179 else
180 {
181 if(errors.loose.empty() ||
182 error > *std::max_element(errors.loose.begin(), errors.loose.end()))
183 {
184 errors.worstFactor = factor;
185 errors.worstNu = nu;
186 errors.worstMode = mode;
187 }
188 errors.loose.push_back(error);
189 errors.defaultMaximum = std::max(errors.defaultMaximum, defaultError);
190 }
191 if((lengths - V::Ones()).norm() == 0.0)
192 {
193 errors.sphereMaximum =
194 std::max(errors.sphereMaximum, (approx - sphere.stress(point)).norm() / norm);
195 }
196 }
197 }
198 }
199 }
200 std::sort(errors.loose.begin(), errors.loose.end());
201 std::cout << lengths.transpose() << ',' << errors.loose.size() << ',' << std::setprecision(12)
202 << errors.loose.back() << ','
203 << errors.loose[static_cast<std::size_t>(0.95 * (errors.loose.size() - 1))] << ','
204 << errors.defaultMaximum << ',' << errors.interiorMaximum << ',' << errors.sphereMaximum << ','
205 << errors.worstFactor << ',' << errors.worstNu << ',' << errors.worstMode << std::endl;
206 }
207}
std::chrono::steady_clock Clock
Eigen::Matrix3d M
model::EshelbyInclusionBase< 3 > Base
volatile double benchmarkSink
Eigen::Vector3d V
MatrixDim stress(const VectorDim &x) const override
double interiorMaximum
double defaultMaximum
double sphereMaximum
double worstNu
double worstFactor
std::vector< double > loose
const double nu
M sphere(const V &r, double a, const M &e, double n=nu, double m=mu)
double measure(const Base &inclusion, const std::vector< V > &points)
Q
int j
void argv
m samples
void b int argc
int k
int i