// This code creates a structured mesh for a 3D geometry of a mechanical part (a small and a bigger cylinder connected together).
//
// It is structured as follows:
//
// 1. The 2D projected surface of the geometry is created
// 2. The projection is extruded
// 3. A deformation function is applied to the big cylinder to get the final geometry.
// 4. A mechanical simulation is performed on the geometry
//
// In order to identify the regions needed in the simulation the following physical region numbers are used:
//
// --> 1 for the whole volume
// --> 2 for the bottom surface of the small cylinder (mechanical clamp)
// --> 3 for the surface inside the big cylinder
// 
// Region number -1 is used for all construction geometries (not used in the simulation).


#include "sparselizardbase.h"


using namespace mathop;

void sparselizard(void)
{	
    // The physical region numbers as detailed above:
    int vol = 1, clamp = 2, faceincylinder = 3;
    
    // Define the x, y and z coordinate fields:
    field x("x"), y("y"), z("z");
    
    // Define pi:
    double pi = getpi();
    
    
    ///// CONSTRUCTION OF THE SMALL CYLINDER with inner and outer radius 7mm and 15mm:
    
    double smallinnerradius = 0.007, smallouterradius = 0.015;
    
    // Define the points to construct the cylinder.
    // Inputs are the x, y and z point coordinates.
    shape p1("point", -1, {0,0,0});
    shape p2("point", -1, {smallinnerradius*cos(45*2*pi/360), smallinnerradius*sin(45*2*pi/360), 0});
    shape p3("point", -1, {smallinnerradius*cos(-45*2*pi/360),smallinnerradius*sin(-45*2*pi/360),0});
    shape p4("point", -1, {smallouterradius*cos(45*2*pi/360), smallouterradius*sin(45*2*pi/360), 0});
    shape p5("point", -1, {smallouterradius*cos(-45*2*pi/360),smallouterradius*sin(-45*2*pi/360),0});
    
    // Define the arcs and the lines to construct the small cylinder.
    // Inputs are the first point, last point and arc center point 
    // as well as the number of mesh nodes in the arc.
    shape a1("arc", -1, {p2,p3,p1}, 16);
    shape a2("arc", -1, {p4,p5,p1}, 16);
    shape a3("arc", -1, {p3,p2,p1}, 8);
    shape a4("arc", -1, {p5,p4,p1}, 8);
    
    shape l1("line", -1, {p2,p4}, 3);
    shape l2("line", -1, {p3,p5}, 3);
    
    // Define the 2 quadrangle surfaces for the small cylinder.
    // Inputs are the contour lines (following the contour clockwise or counter-clockwise).
    shape q1("quadrangle", -1, {a1,l1,a2,l2});
    shape q2("quadrangle", -1, {a3,l2,a4,l1});
    
    
    ///// CONSTRUCTION OF THE BIG CYLINDER with inner and outer radius 10mm and 30mm
    // around center point on x axis at x equal 100mm.
    
    double biginnerradius = 0.01, bigouterradius = 0.03;
    
    // Define the points to construct the cylinder.
    shape p6("point", -1, {0.1,0,0});
    shape p7("point", -1, {0.1-biginnerradius*cos(45*2*pi/360), biginnerradius*sin(45*2*pi/360), 0});
    shape p8("point", -1, {0.1-biginnerradius*cos(-45*2*pi/360),biginnerradius*sin(-45*2*pi/360),0});
    shape p9("point", -1, {0.1-bigouterradius*cos(45*2*pi/360), bigouterradius*sin(45*2*pi/360), 0});
    shape p10("point", -1, {0.1-bigouterradius*cos(-45*2*pi/360),bigouterradius*sin(-45*2*pi/360),0});
    
    // Define the arcs and the lines to construct the big cylinder.
    shape a5("arc", -1, {p7,p8,p6}, 8);
    shape a6("arc", -1, {p9,p10,p6}, 8);
    shape a7("arc", -1, {p8,p7,p6}, 16);
    shape a8("arc", -1, {p10,p9,p6}, 16);
    
    shape l3("line", -1, {p7,p9}, 5);
    shape l4("line", -1, {p8,p10}, 5);
    
    // Define the 2 quadrangle surfaces for the big cylinder.
    shape q3("quadrangle", -1, {a5,l3,a6,l4});
    shape q4("quadrangle", -1, {a7,l4,a8,l3});
    
    
    ///// CONSTRUCTION OF THE SURFACE BETWEEN THE TWO CYLINDERS
    
    // Define the lines linking the 2 cylinders:
    shape l5("line", -1, {p4,p9}, 12);
    shape l6("line", -1, {p5,p10}, 12);
    
    // Define the surface between the cylinders:
    shape q5("quadrangle", -1, {a4,l6,a6,l5});
    
    
    ///// EXTRUDE THE TOP AND BOTTOM CYLINDERS AROUND THE CENTRAL PART OF THE SMALL CYLINDER:
    // Extrude arguments are the physical region of the extruded volume, 
    // the extrusion height and the numbers of node layers in the extrusion.
    
    // The central part in the small cylinder is 10mm thick and the two above and below 5mm.
    double centralthickness = 0.01, thicknessaboveandbelow = 0.005;
    
    // Create the bottom volume part:
    shape v1 = q1.extrude(vol, -thicknessaboveandbelow, 3);
    shape v2 = q2.extrude(vol, -thicknessaboveandbelow, 3);
    
    // Create the central part:
    shape v3 = q1.extrude(vol, centralthickness, 6);
    shape v4 = q2.extrude(vol, centralthickness, 6);
    
    // Create the top volume part.
    // Extrude it from the top face of v3 and v4.
    shape v3topface = v3.getsons()[5];
    shape v4topface = v4.getsons()[5];
    
    shape v5 = v3topface.extrude(vol, thicknessaboveandbelow, 3);
    shape v6 = v4topface.extrude(vol, thicknessaboveandbelow, 3);
    
    
    ///// EXTRUDE THE BIG CYLINDER:
    
    shape v7 = q3.extrude(vol, centralthickness, 6);
    shape v8 = q4.extrude(vol, centralthickness, 6);
    
    
    ///// EXTRUDE THE SURFACE BETWEEN THE 2 CYLINDERS:
    
    shape v9 = q5.extrude(vol, centralthickness, 6);
    
    
    ///// DEFORM THE BIG CYLINDER ABOVE AND BELOW:
    
    v7.deform(0,0, 100*(bigouterradius-sqrt((x-0.1)*(x-0.1)+y*y))*(z-centralthickness/2));
    v8.deform(0,0, 100*(bigouterradius-sqrt((x-0.1)*(x-0.1)+y*y))*(z-centralthickness/2));
    
    
    ///// GET THE BOTTOM SURFACE OF THE SMALL CYLINDER AND ASSIGN PHYSICAL REGION NUMBER 2
    ///// GET THE SURFACE INSIDE THE BIG CYLINDER AND ASSIGN PHYSICAL REGION NUMBER 3
    
    // You can .write the mesh at any time during the geometry construction 
    // phase (see below) to easily know which son you are looking for.
    shape clampface1 = v1.getsons()[5];
    shape clampface2 = v2.getsons()[5];
    
    clampface1.setphysicalregion(clamp);
    clampface2.setphysicalregion(clamp);
    
    shape faceincylinder1 = v7.getsons()[1];
    shape faceincylinder2 = v8.getsons()[1];
    
    faceincylinder1.setphysicalregion(faceincylinder);
    faceincylinder2.setphysicalregion(faceincylinder);
    
    
    ///// LOAD THE MESH
    
    // Add here all regions needed in the finite element simulation.
    mesh mymesh({v1,v2,v3,v4,v5,v6,v7,v8,v9, clampface1,clampface2, faceincylinder1,faceincylinder2});
    
    // You can write the mesh at any time during the geometry 
    // construction to easily debug and validate every line of code.
    mymesh.write("mymesh.msh");
    
    
    ///// START THE MECHANICAL SIMULATION
    
    // Nodal shape functions 'h1' with 3 components.
    // Field u is the mechanical displacement.
    field u("h1xyz");
    
    // Use interpolation order 2 on 'vol', the whole domain:
    u.setorder(vol, 2);
    
    // Clamp on surface 'clamp' (i.e. 0 valued-Dirichlet conditions):
    u.setconstraint(clamp);
    
    // E is Young's modulus. nu is Poisson's ratio. 
    double E = 200e9, nu = 0.3;
    
    formulation elasticity;
    
    // The linear elasticity formulation is classical and thus predefined:
    elasticity += integral(vol, predefinedelasticity(dof(u), tf(u), E, nu));
    // Add a surface force (to the inside of the big cylinder) to tilt the structure around the x axis:
    elasticity += integral(faceincylinder, array1x3(0,10*(z-centralthickness/2),0)*tf(u));
    
    elasticity.generate();
    
    vec solu = solve(elasticity.A(), elasticity.b());
    
    // Transfer the data from the solution vector to the u field:
    u.setdata(vol, solu);
    // Write the deflection with an order 2 interpolation. Exaggerate the deflection by a large factor.
    (0.3e10*u).write(vol, "u.pos", 2);

    // Code validation line. Can be removed.
    std::cout << (abs(compz(u)).max(vol, 2)[0] < 4.24272e-12 && abs(compz(u)).max(vol, 2)[0] > 4.2427e-12);
}

int main(void)
{	
    SlepcInitialize(0,{},0,0);

    sparselizard();

    SlepcFinalize();

    return 0;
}

