25bool near(
double a,
double b,
double tol = 1.e-12) {
26 return std::abs(a - b) <= tol * (1. + std::abs(a) + std::abs(b));
34 const double vol = 4.0;
35 const double Rc = 1.0;
40 if (!
near(full, vol) || !
near(mid, 0.5 * vol) || !
near(edge, 0.)) {
41 std::cerr <<
"correctedContactVolume failed: full=" << full
42 <<
" mid=" << mid <<
" edge=" << edge <<
"\n";
71 const auto fj = law_j->springForce(p);
72 if (!
near(fj.d_x, -150.)) {
73 std::cerr <<
"spring should equal Kn*(R-Rc)*Vj: fj.x=" << fj.d_x <<
"\n";
78 const auto nodal = p.voli * fj;
79 if (!
near(nodal.d_x, -300.)) {
80 std::cerr <<
"nodal force Vi*fj failed: " << nodal.d_x <<
"\n";
107 const auto fd = law_j->nodeDampingForce(
pd);
108 if (!(fd.length() > 0.)) {
109 std::cerr <<
"node damping should be nonzero for approaching pair\n";
114 std::cerr <<
"Damping_Law node flags incorrect\n";
144 for (
int k = 0; k < 20; ++k)
145 fss = ss->springForce(q);
148 const double fn = 100.0 * (1.0 - 0.5) * 1.0;
149 const double ft_max = 0.2 * fn;
150 const double ft = std::abs(fss.
d_y);
151 if (ft > ft_max + 1.e-9) {
152 std::cerr <<
"stick-slip exceeded Coulomb cap: ft=" << ft
153 <<
" ft_max=" << ft_max <<
"\n";
156 if (ft < 0.5 * ft_max) {
157 std::cerr <<
"stick-slip did not mobilize friction: ft=" << ft <<
"\n";
162 std::cout <<
"TestContact spring / stick_slip OK\n";
168 std::cerr <<
"off/node should not create COM damping\n";
173 std::cerr <<
"com/com_and_node should create COM damping\n";
181 std::cerr <<
"damping law flags incorrect\n";
186 std::cout <<
"TestContact damping laws OK\n";
194 const double volj = 1.0;
195 const double Kn = 10.0;
196 const double Rc = 1.0;
197 const double r0 = 0.5;
198 const auto f_bb = bb->force(yji, volj, Kn, Rc, r0);
199 const auto f_rg = rg->force(yji, volj, Kn, Rc, r0);
200 if (!
near(f_bb.d_x, -2.5)) {
201 std::cerr <<
"broken_bond_kn unexpected: " << f_bb.d_x <<
"\n";
204 if (!
near(f_rg.d_x, -1.0)) {
205 std::cerr <<
"reference_gap unexpected: " << f_rg.d_x <<
"\n";
209 const auto f_rg2 = rg->force(
util::Point(0.8, 0., 0.), volj, Kn, Rc, r0);
210 if (!
near(f_rg2.d_x, 0.) || !
near(f_rg2.length(), 0.)) {
211 std::cerr <<
"reference_gap should be zero when R > r0\n";
216 std::cout <<
"TestContact self-contact OK\n";
222 if (!meshed || meshed->skipsMeshedGrainWall() || !anal ||
223 !anal->skipsMeshedGrainWall()) {
224 std::cerr <<
"Wall_Contact factory flags incorrect\n";
232 std::cerr <<
"Plane wallContactQuery free-space failed\n";
237 std::cerr <<
"Plane wallContactQuery penetration failed\n";
244 std::cerr <<
"Rectangle wallContactQuery failed: gap=" << hit.
signed_gap
250 const double Kn = 100., Rc = 1., vol = 2.;
253 auto scalar = Kn * (gap - Rc) * vol;
258 std::cerr <<
"analytical wall force failed: f=(" << f.
d_x <<
","
264 std::cout <<
"TestContact wall contact OK\n";
289 const auto f_cs = cs->springForce(q);
292 for (
int k = 0; k < 5; ++k)
293 f_ss = ss->springForce(q);
296 if (
near(f_cs.d_y, f_ss.
d_y, 1.e-6) &&
near(f_cs.d_x, f_ss.
d_x, 1.e-6)) {
297 std::cerr <<
"coulomb_simple and stick_slip should differ in Ft\n";
302 std::cout <<
"TestContact friction laws differ OK\n";
Infinite plane: free space is the half-space in the normal direction.
bool wallContactQuery(const util::Point &x, WallContactHit &hit) const override
Closest-point / signed-gap query for analytical wall contact. Default: unsupported (returns false,...
bool wallContactQuery(const util::Point &x, WallContactHit &hit) const override
bool near(double a, double b, double tol=1.e-12)
std::unique_ptr< SelfContact > makeSelfContact(const std::string &name)
Build self-contact law named by Model.Self_Contact.
A structure to represent 3d vectors.
double d_y
the y coordinate
double d_x
the x coordinate