ProjectPhysX / FluidX3D

The fastest and most memory efficient lattice Boltzmann CFD software, running on all GPUs via OpenCL. Free for non-commercial use.
https://youtube.com/@ProjectPhysX
Other
3.48k stars 281 forks source link

How can I export a mesh #171

Closed PavelBlend closed 3 months ago

PavelBlend commented 3 months ago

How can I export a mesh to vtk format? I modified your example, but it didn't work. At the end I added a call to write_mesh_to_vtk.

void main_setup() { // raindrop impact; required extensions in defines.hpp: FP16C, VOLUME_FORCE, EQUILIBRIUM_BOUNDARIES, SURFACE, INTERACTIVE_GRAPHICS or GRAPHICS
    // ################################################################## define simulation box size, viscosity and volume force ###################################################################
    const uint3 lbm_N = resolution(float3(1.0f, 1.0f, 0.85f), 32u); // input: simulation box aspect ratio and VRAM occupation in MB, output: grid resolution
    float lbm_D = (float)lbm_N.x/5.0f;
    const float lbm_u = 0.05f; // impact velocity in LBM units
    const float si_T = 0.003f; // simulated time in [s]
    const float inclination = 20.0f; // impact angle [°], 0 = vertical
    const int select_drop_size = 12;
    //                            0        1        2        3        4        5        6        7        8        9       10       11       12       13 (13 is for validation)
    const float si_Ds[] = { 1.0E-3f, 1.5E-3f, 2.0E-3f, 2.5E-3f, 3.0E-3f, 3.5E-3f, 4.0E-3f, 4.5E-3f, 5.0E-3f, 5.5E-3f, 6.0E-3f, 6.5E-3f, 7.0E-3f, 4.1E-3f };
    const float si_us[] = {   4.50f,   5.80f,   6.80f,   7.55f,   8.10f,   8.45f,   8.80f,   9.05f,   9.20f,   9.30f,   9.40f,   9.45f,   9.55f,   7.21f };
    float const si_nu = 1.0508E-6f; // kinematic shear viscosity [m^2/s] at 20°C and 35g/l salinity
    const float si_rho = 1024.8103f; // fluid density [kg/m^3] at 20°C and 35g/l salinity
    const float si_sigma = 73.81E-3f; // fluid surface tension [kg/s^2] at 20°C and 35g/l salinity
    const float si_g = 9.81f; // gravitational acceleration [m/s^2]
    const float si_D = si_Ds[select_drop_size]; // drop diameter [m] (1-7mm)
    const float si_u = si_us[select_drop_size]; // impact velocity [m/s] (4.50-9.55m/s)
    units.set_m_kg_s(lbm_D, lbm_u, 1.0f, si_D, si_u, si_rho); // calculate 3 independent conversion factors (m, kg, s)
    print_info("D = "+to_string(si_D, 6u));
    print_info("Re = "+to_string(units.si_Re(si_D, si_u, si_nu), 6u));
    print_info("We = "+to_string(units.si_We(si_D, si_u, si_rho, si_sigma), 6u));
    print_info("Fr = "+to_string(units.si_Fr(si_D, si_u, si_g), 6u));
    print_info("Ca = "+to_string(units.si_Ca(si_u, si_rho, si_nu, si_sigma), 6u));
    print_info("Bo = "+to_string(units.si_Bo(si_D, si_rho, si_g, si_sigma), 6u));
    print_info("10ms = "+to_string(units.t(0.01f))+" LBM time steps");
    const float lbm_H = 0.4f*(float)lbm_N.x;
    const float lbm_R = 0.5f*lbm_D; // drop radius
    LBM lbm(lbm_N, 1u, 1u, 1u, units.nu(si_nu), 0.0f, 0.0f, -units.f(si_rho, si_g), units.sigma(si_sigma)); // calculate values for remaining parameters in simulation units
    // ###################################################################################### define geometry ######################################################################################
    const uint Nx=lbm.get_Nx(), Ny=lbm.get_Ny(), Nz=lbm.get_Nz(); parallel_for(lbm.get_N(), [&](ulong n) { uint x=0u, y=0u, z=0u; lbm.coordinates(n, x, y, z);
        if(sphere(x, y, z, float3(0.5f*(float)Nx, 0.5f*(float)Ny-2.0f*lbm_R*tan(inclination*pif/180.0f), lbm_H+lbm_R+2.5f)+0.5f, lbm_R+2.0f)) {
            const float b = sphere_plic(x, y, z, float3(0.5f*(float)Nx, 0.5f*(float)Ny-2.0f*lbm_R*tan(inclination*pif/180.0f)+0.5f, lbm_H+lbm_R+2.5f), lbm_R);
            if(b!=-1.0f) {
                lbm.u.y[n] =  sinf(inclination*pif/180.0f)*lbm_u;
                lbm.u.z[n] = -cosf(inclination*pif/180.0f)*lbm_u;
                if(b==1.0f) {
                    lbm.flags[n] = TYPE_F;
                    lbm.phi[n] = 1.0f;
                } else {
                    lbm.flags[n] = TYPE_I;
                    lbm.phi[n] = b; // initialize cell fill level phi directly instead of just flags, this way the raindrop sphere is smooth already at initialization
                }
            }
        }
        if(z==0) lbm.flags[n] = TYPE_S;
        else if(z==to_uint(lbm_H)) {
            lbm.flags[n] = TYPE_I;
            lbm.phi[n] = 0.5f; // not strictly necessary, but should be clearer (phi is automatically initialized to 0.5f for TYPE_I if not initialized)
        } else if((float)z<lbm_H) lbm.flags[n] = TYPE_F;
        else if((x==0u||x==Nx-1u||y==0u||y==Ny-1u||z==Nz-1u)&&(float)z>lbm_H+lbm_R) { // make drops that hit the simulation box ceiling disappear
            lbm.rho[n] = 0.5f;
            lbm.flags[n] = TYPE_E;
        }
    }); // ####################################################################### run simulation, export images and data ##########################################################################
    lbm.graphics.visualization_modes = lbm.get_D()==1u ? VIS_PHI_RAYTRACE : VIS_PHI_RASTERIZE;
#if defined(GRAPHICS) && !defined(INTERACTIVE_GRAPHICS)
    Mesh* mesh = new Mesh(1u, float3(0.0f));
    lbm.run(0u); // initialize simulation
    while(lbm.get_t()<=units.t(si_T)) { // main simulation loop
        if(lbm.graphics.next_frame(units.t(si_T), 5.0f)) { // generate video
            lbm.graphics.set_camera_centered(-30.0f, 20.0f, 100.0f, 1.0f);
            lbm.graphics.write_frame(get_exe_path()+"export/new/");
            lbm.graphics.set_camera_centered(10.0f, 40.0f, 100.0f, 1.0f);
            lbm.graphics.write_frame(get_exe_path()+"export/p/");
            lbm.graphics.set_camera_centered(0.0f, 0.0f, 45.0f, 1.0f);
            lbm.graphics.write_frame(get_exe_path()+"export/o/");
            lbm.graphics.set_camera_centered(0.0f, 90.0f, 45.0f, 1.0f);
            lbm.graphics.write_frame(get_exe_path()+"export/t/");
        }
        lbm.run(1u);
        lbm.write_mesh_to_vtk(mesh);
    }
    //lbm.run(units.t(si_T)); // only generate one image
    //lbm.graphics.set_camera_centered(-30.0f, 20.0f, 100.0f, 1.0f);
    //lbm.graphics.write_frame();
#else // GRAPHICS && !INTERACTIVE_GRAPHICS
    lbm.run();
#endif // GRAPHICS && !INTERACTIVE_GRAPHICS
} /**/
ProjectPhysX commented 3 months ago

Hi @PavelBlend,

the lbm.write_mesh_to_vtk(...); function is there to export meshes previously loaded from .stl files, with correct translation/scaling as they were placed in the simulation box, and with unit conversion.

This does not work for exporting the mesh of the free surface - there is currently no function implemented to generate the free surface mesh from the lbm.phi isofield on the CPU side. For the embedded rendering, the free surface mesh is generated on-the-fly in GPU registers and directly rendered to the bitmap, without ever storing it in GPU memory.

You can however export the lbm.phi isofield, with lbm.phi.write_device_to_vtk();, and render the isosurface from it in ParaView.

In your code snipped above, you just added an empty Mesh with 1 triangle and (rotation) center at 0, 0, 0, without setting the 3 vertex positions of this triangle, and tried exporting that.

Kind regards, Moritz