#include #include #include #include /// Classical 3D Point contact problem. /// http://e6.ijs.si/medusa/wiki/index.php/Linear_elasticity#Point_contact_3D using namespace mm; // NOLINT int main() { XML conf("point_contact3d.xml"); // Physical parameters const double E = conf.get("phy.E"); const double nu = conf.get("phy.nu"); const double P = -conf.get("phy.P"); // Derived parameters double lam = E * nu / (1 - 2 * nu) / (1 + nu); const double mu = E / 2 / (1 + nu); // Closed form solution std::function analytical = [=](const Vec3d& p) { double x = p[0], y = p[1], z = p[2]; double r = std::sqrt(x*x+y*y); double c = x/r, s = y/r; double R = p.norm(); double u = P*r/4/PI/mu * (z/R/R/R - (1-2*nu) / (R*(R+z))); double w = P/4/PI/mu * (z*z/R/R/R + 2*(1-nu)/R); return Vec3d(u*c, u*s, w); }; // Domain definition double a = conf.get("num.a"); double b = conf.get("num.b"); Vec3d low = -a, high = -b; BoxShape box(low, high); double step = conf.get("num.h"); std::function density = [=] (const Vec3d& v) { double r = (v-low).head<2>().norm() / (high-low).head<2>().norm(); return step*(9*(1-r)+1); }; GeneralFill fill; fill.seed(0); DomainDiscretization domain = box.discretizeWithDensity(density, fill); int N = domain.size(); prn(N); domain.findSupport(FindClosest(15)); // the support for each node is the closest 9 nodes // Construct the approximation engine, in this case a weighted least squares using monomials as // basis functions, no weight, and scale to farthest. WLS, GaussianWeight, ScaleToFarthest> wls({15, 100.0}, 1.0); // Compute the shapes using the defined approximation engine auto shapes = domain.computeShapes(wls); std::cerr << "Shapes computed, solving system." << std::endl; Eigen::SparseMatrix M(3*N, 3*N); Eigen::VectorXd rhs(3*N); rhs.setZero(); M.reserve(shapes.supportSizesVec()); // Construct implicit operators over our storage. auto op = shapes.implicitVectorOperators(M, rhs); // Set the governing equations and the boundary conditions. for (int i : domain.interior()) { (lam+mu)*op.graddiv(i) + mu*op.lap(i) = 0.0; } for (int i : domain.boundary()) { op.value(i) = analytical(domain.pos(i)); } Eigen::BiCGSTAB> solver; solver.preconditioner().setFillfactor(20); solver.preconditioner().setDroptol(1e-4); solver.setMaxIterations(100); solver.setTolerance(1e-14); solver.compute(M); Eigen::VectorXd solution = solver.solve(rhs); prn(solver.iterations()); prn(solver.error()); VectorField3d u = VectorField3d::fromLinear(solution); auto eop = shapes.explicitVectorOperators(); VectorField stress(N); for (int i = 0; i < N; ++i) { Eigen::Matrix3d grad = eop.grad(u, i); Eigen::Matrix3d eps = 0.5*(grad + grad.transpose()); Eigen::Matrix3d s = lam * eps.trace() * Eigen::Matrix3d::Identity(3, 3) + 2*mu*eps; stress[i][0] = s(0, 0); stress[i][1] = s(1, 1); stress[i][2] = s(2, 2); stress[i][3] = s(0, 1); stress[i][4] = s(0, 2); stress[i][5] = s(1, 2); } // Write the solution into a file. std::ofstream out_file("point_contact3d_data.m"); out_file << "E = " << E << ";\n"; out_file << "nu = " << nu << ";\n"; out_file << "P = " << P << ";\n"; out_file << "positions = " << domain.positions() << ";\n"; out_file << "displacement = " << u << ";" << ";\n"; out_file << "stress = " << stress << ";" << std::endl; out_file.close(); return 0; }