This is the file that I am currently using. I have my calculations for the 
void ratio at the very end if you need to look at it.
Thank you so much

On Sunday, May 22, 2022 at 3:44:57 PM UTC-7 Mohammad Wasfi wrote:

> Hello there, 
>
> I am using the GPU module to initiate a bed of particles and let it 
> settle. I have been able to do that successfully. Now, I am trying to 
> control the void volume of the bed using the void ratio value. To do so, I 
> need to determine the maximum and minimum x and y positions of the 
> particles to find the most accurate cross-sectional area of the bed. I was 
> wondering of a way to do this similarly to using the getMaxParticleZ. If 
> that's not possible, is there a Chrono function under the GPU module that 
> can directly find the void ratio?
>
> Finally, do you have any suggestions for controlling the void volume of a 
> bed of particles? 
>
>
> Thank you so much,
>

-- 
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/f8c19276-bbae-464b-a9d8-5cc94177cc00n%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"

#include "chrono_thirdparty/filesystem/path.h"

using namespace chrono;
using namespace chrono::gpu;

// Simulation parameters (same as those in the json file)
double step_size = 5e-7;   // time step
double sphere_radius = 0.1;  // sphere radius (6 mm glass beads same as 
experiments )
double sphere_density = 0.92; // density of sphere particle
double time_settle = 0.75;
double time_end = 0.5;

// Define Big domain size
double box_X = 16;
double box_Y = 16;
double box_Z = 200;

int run_mode_id = 0;
// Gravity
double grav_X = 0.0f;
double grav_Y = 0.0f;
double grav_Z = -981.0f;

double ISE = 100000;

float cone_density = 8; //g/cm^3

float cone_mass = (1. / 3.) * (float)CH_C_PI * 5.0 * 5.0 * 5.0 * cone_density;


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
void SetupGPUSystem(ChSystemGpuMesh& gpu_sys) {
    // Set GPU system parameters
    // Currently, parameters are given by Luning
    // After calibration, they may be modified
    double cor_p = 0.8; // sphere restitution
    double cor_w = 0.8;  // mesh & wall restitution (value from Thoesen et al., 
2019)
    double cor_m  = 0.8; // mesh restitution
    double youngs_modulus_p = 9.7e10; // 40Mpa = 4e7Pa = 4e8 g/(cms^2)
    double youngs_modulus_m = 1.9e12;
    double youngs_modulus_w = 9.7e10;
    double poisson_ratio_m = 0.265;
    double poisson_ratio_p = 0.35;
    double poisson_ratio_w = 0.35;
    double mu_s2s = 0.5;  // static friction coefficient sphere to sphere
    double mu_s2w = 0.5;  // static friction coefficient sphere to wall & mesh 
(value from Thoesen et al., 2019)
    double mu_s2m = 0.04;
    float roll_s2s = 0.001;
    float roll_s2w = 0.01;
    float roll_s2m = 0.01;
    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.SetGravitationalAcceleration(ChVector<float>(grav_X, grav_Y, 
grav_Z));
    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.SetInterfacialSurfaceEnergy(ISE);
    gpu_sys.SetParticleOutputMode(CHGPU_OUTPUT_MODE::CSV);
    gpu_sys.SetTimeIntegrator(CHGPU_TIME_INTEGRATOR::CENTERED_DIFFERENCE);
    gpu_sys.SetFixedStepSize(step_size);
    gpu_sys.SetBDFixed(true);
    //gpu_sys.CreateBCPlane(ChVector<>(0, 0, -6.5), ChVector<>(0, 0, 1), false);

    // Rain particles
    double fill_bottom_below = -95;
    double fill_top_below = -65;
    chrono::utils::PDSampler<float> sampler(2.4f * sphere_radius);
    // leave a 1cm margin at edges of sampling
    ChVector<> hdims(box_X / 2 - 2.0, box_Y / 2 - 2.0, 0);
    ChVector<> center(0, 0, fill_bottom_below + 2.0 * sphere_radius);
    std::vector<ChVector<float>> body_points;
    // Shift up for bottom of box
    center.z() += 3 * sphere_radius;
    // fill the lower half
    while (center.z() < fill_top_below) {
        std::cout << "Create layer at " << center.z() << std::endl;
        auto points = sampler.SampleBox(center, hdims);
        body_points.insert(body_points.end(), points.begin(), points.end());
        center.z() += 2.05 * sphere_radius;
    }
        //Send sinusoidal wave through particle bed in x direction after 0.5 
seconds?
    std::function<double3(float)> pos_func_wave = [&params](float t ) {
        double3 pos = {0, 0, 0};

        double t0 = 0.5;
        double freq = CH_C_PI / 4;

        if (t > t0) {
            pos.x = 0.1 * params.box_X * std::sin((t - t0) * freq);
        }
    return pos;
    }

    gpu_sys.setBDWallsMotionFunction(pos_func_wave);

    std::cout << "Created " << body_points.size() << "spheres" << std::endl;
    gpu_sys.SetParticles(body_points);
}

