Skip to content

Instantly share code, notes, and snippets.

@utilForever
Created May 3, 2018 03:48
Show Gist options
  • Select an option

  • Save utilForever/c87cc5bd99b9671840f91f058eb9b1e0 to your computer and use it in GitHub Desktop.

Select an option

Save utilForever/c87cc5bd99b9671840f91f058eb9b1e0 to your computer and use it in GitHub Desktop.
getopt vs Clara (Clara)
/*************************************************************************
> File Name: main.cpp
> Project Name: CubbyFlow
> Author: Chan-Ho Chris Ohk
> Purpose: SPH Simulator
> Created Time: 2017/06/18
> Copyright (c) 2018, Chan-Ho Chris Ohk
*************************************************************************/
#include <Core/Array/ArrayUtils.h>
#include <Core/Collider/RigidBodyCollider3.h>
#include <Core/Emitter/VolumeParticleEmitter3.h>
#include <Core/Geometry/Box3.h>
#include <Core/Geometry/Cylinder3.h>
#include <Core/Geometry/Plane3.h>
#include <Core/Geometry/Sphere3.h>
#include <Core/Particle/ParticleSystemData3.h>
#include <Core/Solver/Particle/PCISPH/PCISPHSolver3.h>
#include <Core/Solver/Particle/SPH/SPHSolver3.h>
#include <Core/Surface/ImplicitSurfaceSet3.h>
#include <Core/Utils/Logging.h>
#include <Clara/include/clara.hpp>
#include <pystring/pystring.h>
#ifdef CUBBYFLOW_WINDOWS
#include <direct.h>
#else
#include <sys/stat.h>
#endif
#include <fstream>
#include <string>
#include <vector>
#define APP_NAME "SPHSim"
using namespace CubbyFlow;
std::string ToString(const clara::Opt& opt)
{
std::ostringstream oss;
oss << (clara::Parser() | opt);
return oss.str();
}
std::string ToString(const clara::Parser& p)
{
std::ostringstream oss;
oss << p;
return oss.str();
}
void SaveParticleAsPos(const ParticleSystemData3Ptr& particles, const std::string& rootDir, int frameCnt)
{
Array1<Vector3D> positions(particles->GetNumberOfParticles());
CopyRange1(particles->GetPositions(), particles->GetNumberOfParticles(), &positions);
char baseName[256];
snprintf(baseName, sizeof(baseName), "frame_%06d.pos", frameCnt);
std::string fileName = pystring::os::path::join(rootDir, baseName);
std::ofstream file(fileName.c_str(), std::ios::binary);
if (file)
{
printf("Writing %s...\n", fileName.c_str());
std::vector<uint8_t> buffer;
Serialize(positions.ConstAccessor(), &buffer);
file.write(reinterpret_cast<char*>(buffer.data()), buffer.size());
file.close();
}
}
void SaveParticleAsXYZ(const ParticleSystemData3Ptr& particles, const std::string& rootDir, int frameCnt)
{
Array1<Vector3D> positions(particles->GetNumberOfParticles());
CopyRange1(particles->GetPositions(), particles->GetNumberOfParticles(), &positions);
char baseName[256];
snprintf(baseName, sizeof(baseName), "frame_%06d.xyz", frameCnt);
std::string filename = pystring::os::path::join(rootDir, baseName);
std::ofstream file(filename.c_str());
if (file)
{
printf("Writing %s...\n", filename.c_str());
for (const auto& pt : positions)
{
file << pt.x << ' ' << pt.y << ' ' << pt.z << std::endl;
}
file.close();
}
}
void PrintInfo(const SPHSolver3Ptr& solver)
{
const auto particles = solver->GetSPHSystemData();
printf("Number of particles: %zu\n", particles->GetNumberOfParticles());
}
void RunSimulation(const std::string& rootDir, const SPHSolver3Ptr& solver, int numberOfFrames, const std::string& format, double fps)
{
const auto particles = solver->GetSPHSystemData();
for (Frame frame(0, 1.0 / fps); frame.index < numberOfFrames; ++frame)
{
solver->Update(frame);
if (format == "xyz")
{
SaveParticleAsXYZ(particles, rootDir, frame.index);
}
else if (format == "pos")
{
SaveParticleAsPos(particles, rootDir, frame.index);
}
}
}
// Water-drop example (PCISPH)
void RunExample1(const std::string& rootDir, double targetSpacing, int numberOfFrames, const std::string& format, double fps)
{
BoundingBox3D domain(Vector3D(), Vector3D(1, 2, 1));
// Build solver
auto solver = PCISPHSolver3::GetBuilder()
.WithTargetDensity(1000.0)
.WithTargetSpacing(targetSpacing)
.MakeShared();
solver->SetPseudoViscosityCoefficient(0.0);
// Build emitter
BoundingBox3D sourceBound(domain);
sourceBound.Expand(-targetSpacing);
const auto plane = Plane3::GetBuilder()
.WithNormal({ 0, 1, 0 })
.WithPoint({ 0, 0.25 * domain.GetHeight(), 0 })
.MakeShared();
const auto sphere = Sphere3::GetBuilder()
.WithCenter(domain.MidPoint())
.WithRadius(0.15 * domain.GetWidth())
.MakeShared();
const auto surfaceSet = ImplicitSurfaceSet3::GetBuilder()
.WithExplicitSurfaces({ plane, sphere })
.MakeShared();
const auto emitter = VolumeParticleEmitter3::GetBuilder()
.WithSurface(surfaceSet)
.WithSpacing(targetSpacing)
.WithMaxRegion(sourceBound)
.WithIsOneShot(true)
.MakeShared();
solver->SetEmitter(emitter);
// Build collider
const auto box = Box3::GetBuilder()
.WithIsNormalFlipped(true)
.WithBoundingBox(domain)
.MakeShared();
const auto collider = RigidBodyCollider3::GetBuilder()
.WithSurface(box)
.MakeShared();
solver->SetCollider(collider);
// Print simulation info
printf("Running example 1 (water-drop with PCISPH)\n");
PrintInfo(solver);
// Run simulation
RunSimulation(rootDir, solver, numberOfFrames, format, fps);
}
// Water-drop example (SPH)
void RunExample2(const std::string& rootDir, double targetSpacing, int numberOfFrames, const std::string& format, double fps)
{
BoundingBox3D domain(Vector3D(), Vector3D(1, 2, 1));
auto solver = SPHSolver3::GetBuilder()
.WithTargetDensity(1000.0)
.WithTargetSpacing(targetSpacing)
.MakeShared();
solver->SetPseudoViscosityCoefficient(0.0);
// Build emitter
BoundingBox3D sourceBound(domain);
sourceBound.Expand(-targetSpacing);
const auto plane = Plane3::GetBuilder()
.WithNormal({ 0, 1, 0 })
.WithPoint({ 0, 0.25 * domain.GetHeight(), 0 })
.MakeShared();
const auto sphere = Sphere3::GetBuilder()
.WithCenter(domain.MidPoint())
.WithRadius(0.15 * domain.GetWidth())
.MakeShared();
const auto surfaceSet = ImplicitSurfaceSet3::GetBuilder()
.WithExplicitSurfaces({ plane, sphere })
.MakeShared();
const auto emitter = VolumeParticleEmitter3::GetBuilder()
.WithSurface(surfaceSet)
.WithSpacing(targetSpacing)
.WithMaxRegion(sourceBound)
.WithIsOneShot(true)
.MakeShared();
solver->SetEmitter(emitter);
// Build collider
const auto box = Box3::GetBuilder()
.WithIsNormalFlipped(true)
.WithBoundingBox(domain)
.MakeShared();
const auto collider = RigidBodyCollider3::GetBuilder()
.WithSurface(box)
.MakeShared();
solver->SetCollider(collider);
// Print simulation info
printf("Running example 2 (water-drop with SPH)\n");
PrintInfo(solver);
// Run simulation
RunSimulation(rootDir, solver, numberOfFrames, format, fps);
}
// Dam-breaking example
void RunExample3(const std::string& rootDir, double targetSpacing, int numberOfFrames, const std::string& format, double fps)
{
BoundingBox3D domain(Vector3D(), Vector3D(3, 2, 1.5));
const double lz = domain.GetDepth();
// Build solver
auto solver = PCISPHSolver3::GetBuilder()
.WithTargetDensity(1000.0)
.WithTargetSpacing(targetSpacing)
.MakeShared();
solver->SetPseudoViscosityCoefficient(0.0);
solver->SetTimeStepLimitScale(10.0);
// Build emitter
BoundingBox3D sourceBound(domain);
sourceBound.Expand(-targetSpacing);
const auto box1 = Box3::GetBuilder()
.WithLowerCorner({ 0, 0, 0 })
.WithUpperCorner({ 0.5 + 0.001, 0.75 + 0.001, 0.75 * lz + 0.001 })
.MakeShared();
const auto box2 = Box3::GetBuilder()
.WithLowerCorner({ 2.5 - 0.001, 0, 0.25 * lz - 0.001 })
.WithUpperCorner({ 3.5 + 0.001, 0.75 + 0.001, 1.5 * lz + 0.001 })
.MakeShared();
const auto boxSet = ImplicitSurfaceSet3::GetBuilder()
.WithExplicitSurfaces({ box1, box2 })
.MakeShared();
const auto emitter = VolumeParticleEmitter3::GetBuilder()
.WithSurface(boxSet)
.WithMaxRegion(sourceBound)
.WithSpacing(targetSpacing)
.MakeShared();
solver->SetEmitter(emitter);
// Build collider
const auto cyl1 = Cylinder3::GetBuilder()
.WithCenter({ 1, 0.375, 0.375 })
.WithRadius(0.1)
.WithHeight(0.75)
.MakeShared();
const auto cyl2 = Cylinder3::GetBuilder()
.WithCenter({ 1.5, 0.375, 0.75 })
.WithRadius(0.1)
.WithHeight(0.75)
.MakeShared();
const auto cyl3 = Cylinder3::GetBuilder()
.WithCenter({ 2, 0.375, 1.125 })
.WithRadius(0.1)
.WithHeight(0.75)
.MakeShared();
const auto box = Box3::GetBuilder()
.WithIsNormalFlipped(true)
.WithBoundingBox(domain)
.MakeShared();
const auto surfaceSet = ImplicitSurfaceSet3::GetBuilder()
.WithExplicitSurfaces({ cyl1, cyl2, cyl3, box })
.MakeShared();
const auto collider = RigidBodyCollider3::GetBuilder()
.WithSurface(surfaceSet)
.MakeShared();
solver->SetCollider(collider);
// Print simulation info
printf("Running example 3 (dam-breaking with PCISPH)\n");
PrintInfo(solver);
// Run simulation
RunSimulation(rootDir, solver, numberOfFrames, format, fps);
}
int main(int argc, char* argv[])
{
bool showHelp = false;
double targetSpacing = 0.02;
int numberOfFrames = 100;
double fps = 60.0;
int exampleNum = 1;
std::string logFileName = APP_NAME ".log";
std::string outputDir = APP_NAME "_output";
std::string format = "xyz";
// Parsing
auto parser =
clara::Help(showHelp) |
clara::Opt(targetSpacing, "targetSpacing")
["-s"]["--spacing"]
("target particle spacing (default is 0.02)") |
clara::Opt(numberOfFrames, "numberOfFrames")
["-f"]["--frames"]
("total number of frames (default is 100)") |
clara::Opt(fps, "fps")
["-p"]["--fps"]
("frames per second (default is 60.0)") |
clara::Opt(exampleNum, "exampleNum")
["-e"]["--example"]
("example number (between 1 and 3, default is 1)") |
clara::Opt(logFileName, "logFileName")
["-l"]["--log"]
("log file name (default is " APP_NAME ".log)") |
clara::Opt(outputDir, "outputDir")
["-o"]["--output"]
("output directory name (default is " APP_NAME "_output)") |
clara::Opt(format, "format")
["-m"]["--format"]
("particle output format (xyz or pos. default is xyz)");
auto result = parser.parse(clara::Args(argc, argv));
if (!result)
{
std::cerr << "Error in command line: " << result.errorMessage() << '\n';
exit(EXIT_FAILURE);
}
if (showHelp)
{
std::cout << ToString(parser) << '\n';
exit(EXIT_SUCCESS);
}
#ifdef CUBBYFLOW_WINDOWS
_mkdir(outputDir.c_str());
#else
mkdir(outputDir.c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
#endif
std::ofstream logFile(logFileName.c_str());
if (logFile)
{
Logging::SetAllStream(&logFile);
}
switch (exampleNum)
{
case 1:
RunExample1(outputDir, targetSpacing, numberOfFrames, format, fps);
break;
case 2:
RunExample2(outputDir, targetSpacing, numberOfFrames, format, fps);
break;
case 3:
RunExample3(outputDir, targetSpacing, numberOfFrames, format, fps);
break;
default:
std::cout << ToString(parser) << '\n';
exit(EXIT_FAILURE);
}
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment