Created
May 3, 2018 03:48
-
-
Save utilForever/c87cc5bd99b9671840f91f058eb9b1e0 to your computer and use it in GitHub Desktop.
getopt vs Clara (Clara)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /************************************************************************* | |
| > 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