void SetupGPUParams(ChSystemGpuMesh& gpu_sys) {
    double cor_p = 0.8; // sphere restitution
    double cor_w = 0.8;  // mesh & wall restitution (value from Thoesen et al., 
2019)
    double cor_m  = 0.8; // mesh restitution
    double youngs_modulus_p = 9.7e10; // 40Mpa = 4e7Pa = 4e8 g/(cms^2)
    double youngs_modulus_m = 1.9e12;
    double youngs_modulus_w = 9.7e10;
    double poisson_ratio_m = 0.265;
    double poisson_ratio_p = 0.35;
    double poisson_ratio_w = 0.35;
    double mu_s2s = 0.5;  // static friction coefficient sphere to sphere
    double mu_s2w = 0.5;  // static friction coefficient sphere to wall & mesh 
(value from Thoesen et al., 2019)
    double mu_s2m = 0.04;
    float roll_s2s = 0.001;
    float roll_s2w = 0.01;
    float roll_s2m = 0.01;
    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.SetGravitationalAcceleration(ChVector<float>(grav_X, grav_Y, 
grav_Z));
    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.SetInterfacialSurfaceEnergy(ISE);
    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)
    {
        // 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);

        // Setup meshes
        // Load the cone
        gpu_sys.AddMesh("../Part1.obj", ChVector<float>(0, 0, -78.5173), 
ChMatrix33<float>(1), cone_mass);
        gpu_sys.EnableMeshCollision(true);


        gpu_sys.Initialize();
        std::cout << gpu_sys.GetNumMeshes() << " meshes" << std::endl;

        // Create rigid ball_body simulation
        ChSystemSMC sys_cone;
        sys_cone.SetContactForceModel(ChSystemSMC::ContactForceModel::Hooke);
        sys_cone.SetTimestepperType(ChTimestepper::Type::EULER_IMPLICIT);
        sys_cone.Set_G_acc(ChVector<>(0, 0, -980));

        float cone_inertia_x = (3. / 10.) * cone_mass * 5.0 * 5.0;
        float cone_inertia_y = cone_mass * ((3. / 20.) * 5.0 * 5.0 + (3. / 80.) 
* 5.0 * 5.0);
        float cone_inertia_z = cone_inertia_y;

        ChVector<> ball_initial_pos(0, 0, 0);

        std::shared_ptr<ChBody> cone_body(sys_cone.NewBody());
        cone_body->SetMass(cone_mass);
        cone_body->SetInertiaXX(ChVector<>(cone_inertia_x, cone_inertia_y, 
cone_inertia_z));
        cone_body->SetPos(ball_initial_pos);
        cone_body->SetBodyFixed(false);
        sys_cone.AddBody(cone_body);

        // Setup detailed output options
        float out_fps = 350;
        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> cone_fx(total_frames);
        std::vector<float> cone_fy(total_frames);
        std::vector<float> cone_fz(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

            gpu_sys.ApplyMeshMotion(0, cone_body->GetPos(), cone_body->GetRot(),
                cone_body->GetPos_dt(), cone_body->GetWvel_par());

            //// calculate forces on the cone
            ChVector<> cone_force;
            ChVector<> cone_torque;
            gpu_sys.CollectMeshContactForces(0, cone_force, cone_torque);
            cone_body->Empty_forces_accumulators();
            cone_body->Accumulate_force(cone_force, cone_body->GetPos(), false);
            cone_body->Accumulate_torque(cone_torque, false);

            if (curr_step % out_steps == 0) {
                std::cout << "Output frame " << currframe + 1 << " of " << 
total_frames << std::endl;
                char filename[100];
                char mesh_filename[100];

                cone_fx[currframe] = cone_force.x();
                cone_fy[currframe] = cone_force.y();
                cone_fz[currframe] = cone_force.z();

                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_cone.DoStepDynamics(step_size);
        }

        std::vector<std::pair<std::string, std::vector<float>>> vals = {{"Fx", 
cone_fx}, {"Fy", cone_fy}, {"Fz", cone_fz}};
        write_csv("cone_forces.csv",vals);

        clock_t end = std::clock();
        double total_time = ((double)(end - start)) / CLOCKS_PER_SEC;

        std::cout << "Time: " << total_time << " seconds" << std::endl;

        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(true);
    gpu_sys.Initialize();

    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);
    }

    double height = gpu_sys.GetMaxParticleZ();
    std::cout << height << std::endl;

    // void Fraction calcs Mohammad:
    double Volume_Of_SettledParticles = (box_X*box_Y)* (gpu_sys.GetMaxParticleZ 
() - gpu_sys.GetMinParticleZ ());
    double Total_Volume_Of_Particles = (1.334 * 3.14 * 
pow(sphere_radius,3))*gpu_sys.GetNumParticles () ;
    double voids_volume = Volume_Of_SettledParticles - 
Total_Volume_Of_Particles;
    double vr2 = voids_volume/Total_Volume_Of_Particles;
    std::cout << "Void_Ratio " << vr2 << std::endl;
    
    // This is settling phase, so output a checkpoint file
    gpu_sys.WriteCheckpointFile(checkpoint_file);
    return 0;
}

Reply via email to