int main(int argc, char* argv[]) { // Create output directories. if (ChFileutils::MakeDirectory(out_dir.c_str()) < 0) { cout << "Error creating directory " << out_dir << endl; return 1; } if (ChFileutils::MakeDirectory(pov_dir.c_str()) < 0) { cout << "Error creating directory " << pov_dir << endl; return 1; } // ------------- // Create system // ------------- #ifdef USE_DEM cout << "Create DEM system" << endl; ChSystemParallelDEM* msystem = new ChSystemParallelDEM(); #else cout << "Create DVI system" << endl; ChSystemParallelDVI* msystem = new ChSystemParallelDVI(); #endif msystem->Set_G_acc(ChVector<>(0, 0, -gravity)); // Set number of threads. int max_threads = omp_get_num_procs(); if (threads > max_threads) threads = max_threads; msystem->SetParallelThreadNumber(threads); omp_set_num_threads(threads); cout << "Using " << threads << " threads" << endl; msystem->GetSettings()->max_threads = threads; msystem->GetSettings()->perform_thread_tuning = thread_tuning; // Edit system settings msystem->GetSettings()->solver.use_full_inertia_tensor = false; msystem->GetSettings()->solver.tolerance = tolerance; msystem->GetSettings()->solver.max_iteration_bilateral = max_iteration_bilateral; msystem->GetSettings()->solver.clamp_bilaterals = clamp_bilaterals; msystem->GetSettings()->solver.bilateral_clamp_speed = bilateral_clamp_speed; #ifdef USE_DEM msystem->GetSettings()->collision.narrowphase_algorithm = NARROWPHASE_R; msystem->GetSettings()->solver.contact_force_model = contact_force_model; msystem->GetSettings()->solver.tangential_displ_mode = tangential_displ_mode; #else msystem->GetSettings()->solver.solver_mode = SLIDING; msystem->GetSettings()->solver.max_iteration_normal = max_iteration_normal; msystem->GetSettings()->solver.max_iteration_sliding = max_iteration_sliding; msystem->GetSettings()->solver.max_iteration_spinning = max_iteration_spinning; msystem->GetSettings()->solver.alpha = 0; msystem->GetSettings()->solver.contact_recovery_speed = contact_recovery_speed; msystem->SetMaxPenetrationRecoverySpeed(contact_recovery_speed); msystem->ChangeSolverType(APGDREF); msystem->GetSettings()->collision.collision_envelope = 0.05 * r_g; #endif msystem->GetSettings()->collision.bins_per_axis = I3(10, 10, 10); // -------------- // Problem set up // -------------- // Depending on problem type: // - Select end simulation time // - Select output FPS // - Create / load objects double time_min = 0; double time_end; int out_fps; ChSharedPtr<ChBody> ground; ChSharedPtr<ChBody> loadPlate; ChSharedPtr<ChLinkLockPrismatic> prismatic; ChSharedPtr<ChLinkLinActuator> actuator; switch (problem) { case SETTLING: { time_min = time_settling_min; time_end = time_settling_max; out_fps = out_fps_settling; // Create the mechanism bodies (all fixed). CreateMechanismBodies(msystem); // Grab handles to mechanism bodies (must increase ref counts) ground = ChSharedPtr<ChBody>(msystem->Get_bodylist()->at(0)); loadPlate = ChSharedPtr<ChBody>(msystem->Get_bodylist()->at(1)); msystem->Get_bodylist()->at(0)->AddRef(); msystem->Get_bodylist()->at(1)->AddRef(); // Create granular material. int num_particles = CreateGranularMaterial(msystem); cout << "Granular material: " << num_particles << " particles" << endl; break; } case PRESSING: { time_min = time_pressing_min; time_end = time_pressing_max; out_fps = out_fps_pressing; // Create bodies from checkpoint file. cout << "Read checkpoint data from " << settled_ckpnt_file; utils::ReadCheckpoint(msystem, settled_ckpnt_file); cout << " done. Read " << msystem->Get_bodylist()->size() << " bodies." << endl; // Grab handles to mechanism bodies (must increase ref counts) ground = ChSharedPtr<ChBody>(msystem->Get_bodylist()->at(0)); loadPlate = ChSharedPtr<ChBody>(msystem->Get_bodylist()->at(1)); msystem->Get_bodylist()->at(0)->AddRef(); msystem->Get_bodylist()->at(1)->AddRef(); // Move the load plate just above the granular material. double highest, lowest; FindHeightRange(msystem, lowest, highest); ChVector<> pos = loadPlate->GetPos(); double z_new = highest + 1.01 * r_g; loadPlate->SetPos(ChVector<>(pos.x, pos.y, z_new)); // Add collision geometry to plate loadPlate->GetCollisionModel()->ClearModel(); utils::AddBoxGeometry(loadPlate.get_ptr(), ChVector<>(hdimX_p, hdimY_p, hdimZ_p), ChVector<>(0, 0, hdimZ_p)); loadPlate->GetCollisionModel()->BuildModel(); // If using an actuator, connect the load plate and get a handle to the actuator. if (use_actuator) { ConnectLoadPlate(msystem, ground, loadPlate); prismatic = msystem->SearchLink("prismatic").StaticCastTo<ChLinkLockPrismatic>(); actuator = msystem->SearchLink("actuator").StaticCastTo<ChLinkLinActuator>(); } // Release the load plate. loadPlate->SetBodyFixed(!use_actuator); break; } case TESTING: { time_end = time_testing; out_fps = out_fps_testing; // For TESTING only, increse shearing velocity. desiredVelocity = 0.5; // Create the mechanism bodies (all fixed). CreateMechanismBodies(msystem); // Create the test ball. CreateBall(msystem); // Grab handles to mechanism bodies (must increase ref counts) ground = ChSharedPtr<ChBody>(msystem->Get_bodylist()->at(0)); loadPlate = ChSharedPtr<ChBody>(msystem->Get_bodylist()->at(1)); msystem->Get_bodylist()->at(0)->AddRef(); msystem->Get_bodylist()->at(1)->AddRef(); // Move the load plate just above the test ball. ChVector<> pos = loadPlate->GetPos(); double z_new = 2.1 * radius_ball; loadPlate->SetPos(ChVector<>(pos.x, pos.y, z_new)); // Add collision geometry to plate loadPlate->GetCollisionModel()->ClearModel(); utils::AddBoxGeometry(loadPlate.get_ptr(), ChVector<>(hdimX_p, hdimY_p, hdimZ_p), ChVector<>(0, 0, hdimZ_p)); loadPlate->GetCollisionModel()->BuildModel(); // If using an actuator, connect the shear box and get a handle to the actuator. if (use_actuator) { ConnectLoadPlate(msystem, ground, loadPlate); actuator = msystem->SearchLink("actuator").StaticCastTo<ChLinkLinActuator>(); } // Release the shear box when using an actuator. loadPlate->SetBodyFixed(!use_actuator); break; } } // ---------------------- // Perform the simulation // ---------------------- // Set number of simulation steps and steps between successive output int num_steps = (int)std::ceil(time_end / time_step); int out_steps = (int)std::ceil((1.0 / time_step) / out_fps); int write_steps = (int)std::ceil((1.0 / time_step) / write_fps); // Initialize counters double time = 0; int sim_frame = 0; int out_frame = 0; int next_out_frame = 0; double exec_time = 0; int num_contacts = 0; double max_cnstr_viol[2] = {0, 0}; // Circular buffer with highest particle location // (only used for SETTLING or PRESSING) int buffer_size = std::ceil(time_min / time_step); std::valarray<double> hdata(0.0, buffer_size); // Create output files ChStreamOutAsciiFile statsStream(stats_file.c_str()); ChStreamOutAsciiFile sinkageStream(sinkage_file.c_str()); sinkageStream.SetNumFormat("%16.4e"); #ifdef CHRONO_PARALLEL_HAS_OPENGL opengl::ChOpenGLWindow& gl_window = opengl::ChOpenGLWindow::getInstance(); gl_window.Initialize(1280, 720, "Pressure Sinkage Test", msystem); gl_window.SetCamera(ChVector<>(0, -10 * hdimY, hdimZ), ChVector<>(0, 0, hdimZ), ChVector<>(0, 0, 1)); gl_window.SetRenderMode(opengl::WIREFRAME); #endif // Loop until reaching the end time... while (time < time_end) { // Current position and velocity of the shear box ChVector<> pos_old = loadPlate->GetPos(); ChVector<> vel_old = loadPlate->GetPos_dt(); // Calculate minimum and maximum particle heights double highest, lowest; FindHeightRange(msystem, lowest, highest); // If at an output frame, write PovRay file and print info if (sim_frame == next_out_frame) { cout << "------------ Output frame: " << out_frame + 1 << endl; cout << " Sim frame: " << sim_frame << endl; cout << " Time: " << time << endl; cout << " Load plate pos: " << pos_old.z << endl; cout << " Lowest point: " << lowest << endl; cout << " Highest point: " << highest << endl; cout << " Execution time: " << exec_time << endl; // Save PovRay post-processing data. if (write_povray_data) { char filename[100]; sprintf(filename, "%s/data_%03d.dat", pov_dir.c_str(), out_frame + 1); utils::WriteShapesPovray(msystem, filename, false); } // Create a checkpoint from the current state. if (problem == SETTLING || problem == PRESSING) { cout << " Write checkpoint data " << flush; if (problem == SETTLING) utils::WriteCheckpoint(msystem, settled_ckpnt_file); else utils::WriteCheckpoint(msystem, pressed_ckpnt_file); cout << msystem->Get_bodylist()->size() << " bodies" << endl; } // Increment counters out_frame++; next_out_frame += out_steps; } // Check for early termination of a settling phase. if (problem == SETTLING) { // Store maximum particle height in circular buffer hdata[sim_frame % buffer_size] = highest; // Check variance of data in circular buffer if (time > time_min) { double mean_height = hdata.sum() / buffer_size; std::valarray<double> x = hdata - mean_height; double var = std::sqrt((x * x).sum() / buffer_size); // Consider the material settled when the variance is below the // specified fraction of a particle radius if (var < settling_tol * r_g) { cout << "Granular material settled... time = " << time << endl; break; } } } // Advance simulation by one step #ifdef CHRONO_PARALLEL_HAS_OPENGL if (gl_window.Active()) { gl_window.DoStepDynamics(time_step); gl_window.Render(); } else break; #else msystem->DoStepDynamics(time_step); #endif TimingOutput(msystem); // Record stats about the simulation if (sim_frame % write_steps == 0) { // write stat info int numIters = msystem->data_manager->measures.solver.maxd_hist.size(); double residual = 0; if (numIters) residual = msystem->data_manager->measures.solver.residual; statsStream << time << ", " << exec_time << ", " << num_contacts / write_steps << ", " << numIters << ", " << residual << ", " << max_cnstr_viol[0] << ", " << max_cnstr_viol[1] << ", \n"; statsStream.GetFstream().flush(); num_contacts = 0; max_cnstr_viol[0] = 0; max_cnstr_viol[1] = 0; } if (problem == PRESSING || problem == TESTING) { // Get the current reaction force or impose load plate position double cnstr_force = 0; if (use_actuator) { cnstr_force = actuator->Get_react_force().x; } else { double zpos_new = pos_old.z + desiredVelocity * time_step; loadPlate->SetPos(ChVector<>(pos_old.x, pos_old.y, zpos_new)); loadPlate->SetPos_dt(ChVector<>(0, 0, desiredVelocity)); } if (sim_frame % write_steps == 0) { // std::cout << time << ", " << loadPlate->GetPos().z << ", " << cnstr_force << ", \n"; sinkageStream << time << ", " << loadPlate->GetPos().z << ", " << cnstr_force << ", \n"; sinkageStream.GetFstream().flush(); } } // Find maximum constraint violation if (!prismatic.IsNull()) { ChMatrix<>* C = prismatic->GetC(); for (int i = 0; i < 5; i++) max_cnstr_viol[0] = std::max(max_cnstr_viol[0], std::abs(C->GetElement(i, 0))); } if (!actuator.IsNull()) { ChMatrix<>* C = actuator->GetC(); max_cnstr_viol[1] = std::max(max_cnstr_viol[2], std::abs(C->GetElement(0, 0))); } // Increment counters time += time_step; sim_frame++; exec_time += msystem->GetTimerStep(); num_contacts += msystem->GetNcontacts(); // If requested, output detailed timing information for this step if (sim_frame == timing_frame) msystem->PrintStepStats(); } // ---------------- // Final processing // ---------------- // Create a checkpoint from the last state if (problem == SETTLING || problem == PRESSING) { cout << " Write checkpoint data " << flush; if (problem == SETTLING) utils::WriteCheckpoint(msystem, settled_ckpnt_file); else utils::WriteCheckpoint(msystem, pressed_ckpnt_file); cout << msystem->Get_bodylist()->size() << " bodies" << endl; } // Final stats cout << "==================================" << endl; cout << "Number of bodies: " << msystem->Get_bodylist()->size() << endl; cout << "Simulation time: " << exec_time << endl; cout << "Number of threads: " << threads << endl; return 0; }