--
You received this message because you are subscribed to the Google Groups
"ProjectChrono" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/projectchrono/b8081c94-53f0-467d-a57a-14cbf98766e4n%40googlegroups.com.
#include <cmath>
#include <iomanip>
#include <iostream>
#include <string>
#include "chrono/core/ChGlobal.h"
#include "chrono/physics/ChBody.h"
#include "chrono/physics/ChSystemSMC.h"
#include "chrono/utils/ChUtilsSamplers.h"
#include "chrono_gpu/physics/ChSystemGpu.h"
#include "chrono_gpu/utils/ChGpuJsonParser.h"
#include "chrono_gpu/ChGpuData.h"
// added for motor:
#include "chrono/motion_functions/ChFunction.h"
#include "chrono/physics/ChForce.h"
#include "chrono/timestepper/ChTimestepper.h"
#include "chrono/utils/ChUtilsCreators.h"
#include "chrono/physics/ChLinkMotorLinearForce.h"
#include "chrono/physics/ChLinkMotorLinearPosition.h"
#include "chrono/physics/ChLinkMotorLinearSpeed.h"
#include "chrono/physics/ChLinkMotorRotationAngle.h"
#include "chrono/physics/ChLinkMotorRotationSpeed.h"
#include "chrono/physics/ChLinkMotorRotationTorque.h"
#include "chrono_gpu/ChGpuData.h"
#include "chrono_thirdparty/filesystem/path.h"
#include "chrono/assets/ChBoxShape.h"
using namespace chrono;
using namespace chrono::gpu;
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// Simulation parameters (same as those in the json file)
double step_size = 5e-7; // time step s
double sphere_radius = 0.2; // cm sphere radius (6 mm glass beads same as
experiments )
double sphere_density = 0.92; // g/cm^3 density of sphere particle
double time_settle =0.75;// time needed for bed to settle
double time_end = .01;// time needed for the drop phase
double compress_end = .95; // compressing the bed
double decompress_end = 1.05; // bed decompression
// Define Big domain size
double box_X = 60;
double box_Y = 60;
double box_Z = 200;
//int run_mode_id = 0;//settling phase
int run_mode_id = 1;//drop phase
// int run_mode_id = 2; // pull phase
int helix_angle = 20;
std::string planet = "_Earth_CubeSim";
double youngs_modulus1 = 1e10;
// Gravity
double grav_X = 0.0f;
double grav_Y = 0.0f;
double grav_Z = -981.0f;
// Cube mass
float cube_mass = 600; //g value from Solidworks 20helix Angle.
///////////////////////////////////////////////////////////////////////////////////////////////////////
// ONLY for a Square/Rectangular shaped bed (If Cylindar need to be changed)
double getVoidRatio( ChSystemGpuMesh& gpu_sys, double sphere_radius){
double vol_sphere = 4.0f/3.0f * chrono::CH_C_PI * std::pow(sphere_radius,
3) * gpu_sys.GetNumParticles () ;
double vol_box = (box_X*box_Y)* (gpu_sys.GetMaxParticleZ () -
gpu_sys.GetMinParticleZ ());
double eta = vol_sphere/vol_box;
double voidRatio = (1.0f - eta)/eta;
return voidRatio;
}
/////////////////////////////////////////////////////////////////////////////////////////////
double CalcKE(ChSystemGpuMesh& gpu_sys, double sphere_radius, double
sphere_density){
double vol_sphere = 4.0f/3.0f * chrono::CH_C_PI *
std::pow(sphere_radius, 3);
double mass_sphere = vol_sphere * sphere_density;
double inertia_sphere = 0.4f * mass_sphere * sphere_radius *
sphere_radius;
ChVector<float> ang_velo;
ChVector<float> lin_velo;
double KE = 0;
double nb = gpu_sys.GetNumParticles();
for(int i = 0; i < nb; i++){
lin_velo = gpu_sys.GetParticleVelocity(i);
ang_velo = gpu_sys.GetParticleAngVelocity(i);
KE = 0.5f * mass_sphere * lin_velo.Length2() + 0.5f *
inertia_sphere * ang_velo.Length2();
}
return KE;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
void write_csv(std::string filename, std::vector<std::pair<std::string,
std::vector<float>>> dataset){
// Make a CSV file with one or more columns of integer values
// Each column of data is represented by the pair <column name, column data>
// as std::pair<std::string, std::vector<int>>
// The dataset is represented as a vector of these columns
// Note that all columns should be the same size
// Create an output filestream object
std::ofstream myFile(filename);
// Send column names to the stream
for(int j = 0; j < dataset.size(); ++j)
{
myFile << dataset.at(j).first;
if(j != dataset.size() - 1) myFile << ","; // No comma at end of line
}
myFile << "\n";
// Send data to the stream
for(int i = 0; i < dataset.at(0).second.size(); ++i)
{
for(int j = 0; j < dataset.size(); ++j)
{
myFile << dataset.at(j).second.at(i);
if(j != dataset.size() - 1) myFile << ","; // No comma at end of
line
}
myFile << "\n";
}
// Close the file
myFile.close();
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Set up GPU system -bed Particles
void SetupGPUSystem(ChSystemGpuMesh& gpu_sys) {
double cor_p = 0.36; // sphere restitution
double cor_w = 0.36; // mesh & wall restitution (value from Thoesen et
al., 2019)
double cor_m = 0.8; // mesh restitution
double youngs_modulus_p = 1e10; //(cms^2)
double youngs_modulus_m = 7.2e11;
double youngs_modulus_w = 1e10;
double poisson_ratio_m = 0.33;
double poisson_ratio_p = 0.32;
double poisson_ratio_w = 0.32;
double mu_s2s = 0.5; // 0.5 static friction coefficient sphere to sphere
double mu_s2w = 0.5; //0.5 static friction coefficient sphere to wall &
mesh (value from Thoesen et al., 2019)
double mu_s2m = 0.04;
float roll_s2s = 1; //1
float roll_s2w = 1;
float roll_s2m = 0.1;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
gpu_sys.UseMaterialBasedModel(true); // use material based model (Young's
modulus, restitution, Poisson's ratio)
gpu_sys.SetYoungModulus_SPH(youngs_modulus_p);
gpu_sys.SetYoungModulus_WALL(youngs_modulus_w);
gpu_sys.SetYoungModulus_MESH(youngs_modulus_m);
gpu_sys.SetRestitution_SPH(cor_p);
gpu_sys.SetRestitution_WALL(cor_w);
gpu_sys.SetRestitution_MESH(cor_m);
gpu_sys.SetPoissonRatio_SPH(poisson_ratio_p);
gpu_sys.SetPoissonRatio_WALL(poisson_ratio_w);
gpu_sys.SetPoissonRatio_MESH(poisson_ratio_m);
gpu_sys.SetFrictionMode(chrono::gpu::CHGPU_FRICTION_MODE::MULTI_STEP);
gpu_sys.SetStaticFrictionCoeff_SPH2SPH(mu_s2s);
gpu_sys.SetStaticFrictionCoeff_SPH2WALL(mu_s2w);
gpu_sys.SetStaticFrictionCoeff_SPH2MESH(mu_s2m);
gpu_sys.SetRollingMode(CHGPU_ROLLING_MODE::SCHWARTZ);
gpu_sys.SetRollingCoeff_SPH2SPH(roll_s2s);
gpu_sys.SetRollingCoeff_SPH2WALL(roll_s2w);
gpu_sys.SetRollingCoeff_SPH2MESH(roll_s2m);
gpu_sys.SetParticleOutputMode(CHGPU_OUTPUT_MODE::CSV);
gpu_sys.SetTimeIntegrator(CHGPU_TIME_INTEGRATOR::CENTERED_DIFFERENCE);
gpu_sys.SetFixedStepSize(step_size);
gpu_sys.SetBDFixed(true);
/////////////////////////////////////////////////////////////////////////////////////////////
// Rain particles
double fill_top;
double fill_bottom = -99.0f;
double box_xy = 58; // 56 cm by 56 cm box
double box_r = box_xy / 2;
double spacing = 2.001 * sphere_radius;
std::vector<ChVector<float>> body_points;
utils::PDSampler<float> sampler(spacing);
fill_top = -80; // bring it back to -60 later
//fill_top = box_Z / 2 - spacing;
ChVector<> hdims(box_r - sphere_radius, box_r - sphere_radius, 0);
int counter = 0;
for (double z = fill_bottom + spacing; z < fill_top; z += spacing) {
ChVector<> center(0, 0, z);
auto points = sampler.SampleBox(center, hdims);
body_points.insert(body_points.end(), points.begin(), points.end());
counter = counter + points.size();
}
std::cout << "Created " << body_points.size() << "spheres" << std::endl;
gpu_sys.SetParticles(body_points);
gpu_sys.SetGravitationalAcceleration(ChVector<float>(grav_X, grav_Y,
grav_Z));
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
void SetupGPUParams(ChSystemGpuMesh& gpu_sys) {
double cor_p = 0.36; // sphere restitution
double cor_w = 0.36; // mesh & wall restitution (value from Thoesen et
al., 2019)
double cor_m = 0.8; // mesh restitution
double youngs_modulus_p = 1e10; // 40Mpa = 4e7Pa = 4e8 g/(cms^2)
double youngs_modulus_m = 7.2e11;
double youngs_modulus_w = 1e10;
double poisson_ratio_m = 0.33;
double poisson_ratio_p = 0.32;
double poisson_ratio_w = 0.32;
double mu_s2s = 0.5; // 0.5 static friction coefficient sphere to sphere
double mu_s2w = 0.5; //0.5 static friction coefficient sphere to wall &
mesh (value from Thoesen et al., 2019)
double mu_s2m = 0.04;
float roll_s2s = 1; //1
float roll_s2w = 1;
float roll_s2m = 0.1;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
gpu_sys.UseMaterialBasedModel(true); // use material based model (Young's
modulus, restitution, Poisson's ratio)
gpu_sys.SetYoungModulus_SPH(youngs_modulus_p);
gpu_sys.SetYoungModulus_WALL(youngs_modulus_w);
gpu_sys.SetYoungModulus_MESH(youngs_modulus_m);
gpu_sys.SetRestitution_SPH(cor_p);
gpu_sys.SetRestitution_WALL(cor_w);
gpu_sys.SetRestitution_MESH(cor_m);
gpu_sys.SetPoissonRatio_SPH(poisson_ratio_p);
gpu_sys.SetPoissonRatio_WALL(poisson_ratio_w);
gpu_sys.SetPoissonRatio_MESH(poisson_ratio_m);
gpu_sys.SetFrictionMode(chrono::gpu::CHGPU_FRICTION_MODE::MULTI_STEP);
gpu_sys.SetStaticFrictionCoeff_SPH2SPH(mu_s2s);
gpu_sys.SetStaticFrictionCoeff_SPH2WALL(mu_s2w);
gpu_sys.SetStaticFrictionCoeff_SPH2MESH(mu_s2m);
gpu_sys.SetRollingMode(CHGPU_ROLLING_MODE::SCHWARTZ);
gpu_sys.SetRollingCoeff_SPH2SPH(roll_s2s);
gpu_sys.SetRollingCoeff_SPH2WALL(roll_s2w);
gpu_sys.SetRollingCoeff_SPH2MESH(roll_s2m);
gpu_sys.SetGravitationalAcceleration(ChVector<float>(grav_X, grav_Y,
grav_Z));
gpu_sys.SetParticleOutputMode(CHGPU_OUTPUT_MODE::CSV);
gpu_sys.SetTimeIntegrator(CHGPU_TIME_INTEGRATOR::CENTERED_DIFFERENCE);
gpu_sys.SetFixedStepSize(step_size);
gpu_sys.SetBDFixed(true);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[]) {
// Output directory
std::string out_dir = GetChronoOutputPath() + "GPU/";
filesystem::create_directory(filesystem::path(out_dir));
out_dir = out_dir + "ballcosim";
filesystem::create_directory(filesystem::path(out_dir));
std::string checkpoint_file = out_dir + "checkpoint.dat";
// run_mode_id == 1, this is simulation phase
if (run_mode_id == 1 || run_mode_id == 2)
{
// Load Checkpoint file
ChSystemGpuMesh gpu_sys(checkpoint_file);
// Material based model is not included in the checkpoint file
// Setup GPU system simulation parameters
SetupGPUParams(gpu_sys);
//auto cube_mesh =
gpu_sys.AddMesh(GetChronoDataFile("models/cube.obj"), ChVector<float>(0),
ChMatrix33<>(1), cube_mass);
auto cube_mesh =
chrono_types::make_shared<geometry::ChTriangleMeshConnected>();
cube_mesh->LoadWavefrontMesh(std::string("../cube_thin.obj"), true,
false);
// I know you can rotate the cube here too, but I'm not sure which
parameter
// it would be.
cube_mesh->Transform(ChVector<>(0, 0,0), ChMatrix33<>(1));
auto cube_mesh_id = gpu_sys.AddMesh(cube_mesh, cube_mass);
gpu_sys.EnableMeshCollision(true);
gpu_sys.Initialize();
std::cout << gpu_sys.GetNumMeshes() << " meshes" << std::endl;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ChSystemSMC sys_cube;
sys_cube.SetContactForceModel(ChSystemSMC::ContactForceModel::Hooke);
sys_cube.SetTimestepperType(ChTimestepper::Type::EULER_IMPLICIT);
sys_cube.Set_G_acc(ChVector<>(grav_X, grav_Y, grav_Z));
//cube inertias:
float cube_inertia_x = 1.873;//
float cube_inertia_y = 1.873;//
float cube_inertia_z = 1.873;//
ChVector<> cube_initial_pos(0,0, -70.5);//was -87.5
//cube body
std::shared_ptr<ChBody> cube_body(sys_cube.NewBody());
cube_body->SetMass(cube_mass);
cube_body->SetInertiaXX(ChVector<>(cube_inertia_x, cube_inertia_y,
cube_inertia_z));
cube_body->SetPos(cube_initial_pos);
// My attempt to rotate the cube 90 degrees horizontally.
cube_body->SetRot(ChMatrix33<>(.90,0,0));
cube_body->SetBodyFixed(false);
sys_cube.AddBody(cube_body);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Motor Guide:
/*std::shared_ptr<ChBody> guide_body(sys_cube.NewBody());
guide_body->SetMass(cube_mass);
guide_body->SetInertiaXX(ChVector<>(cube_inertia_x, cube_inertia_y,
cube_inertia_z));
guide_body->SetPos(cube_initial_pos);
guide_body->SetBodyFixed(true); //must be fixed
sys_cube.AddBody(guide_body);
ChQuaternion<> mesh_rot = Q_from_AngAxis(-90 * CH_C_DEG_TO_RAD, VECT_X);
ChVector<> mesh_trans(cube_initial_pos);
ChFrame<> Xb(mesh_trans,mesh_rot);
*/
//Motor Parameters:
//float lin_freq = 0.5f;
//float lin_period = 1.f / lin_freq;
//float lin_vel = 10;
// Create and initialize the linear motor on tip of the body
//auto motor_lin = chrono_types::make_shared<ChLinkMotorLinearSpeed>();
//motor_lin->Initialize(
//cube_body, // body A (slave)
//guide_body, // body B (master)
//Xb); // motor frame, in abs. coords
// Add the motor to the system
//sys_cube.AddLink(motor_lin);
// Create a ChFunction to be used for the ChLinkMotorLinearSpeed
// lin_rep_seq is a step function for the linear velocity control
//auto lin_part = chrono_types::make_shared<ChFunction_Const>();
//lin_part->Set_yconst(lin_vel);
//auto lin_seq = chrono_types::make_shared<ChFunction_Sequence>();
//lin_seq->InsertFunct(lin_part, time_end, 1, false); // fx,
duration, weight, enforce C0 continuity
//auto lin_rep_seq_0 =
chrono_types::make_shared<ChFunction_Repeat>();
//lin_rep_seq_0->Set_fa(lin_seq);
//lin_rep_seq_0->Set_window_length(lin_period);
//lin_rep_seq_0->Set_window_start(0.25);
//lin_rep_seq_0->Set_window_phase(lin_period);
// Let the linearmotor use this motion function:
//motor_lin_0->SetSpeedFunction(lin_rep_seq_0);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Setup detailed output options
float out_fps = 200;
std::cout << "Output at " << out_fps << " FPS" << std::endl;
unsigned int out_steps = (unsigned int)(1.0 / (out_fps * step_size));
unsigned int total_frames = (unsigned int)(time_end * out_fps);
int currframe = 0;
unsigned int curr_step = 0;
std::vector<float> cube_fx(total_frames);
std::vector<float> cube_fy(total_frames);
std::vector<float> cube_fz(total_frames);
std::vector<float> cube_Tx(total_frames);
std::vector<float> cube_Ty(total_frames);
std::vector<float> cube_Tz(total_frames);
std::vector<float> cube_Vx(total_frames);
std::vector<float> cube_Vy(total_frames);
std::vector<float> cube_Vz(total_frames);
std::vector<float> cube_ax(total_frames);
std::vector<float> cube_ay(total_frames);
std::vector<float> cube_az(total_frames);
std::vector<float> cube_Px(total_frames);
std::vector<float> cube_Py(total_frames);
std::vector<float> cube_Pz(total_frames);
std::vector<float> cube_R0(total_frames);
std::vector<float> cube_R1(total_frames);
std::vector<float> cube_R2(total_frames);
std::vector<float> cube_R3(total_frames);
std::vector<float> cube_Rv0(total_frames);
std::vector<float> cube_Rv1(total_frames);
std::vector<float> cube_Rv2(total_frames);
std::vector<float> cube_Rv3(total_frames);
std::vector<float> cube_Ra0(total_frames);
std::vector<float> cube_Ra1(total_frames);
std::vector<float> cube_Ra2(total_frames);
std::vector<float> cube_Ra3(total_frames);
std::vector<float> KE(total_frames);
clock_t start = std::clock();
for (double t = 0; t < (double)time_end;
t += step_size, curr_step++) {
//// Apply motion to the meshes
ChVector<float> cube_pos(0, 0, 0);
cube_pos.z() = cube_body->GetPos().z();
cube_pos.y() = cube_body->GetPos().y();
cube_pos.x() = cube_body->GetPos().x();
// initial positions and velocity
ChVector<float> mesh_pos(0, 0, 0);
float rev_per_sec = 1;
float ang_vel_Z = rev_per_sec * (float)CH_C_PI;
ChVector<> mesh_lin_vel(0,10,0);
ChQuaternion<> mesh_rot = Q_from_AngY(t * ang_vel_Z);
ChVector<> mesh_ang_vel(0, 0, ang_vel_Z);
if (run_mode_id == 1 ) {
gpu_sys.ApplyMeshMotion(0, cube_body->GetPos(),
cube_body->GetRot(),
cube_body->GetPos_dt(), cube_body->GetWvel_par());
}
else{
gpu_sys.ApplyMeshMotion(0, cube_body->GetPos(),
cube_body->GetRot(),
mesh_lin_vel, cube_body->GetWvel_par());
}
//// calculate forces on the tip ////
ChVector<> cube_force;
ChVector<> cube_torque;
gpu_sys.CollectMeshContactForces(0, cube_force, cube_torque);
cube_body->Empty_forces_accumulators();
cube_body->Accumulate_force(cube_force, cube_body->GetPos(), false);
cube_body->Accumulate_torque(cube_torque, false);
if (t == 0.25 ) {
std::cout << "Next Output frame is at 0.25s" << std::endl;
}
if (curr_step % out_steps == 0) {
std::cout << "Output frame " << currframe + 1 << " of " <<
total_frames << std::endl;
char filename[100];
char mesh_filename[100];
gpu_sys.SetParticleOutputFlags(ABSV | FORCE_COMPONENTS);
KE[currframe]= gpu_sys.GetParticlesKineticEnergy();
//const ChVector<>& pos= cube_body->GetPos();
//std::cout << "Position of cube in z direction " << pos <<
std::endl;
const ChQuaternion<>& Rot= cube_body->GetRot();
//std::cout << "Rotation of cube " << Rot << std::endl;
const ChQuaternion<>& Rot_velocity= cube_body->GetRot_dt();
const ChQuaternion<>& Rot_acc= cube_body->GetRot_dtdt();
//const ChVector<>& pos= cube_body->GetPos_dt();
//std::cout << "Velocity of cube in z direction " << pos <<
std::endl;
cube_fx[currframe] = cube_force.x();
cube_fy[currframe] = cube_force.y();
cube_fz[currframe] = cube_force.z();
cube_Tx[currframe]= cube_torque.x();
cube_Ty[currframe]= cube_torque.y();
cube_Tz[currframe]= cube_torque.z();
cube_Px[currframe]= cube_body->GetPos().x();
cube_Py[currframe]= cube_body->GetPos().y();
cube_Pz[currframe]= cube_body->GetPos().z();
cube_Vx[currframe]= cube_body->GetPos_dt().x();
cube_Vy[currframe]= cube_body->GetPos_dt().y();
cube_Vz[currframe]= cube_body->GetPos_dt().z();
cube_ax[currframe]= cube_body->GetPos_dtdt().x();
cube_ay[currframe]= cube_body->GetPos_dtdt().y();
cube_az[currframe]= cube_body->GetPos_dtdt().z();
cube_R0 [currframe] =Rot.e0();
cube_R1 [currframe] =Rot.e1();
cube_R2 [currframe] =Rot.e2();
cube_R3 [currframe] =Rot.e3();
cube_Rv0 [currframe] =Rot_velocity.e0();
cube_Rv1 [currframe] =Rot_velocity.e1();
cube_Rv2 [currframe] =Rot_velocity.e2();
cube_Rv3 [currframe] =Rot_velocity.e3();
cube_Ra0 [currframe] =Rot_acc.e0();
cube_Ra1 [currframe] =Rot_acc.e1();
cube_Ra2 [currframe] =Rot_acc.e2();
cube_Ra3 [currframe] =Rot_acc.e3();
sprintf(filename, "%s/step%06d.csv", out_dir.c_str(), currframe);
sprintf(mesh_filename, "%s/step%06d_mesh", out_dir.c_str(),
currframe++);
gpu_sys.WriteParticleFile(std::string(filename));
gpu_sys.WriteMeshes(std::string(mesh_filename));
}
gpu_sys.AdvanceSimulation(step_size);
sys_cube.DoStepDynamics(step_size);
}
std::vector<std::pair<std::string, std::vector<float>>> vals = {{"Fx",
cube_fx}, {"Fy", cube_fy}, {"Fz", cube_fz},{"Tx", cube_Tx}, {"Ty", cube_Ty},
{"Tz", cube_Tz},{"Px", cube_Px}, {"Py", cube_Py}, {"Pz", cube_Pz},{"Vx",
cube_Vx}, {"Vy", cube_Vy}, {"Vz", cube_Vz},{"ax", cube_Px}, {"ay", cube_Py},
{"az", cube_Pz},{"R0", cube_R0},{"R1", cube_R1}, {"R2", cube_R2}, {"R3",
cube_R3},{"Rv0", cube_R0},{"Rv1", cube_R1}, {"Rv2", cube_R2}, {"Rv3",
cube_R3},{"Ra0", cube_R0},{"Ra1", cube_R1}, {"Ra2", cube_R2}, {"Ra3",
cube_R3},{"KE", KE}};
write_csv("simulation_outputs_"+std::to_string(helix_angle)+planet+
std::to_string(run_mode_id)+".csv",vals);
clock_t end = std::clock();
double total_time = ((double)(end - start)) / CLOCKS_PER_SEC;
std::cout << "Time: " << total_time << " seconds" << std::endl;
gpu_sys.WriteCheckpointFile(checkpoint_file);
return 0;
}
// run_mode_id == 0, this is the sample preparation phase
ChSystemGpuMesh gpu_sys(sphere_radius, sphere_density,
ChVector<float>(box_X, box_Y, box_Z));
// One thing we can do is to move the Big Box Domain by (0, 0, Z/2) using
SetBDCenter, so the
// coordinate range we are now working with is (-X/2,-Y/2,0) to
(X/2,Y/2,Z), instead of (-X/2,-Y/2,-Z/2) to (X/2, Y/2, Z/2).
// gpu_sys.SetBDCenter(ChVector<float>(0, 0, box_Z / 2));
SetupGPUSystem(gpu_sys);
gpu_sys.EnableMeshCollision(false);
// create top plane boundary condition with its position and normal
ChVector<float> topWallPos(box_X / 2, box_Y / 2, box_Z);
ChVector<float> topWallNrm(0.0f, 0.0f, -1.0f);
size_t topWall = gpu_sys.CreateBCPlane(topWallPos, topWallNrm, true);
float topWall_vel; // downword top plane moving velocity
float topWall_offset; // position offset of the plane when it first
starts to move
float topWall_moveTime; // time when the plane first starts to move
downword
float topWall_vel2; // upward top plane moving velocity
float topWall_offset2; // position offset of the plane when it first
starts to move
float topWall_moveTime2; // time when the plane first starts to move upward
gpu_sys.Initialize();
// user defined offset position function for top wall
std::function<double3(float)> topWall_posFunc = [&topWall_offset,
&topWall_vel, &topWall_moveTime](float t) {
double3 pos = {0, 0, 0};
pos.z = topWall_offset + topWall_vel * (t - topWall_moveTime);
return pos;
};
// user defined offset position function for top wall
std::function<double3(float)> topWall_posFunc2 = [&topWall_offset2,
&topWall_vel2, &topWall_moveTime2](float t) {
double3 pos = {0, 0, 0};
pos.z = topWall_offset2 + topWall_vel2 * (t - topWall_moveTime2);
return pos;
};
float curr_timee = 0;
ChVector<float> plane_reaction_force;
ChVector<float> platePos;
float platePos2;
int nc;
unsigned int currframe = 0;
float out_fps = 100;
unsigned int out_steps = (unsigned int)(1 / (out_fps * step_size));
unsigned int total_frames = (unsigned int)(time_settle * out_fps);
unsigned int curr_step = 0;
for (double t = 0; t < (double)time_settle; t += step_size, curr_step++) {
if (curr_step % out_steps == 0) {
std::cout << "Output frame " << currframe + 1 << " of " <<
total_frames << std::endl;
char filename[100];
sprintf(filename, "%s/step%06d.csv", out_dir.c_str(), currframe++);
gpu_sys.WriteParticleFile(std::string(filename));
}
gpu_sys.AdvanceSimulation(step_size);
curr_timee += step_size;
}
double vr1 = getVoidRatio( gpu_sys, sphere_radius);
double sysKE1 = CalcKE(gpu_sys, sphere_radius, sphere_density);
double pr1 = vr1/(1.0f+vr1);
std::cout << "Void_Ratio Before Plate " << vr1 << std::endl;
std::cout << "Porosity Before Plate" << pr1<< std::endl;
std::cout << "MAX_z Before Plate " << gpu_sys.GetMaxParticleZ () <<
std::endl;
std::cout << "Min_z Before Plate" << gpu_sys.GetMinParticleZ () <<
std::endl;
// top plate move downward with velocity 1cm/s
topWall_vel = -2.0f;
// i would like it to start from the top most sphere
topWall_offset = (float)gpu_sys.GetMaxParticleZ() + sphere_radius -
topWallPos[2];
topWall_moveTime = curr_timee;
// sphere settled now push the plate downward
gpu_sys.SetBCOffsetFunction(topWall, topWall_posFunc);
// continue simulation until the end
for (double t = curr_timee; t < (double)compress_end; t += step_size,
curr_step++) {
if (curr_step % out_steps == 0) {
std::cout << "Output frame " << currframe + 1 << " of " <<
total_frames << std::endl;
char filename[100];
sprintf(filename, "%s/step%06d.csv", out_dir.c_str(), currframe++);
gpu_sys.WriteParticleFile(std::string(filename));
}
gpu_sys.AdvanceSimulation(step_size);
platePos = gpu_sys.GetBCPlanePosition(topWall);
std::cout << "top plate pos_z: " << platePos.z() << " cm" <<
std::endl;
curr_timee += step_size;
}
double vr2 = getVoidRatio( gpu_sys, sphere_radius);
double sysKE2 = CalcKE(gpu_sys, sphere_radius, sphere_density);
double pr2 = vr2/(1.0f+vr2);
std::cout << "Void_Ratio after Plate compression " << vr2 << std::endl;
std::cout << "Porosity after Plate compression" << pr2<< std::endl;
std::cout << "MAX_z after Plate compression" << gpu_sys.GetMaxParticleZ ()
<< std::endl;
std::cout << "Min_z after Plate compression" << gpu_sys.GetMinParticleZ ()
<< std::endl;
// top plate move upward with velocity 0.5cm/s
topWall_vel2 = 0.5f;
// i would like it to start from the top most sphere
topWall_offset2 = (float)gpu_sys.GetMaxParticleZ() + sphere_radius -
topWallPos[2];;
topWall_moveTime2 = curr_timee;
gpu_sys.SetBCOffsetFunction(topWall, topWall_posFunc2);
for (double t = curr_timee; t < (double)decompress_end; t +=
step_size, curr_step++) {
if (curr_step % out_steps == 0) {
std::cout << "Output frame " << currframe + 1 << " of " <<
total_frames << std::endl;
char filename[100];
sprintf(filename, "%s/step%06d.csv", out_dir.c_str(), currframe++);
gpu_sys.WriteParticleFile(std::string(filename));
}
gpu_sys.AdvanceSimulation(step_size);
//platePos2 = (float)gpu_sys.GetBCPlanePosition(topWall);
//std::cout << "top plate pos_z: " << platePos.z() << " cm" <<
std::endl;
curr_timee += step_size;
}
double vr = getVoidRatio( gpu_sys, sphere_radius);
double sysKE = CalcKE(gpu_sys, sphere_radius, sphere_density);
double pr = vr/(1.0f+vr);
std::cout << "Final Void_Ratio " << vr << std::endl;
std::cout << "Final Porosity" << pr<< std::endl;
std::cout << "Final MAX_z " << gpu_sys.GetMaxParticleZ () << std::endl;
std::cout << "Final Min_z " << gpu_sys.GetMinParticleZ () << std::endl;
std::cout << "NOP " << gpu_sys.GetNumParticles () << std::endl;
std::cout << "sysKE " << sysKE << std::endl;
// This is settling phase, so output a checkpoint file
gpu_sys.WriteCheckpointFile(checkpoint_file);
return 0;
}