├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md ├── img ├── 1.png ├── 2.png ├── 3.png ├── 4.png ├── 5.png ├── 6.png ├── 7.png └── 8.png └── simulators ├── 1_mass_spring ├── CMakeLists.txt ├── include │ ├── InertialEnergy.h │ ├── MassSpringEnergy.h │ ├── device_uti.h │ ├── simulator.h │ ├── square_mesh.h │ └── uti.h └── src │ ├── InertialEnergy.cu │ ├── MassSpringEnergy.cu │ ├── device_uti.cu │ ├── main.cpp │ ├── simulator.cu │ ├── square_mesh.cpp │ └── uti.cu ├── 2_dirichlet ├── CMakeLists.txt ├── include │ ├── GravityEnergy.h │ ├── InertialEnergy.h │ ├── MassSpringEnergy.h │ ├── device_uti.h │ ├── simulator.h │ ├── square_mesh.h │ └── uti.h └── src │ ├── GravityEnergy.cu │ ├── InertialEnergy.cu │ ├── MassSpringEnergy.cu │ ├── device_uti.cu │ ├── main.cpp │ ├── simulator.cu │ ├── square_mesh.cpp │ └── uti.cu ├── 3_contact ├── CMakeLists.txt ├── include │ ├── BarrierEnergy.h │ ├── GravityEnergy.h │ ├── InertialEnergy.h │ ├── MassSpringEnergy.h │ ├── device_uti.h │ ├── simulator.h │ ├── square_mesh.h │ └── uti.h └── src │ ├── BarrierEnergy.cu │ ├── GravityEnergy.cu │ ├── InertialEnergy.cu │ ├── MassSpringEnergy.cu │ ├── device_uti.cu │ ├── main.cpp │ ├── simulator.cu │ ├── square_mesh.cpp │ └── uti.cu ├── 4_friction ├── CMakeLists.txt ├── include │ ├── BarrierEnergy.h │ ├── FrictionEnergy.h │ ├── GravityEnergy.h │ ├── InertialEnergy.h │ ├── MassSpringEnergy.h │ ├── device_uti.h │ ├── simulator.h │ ├── square_mesh.h │ └── uti.h └── src │ ├── BarrierEnergy.cu │ ├── FrictionEnergy.cu │ ├── GravityEnergy.cu │ ├── InertialEnergy.cu │ ├── MassSpringEnergy.cu │ ├── device_uti.cu │ ├── main.cpp │ ├── simulator.cu │ ├── square_mesh.cpp │ └── uti.cu ├── 5_mov_dirichlet ├── CMakeLists.txt ├── include │ ├── BarrierEnergy.h │ ├── FrictionEnergy.h │ ├── GravityEnergy.h │ ├── InertialEnergy.h │ ├── MassSpringEnergy.h │ ├── SparseMatrix.h │ ├── SpringEnergy.h │ ├── device_uti.h │ ├── simulator.h │ ├── square_mesh.h │ └── uti.h └── src │ ├── BarrierEnergy.cu │ ├── FrictionEnergy.cu │ ├── GravityEnergy.cu │ ├── InertialEnergy.cu │ ├── MassSpringEnergy.cu │ ├── SpringEnergy.cu │ ├── device_uti.cu │ ├── main.cpp │ ├── simulator.cu │ ├── square_mesh.cpp │ └── uti.cu ├── 6_inv_free ├── CMakeLists.txt ├── include │ ├── BarrierEnergy.h │ ├── FrictionEnergy.h │ ├── GravityEnergy.h │ ├── InertialEnergy.h │ ├── NeoHookeanEnergy.h │ ├── NeoHookean_auto.h │ ├── SpringEnergy.h │ ├── device_uti.h │ ├── simulator.h │ ├── square_mesh.h │ └── uti.h └── src │ ├── BarrierEnergy.cu │ ├── FrictionEnergy.cu │ ├── GravityEnergy.cu │ ├── InertialEnergy.cu │ ├── NeoHookeanEnergy.cu │ ├── NeoHookean_auto.cu │ ├── SpringEnergy.cu │ ├── device_uti.cu │ ├── main.cpp │ ├── simulator.cu │ ├── square_mesh.cpp │ └── uti.cu ├── 7_self_contact ├── CMakeLists.txt ├── include │ ├── BarrierEnergy.h │ ├── FrictionEnergy.h │ ├── GravityEnergy.h │ ├── InertialEnergy.h │ ├── NeoHookeanEnergy.h │ ├── NeoHookean_auto.h │ ├── SparseMatrix.h │ ├── SpringEnergy.h │ ├── device_uti.h │ ├── distance.h │ ├── simulator.h │ ├── square_mesh.h │ └── uti.h └── src │ ├── BarrierEnergy.cu │ ├── FrictionEnergy.cu │ ├── GravityEnergy.cu │ ├── InertialEnergy.cu │ ├── NeoHookeanEnergy.cu │ ├── NeoHookean_auto.cu │ ├── SpringEnergy.cu │ ├── device_uti.cu │ ├── distance │ ├── CCD.cu │ ├── PointEdgeDistance.cu │ ├── PointLineDistance.cu │ └── PointPointDistance.cu │ ├── main.cpp │ ├── simulator.cu │ ├── square_mesh.cpp │ └── uti.cu ├── 8_self_friction ├── CMakeLists.txt ├── include │ ├── BarrierEnergy.h │ ├── FrictionEnergy.h │ ├── GravityEnergy.h │ ├── InertialEnergy.h │ ├── NeoHookeanEnergy.h │ ├── NeoHookean_auto.h │ ├── SparseMatrix.h │ ├── SpringEnergy.h │ ├── device_uti.h │ ├── distance.h │ ├── simulator.h │ ├── square_mesh.h │ └── uti.h └── src │ ├── BarrierEnergy.cu │ ├── FrictionEnergy.cu │ ├── GravityEnergy.cu │ ├── InertialEnergy.cu │ ├── NeoHookeanEnergy.cu │ ├── NeoHookean_auto.cu │ ├── SpringEnergy.cu │ ├── device_uti.cu │ ├── distance │ ├── CCD.cu │ ├── PointEdgeDistance.cu │ ├── PointLineDistance.cu │ └── PointPointDistance.cu │ ├── main.cpp │ ├── simulator.cu │ ├── square_mesh.cpp │ └── uti.cu └── CMakeLists.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # make cache 2 | .vscode/ 3 | build/ 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "muda"] 2 | path = muda 3 | url = https://github.com/MuGdxy/muda.git 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20) 2 | 3 | project(Solid_Sim_Muda LANGUAGES CXX CUDA) 4 | option(BUILD_SHARED_LIBS "Build shared libraries" OFF) 5 | # set MUDA_BUILD_EXAMPLE to OFF for the subdirectory 6 | set(MUDA_BUILD_EXAMPLE OFF CACHE BOOL "" FORCE) 7 | 8 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 9 | add_subdirectory(muda) 10 | 11 | 12 | include(FetchContent) 13 | FetchContent_Declare(SFML 14 | GIT_REPOSITORY https://github.com/SFML/SFML.git 15 | GIT_TAG 2.6.x) 16 | FetchContent_MakeAvailable(SFML) 17 | set(CMAKE_CUDA_ARCHITECTURES 75) 18 | set(CMAKE_CXX_STANDARD 17) 19 | 20 | find_package(Eigen3 REQUIRED ) 21 | 22 | if(Eigen3_FOUND) 23 | message(STATUS "Eigen3 found (include: ${EIGEN3_INCLUDE_DIR}, version: ${EIGEN3_VERSION_STRING})") 24 | else() 25 | message(FATAL_ERROR "Eigen3 not found") 26 | endif() 27 | 28 | include_directories(${EIGEN3_INCLUDE_DIR}) 29 | 30 | include_directories(/usr/include) 31 | 32 | add_subdirectory(simulators) 33 | add_compile_options(/W4) 34 | add_compile_options(/wd4100) 35 | add_compile_options(/wd4244) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MUDA-based Solid Simulation Tutorial 2 | This is a tutorial for elastodynamic contact simulation using [MUDA](https://github.com/MuGdxy/muda) (a [CUDA](https://developer.nvidia.com/cuda-toolkit) programming paradigm). 3 | 4 | The basic architecture of the simulators follows [@liminchen](https://github.com/liminchen)'s Numpy version [solid-sim-tutorial](https://github.com/phys-sim-book/solid-sim-tutorial). 5 | 6 | The tutorial (written by a beginner of simulation) aims at helping beginners learn how to write simple CUDA codes for efficient solid simulations on the GPU. An introductory section for the first example of this tutorial can be found at [https://phys-sim-book.github.io/lec4.6-gpu_accel.html](https://phys-sim-book.github.io/lec4.6-gpu_accel.html). 7 | 8 | ## Usage 9 | 1. Clone the repository 10 | ```bash 11 | git clone https://github.com/Roushelfy/solid-sim-muda 12 | cd solid-sim-muda 13 | git submodule update --init --recursive 14 | ``` 15 | 16 | 2. build with cmake 17 | ```bash 18 | mkdir build 19 | cd build 20 | cmake .. 21 | cmake --build . 22 | ``` 23 | 24 | ## Requirements 25 | Eigen3==3.4.0 26 | 27 | CMake>=3.29 28 | 29 | CUDA>=11.0 30 | 31 | ## Examples 32 | 33 | ### 1. Simple Mass-Spring System 34 | ![Simple Mass-Spring System](./img/1.png) 35 | ### 2. Dirichlet Boundary Condition 36 | ![Dirichlet Boundary Condition](./img/2.png) 37 | ### 3. Contact 38 | ![Contact](./img/3.png) 39 | ### 4. Friction 40 | ![Friction](./img/4.png) 41 | ### 5. Moving Dirichlet Boundary Condition 42 | ![Moving Dirichlet Boundary](./img/5.png) 43 | ### 6. Neohookean Solids 44 | ![Neohookean Model](./img/6.png) 45 | ### 7. Neohookean Solids with Self-Contact 46 | ![Neohookean Model with Self Collision](./img/7.png) 47 | ### 8. Neohookean Solids with Frictional Self-Contact 48 | ![Neohookean Model with Self Friction](./img/8.png) 49 | -------------------------------------------------------------------------------- /img/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phys-sim-book/solid-sim-tutorial-gpu/830cf4a49f9a059fcb9a3de3a71dd52ff80035d6/img/1.png -------------------------------------------------------------------------------- /img/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phys-sim-book/solid-sim-tutorial-gpu/830cf4a49f9a059fcb9a3de3a71dd52ff80035d6/img/2.png -------------------------------------------------------------------------------- /img/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phys-sim-book/solid-sim-tutorial-gpu/830cf4a49f9a059fcb9a3de3a71dd52ff80035d6/img/3.png -------------------------------------------------------------------------------- /img/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phys-sim-book/solid-sim-tutorial-gpu/830cf4a49f9a059fcb9a3de3a71dd52ff80035d6/img/4.png -------------------------------------------------------------------------------- /img/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phys-sim-book/solid-sim-tutorial-gpu/830cf4a49f9a059fcb9a3de3a71dd52ff80035d6/img/5.png -------------------------------------------------------------------------------- /img/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phys-sim-book/solid-sim-tutorial-gpu/830cf4a49f9a059fcb9a3de3a71dd52ff80035d6/img/6.png -------------------------------------------------------------------------------- /img/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phys-sim-book/solid-sim-tutorial-gpu/830cf4a49f9a059fcb9a3de3a71dd52ff80035d6/img/7.png -------------------------------------------------------------------------------- /img/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phys-sim-book/solid-sim-tutorial-gpu/830cf4a49f9a059fcb9a3de3a71dd52ff80035d6/img/8.png -------------------------------------------------------------------------------- /simulators/1_mass_spring/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(1_mass_spring) 2 | 3 | target_compile_options(1_mass_spring PRIVATE -g) 4 | set_target_properties(1_mass_spring PROPERTIES CUDA_SEPARABLE_COMPILATION ON) 5 | 6 | target_link_libraries(1_mass_spring PRIVATE muda cusolver cublas cusparse ) 7 | 8 | option(BUILD_SHARED_LIBS "Build shared libraries" OFF) 9 | 10 | include_directories(include) 11 | 12 | file(GLOB_RECURSE 1_mass_spring_CU_SOURCE CONFIGURE_DEPENDS "src/*.cu") 13 | target_sources(1_mass_spring PRIVATE ${1_mass_spring_CU_SOURCE}) 14 | 15 | file(GLOB_RECURSE 1_mass_spring_CPP_SOURCE CONFIGURE_DEPENDS "src/*.cpp") 16 | target_sources(1_mass_spring PRIVATE ${1_mass_spring_CPP_SOURCE}) 17 | 18 | target_link_libraries(1_mass_spring PRIVATE sfml-graphics) 19 | -------------------------------------------------------------------------------- /simulators/1_mass_spring/include/InertialEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "square_mesh.h" 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace muda; 11 | 12 | template 13 | class InertialEnergy 14 | { 15 | public: 16 | InertialEnergy(int N, T m); 17 | InertialEnergy(); 18 | ~InertialEnergy(); 19 | InertialEnergy(InertialEnergy &&rhs); 20 | InertialEnergy(const InertialEnergy &rhs); 21 | InertialEnergy &operator=(InertialEnergy &&rhs); 22 | InertialEnergy &operator=(const InertialEnergy &rhs); 23 | 24 | void update_x(const DeviceBuffer &x); 25 | void generate_hess(); 26 | void update_x_tilde(const DeviceBuffer &x_tilde); 27 | void update_m(T m); 28 | T val(); // Calculate the value of the energy 29 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 30 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 31 | 32 | private: 33 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 34 | struct Impl; 35 | // The private pointer to the implementation class Impl 36 | std::unique_ptr pimpl_; 37 | }; 38 | -------------------------------------------------------------------------------- /simulators/1_mass_spring/include/MassSpringEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "uti.h" 6 | 7 | template 8 | class MassSpringEnergy 9 | { 10 | public: 11 | MassSpringEnergy(const std::vector &x, const std::vector &e, const std::vector &l2, const std::vector &k); 12 | MassSpringEnergy(); 13 | ~MassSpringEnergy(); 14 | MassSpringEnergy(MassSpringEnergy &&rhs); 15 | MassSpringEnergy(const MassSpringEnergy &rhs); 16 | MassSpringEnergy &operator=(MassSpringEnergy &&rhs); 17 | 18 | void update_x(const DeviceBuffer &x); 19 | void update_e(const std::vector &e); 20 | void update_l2(const std::vector &l2); 21 | void update_k(const std::vector &k); 22 | T val(); // Calculate the value of the energy 23 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 24 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 25 | 26 | private: 27 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 28 | struct Impl; 29 | // The private pointer to the implementation class Impl 30 | std::unique_ptr pimpl_; 31 | }; -------------------------------------------------------------------------------- /simulators/1_mass_spring/include/device_uti.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | // utility functions 6 | template 7 | T devicesum(const muda::DeviceBuffer &buffer); 8 | 9 | template 10 | void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); -------------------------------------------------------------------------------- /simulators/1_mass_spring/include/simulator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "square_mesh.h" 6 | #include 7 | 8 | // ANCHOR: Header 9 | template 10 | class MassSpringSimulator 11 | { 12 | public: 13 | MassSpringSimulator(); 14 | ~MassSpringSimulator(); 15 | MassSpringSimulator(MassSpringSimulator &&rhs); 16 | MassSpringSimulator &operator=(MassSpringSimulator &&rhs); 17 | MassSpringSimulator(T rho, T side_len, T initial_stretch, T K, T h, T tol, int n_seg); 18 | void run(); 19 | 20 | private: 21 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 22 | struct Impl; 23 | // The private pointer to the implementation class Impl 24 | std::unique_ptr pimpl_; 25 | }; 26 | // ANCHOR_END: Header -------------------------------------------------------------------------------- /simulators/1_mass_spring/include/square_mesh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | // Function to generate mesh points and edges 6 | template 7 | void generate(T side_length, int n_seg, std::vector &x, std::vector &e); 8 | -------------------------------------------------------------------------------- /simulators/1_mass_spring/include/uti.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace muda; 8 | 9 | template 10 | DeviceBuffer add_vector(const DeviceBuffer &a, const DeviceBuffer &b, const T &factor1 = 1, const T &factor2 = 1); 11 | 12 | template 13 | DeviceBuffer mult_vector(const DeviceBuffer &a, const T &b); 14 | 15 | template 16 | DeviceTripletMatrix add_triplet(const DeviceTripletMatrix &a, const DeviceTripletMatrix &b, const T &factor1 = 1, const T &factor2 = 1); 17 | 18 | template 19 | T max_vector(const DeviceBuffer &a); 20 | 21 | template 22 | void search_dir(const DeviceBuffer &grad, const DeviceTripletMatrix &hess, DeviceBuffer &dir); 23 | 24 | template 25 | void display_vec(const DeviceBuffer &vec); 26 | -------------------------------------------------------------------------------- /simulators/1_mass_spring/src/InertialEnergy.cu: -------------------------------------------------------------------------------- 1 | #include "InertialEnergy.h" 2 | #include "uti.h" 3 | #include 4 | #include 5 | #include "device_uti.h" 6 | using namespace muda; 7 | 8 | template 9 | struct InertialEnergy::Impl 10 | { 11 | DeviceBuffer device_x, device_x_tilde, device_grad; 12 | DeviceTripletMatrix device_hess; 13 | int N; 14 | T m, val; 15 | Impl(int N, T m); 16 | }; 17 | template 18 | InertialEnergy::InertialEnergy() = default; 19 | 20 | template 21 | InertialEnergy::~InertialEnergy() = default; 22 | 23 | template 24 | InertialEnergy::InertialEnergy(InertialEnergy &&rhs) = default; 25 | 26 | template 27 | InertialEnergy &InertialEnergy::operator=(InertialEnergy &&rhs) = default; 28 | 29 | template 30 | InertialEnergy::InertialEnergy(const InertialEnergy &rhs) 31 | : pimpl_{std::make_unique(*rhs.pimpl_)} {} 32 | 33 | template 34 | InertialEnergy::InertialEnergy(int N, T m) : pimpl_{std::make_unique(N, m)} 35 | { 36 | generate_hess(); 37 | } 38 | 39 | template 40 | InertialEnergy::Impl::Impl(int N_, T m_) : N(N_), m(m_) 41 | { 42 | device_x.resize(N * dim); 43 | device_x_tilde.resize(N * dim); 44 | device_hess.resize_triplets(N * dim); 45 | device_hess.reshape(N * dim, N * dim); 46 | device_grad.resize(N * dim); 47 | } 48 | template 49 | void InertialEnergy::generate_hess() 50 | { 51 | auto &device_hess = pimpl_->device_hess; 52 | auto m = pimpl_->m; 53 | auto N = pimpl_->N; 54 | ParallelFor(256) 55 | .apply(N * dim, 56 | [device_hess_row_indices = device_hess.row_indices().viewer(), device_hess_col_indices = device_hess.col_indices().viewer(), 57 | device_hess_values = device_hess.values().viewer(), m] __device__(int i) mutable 58 | { 59 | device_hess_row_indices(i) = i; 60 | device_hess_col_indices(i) = i; 61 | device_hess_values(i) = m; 62 | }) 63 | .wait(); 64 | } 65 | 66 | template 67 | void InertialEnergy::update_x(const DeviceBuffer &x) 68 | { 69 | pimpl_->device_x.view().copy_from(x); 70 | } 71 | 72 | template 73 | void InertialEnergy::update_x_tilde(const DeviceBuffer &x_tilde) 74 | { 75 | pimpl_->device_x_tilde.view().copy_from(x_tilde); 76 | } 77 | 78 | template 79 | void InertialEnergy::update_m(T m) 80 | { 81 | pimpl_->m = m; 82 | } 83 | 84 | template 85 | T InertialEnergy::val() 86 | { 87 | auto &device_x = pimpl_->device_x; 88 | auto &device_x_tilde = pimpl_->device_x_tilde; 89 | auto &m = pimpl_->m; 90 | auto N = pimpl_->N * dim; 91 | DeviceBuffer device_val(N); 92 | ParallelFor(256) 93 | .apply(N, 94 | [device_val = device_val.viewer(), device_x = device_x.cviewer(), device_x_tilde = device_x_tilde.cviewer(), m] __device__(int i) mutable 95 | { 96 | device_val(i) = 0.5 * m * (device_x(i) - device_x_tilde(i)) * (device_x(i) - device_x_tilde(i)); 97 | }) 98 | .wait(); 99 | return devicesum(device_val); 100 | } 101 | 102 | template 103 | const DeviceBuffer &InertialEnergy::grad() 104 | { 105 | auto &device_x = pimpl_->device_x; 106 | auto &device_x_tilde = pimpl_->device_x_tilde; 107 | auto m = pimpl_->m; 108 | auto N = pimpl_->N * dim; 109 | auto &device_grad = pimpl_->device_grad; 110 | ParallelFor(256) 111 | .apply(N, 112 | [device_x = device_x.cviewer(), device_x_tilde = device_x_tilde.cviewer(), m, N, device_grad = device_grad.viewer()] __device__(int i) mutable 113 | { 114 | device_grad(i) = m * (device_x(i) - device_x_tilde(i)); 115 | }) 116 | .wait(); 117 | return device_grad; 118 | } // Calculate the gradient of the energy 119 | 120 | template 121 | const DeviceTripletMatrix &InertialEnergy::hess() 122 | { 123 | return pimpl_->device_hess; 124 | } // Calculate the Hessian matrix of the energy 125 | 126 | template class InertialEnergy; 127 | template class InertialEnergy; 128 | template class InertialEnergy; 129 | template class InertialEnergy; 130 | -------------------------------------------------------------------------------- /simulators/1_mass_spring/src/device_uti.cu: -------------------------------------------------------------------------------- 1 | #include "device_uti.h" 2 | using namespace muda; 3 | 4 | template 5 | T devicesum(const DeviceBuffer &buffer) 6 | { 7 | T sum = 0.0f; // Result of the reduction 8 | T *d_out; // Device memory to store the result of the reduction 9 | cudaMalloc(&d_out, sizeof(T)); // Allocate memory for the result 10 | 11 | // DeviceReduce is assumed to be part of the 'muda' library or similar 12 | DeviceReduce().Sum(buffer.data(), d_out, buffer.size()); 13 | 14 | // Copy the result back to the host 15 | cudaMemcpy(&sum, d_out, sizeof(T), cudaMemcpyDeviceToHost); 16 | 17 | // Clean up 18 | cudaFree(d_out); 19 | return sum; 20 | } 21 | template float devicesum(const DeviceBuffer &); 22 | template double devicesum(const DeviceBuffer &); 23 | 24 | template 25 | void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD) 26 | { 27 | Eigen::SelfAdjointEigenSolver> eigensolver(hess); 28 | Eigen::Matrix lam = eigensolver.eigenvalues(); 29 | Eigen::Matrix V = eigensolver.eigenvectors(); 30 | // set all negative eigenvalues to zero 31 | Eigen::Matrix lamDiag; 32 | lamDiag.setZero(); 33 | for (int i = 0; i < Size; i++) 34 | if (lam(i) > 0) 35 | lamDiag(i, i) = lam(i); 36 | 37 | Eigen::Matrix VT = V.transpose(); 38 | 39 | PSD = V * lamDiag * VT; 40 | } 41 | 42 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 43 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 44 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 45 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); -------------------------------------------------------------------------------- /simulators/1_mass_spring/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "simulator.h" 2 | 3 | int main() 4 | { 5 | double rho = 1000, k = 1e5, initial_stretch = 1.3, n_seg = 15, h = 0.004, side_len = 1, tol = 0.01; 6 | MassSpringSimulator simulator(rho, side_len, initial_stretch, k, h, tol, n_seg); 7 | simulator.run(); 8 | } -------------------------------------------------------------------------------- /simulators/1_mass_spring/src/square_mesh.cpp: -------------------------------------------------------------------------------- 1 | #include "square_mesh.h" 2 | template 3 | void generate(T side_length, int n_seg, std::vector &x, std::vector &e) 4 | { 5 | int dim = n_seg + 1; 6 | x.clear(); 7 | x.reserve(dim * dim * 2); // Preallocate space for all nodes 8 | 9 | T step = side_length / n_seg; 10 | 11 | // Populate the coordinates 12 | for (int i = 0; i < dim; i++) 13 | { 14 | for (int j = 0; j < dim; j++) 15 | { 16 | x.push_back(-side_length / 2 + i * step); 17 | x.push_back(-side_length / 2 + j * step); 18 | } 19 | } 20 | 21 | // Clear any existing data in e and reserve space for edges 22 | e.clear(); 23 | // Reserve space assuming maximum edge count (horizontal + vertical + 2*diagonal) 24 | e.reserve(2 * n_seg * (n_seg + 1) + 4 * n_seg * n_seg); 25 | 26 | // Horizontal edges 27 | for (int i = 0; i < n_seg; i++) 28 | { 29 | for (int j = 0; j < dim; j++) 30 | { 31 | e.push_back(i * dim + j); 32 | e.push_back((i + 1) * dim + j); 33 | } 34 | } 35 | 36 | // Vertical edges 37 | for (int i = 0; i < dim; i++) 38 | { 39 | for (int j = 0; j < n_seg; j++) 40 | { 41 | e.push_back(i * dim + j); 42 | e.push_back(i * dim + j + 1); 43 | } 44 | } 45 | 46 | // Diagonal edges 47 | for (int i = 0; i < n_seg; i++) 48 | { 49 | for (int j = 0; j < n_seg; j++) 50 | { 51 | e.push_back(i * dim + j); 52 | e.push_back((i + 1) * dim + j + 1); 53 | e.push_back((i + 1) * dim + j); 54 | e.push_back(i * dim + j + 1); 55 | } 56 | } 57 | } 58 | 59 | template void generate(float side_length, int n_seg, std::vector &x, std::vector &e); 60 | template void generate(double side_length, int n_seg, std::vector &x, std::vector &e); 61 | template void generate(long double side_length, int n_seg, std::vector &x, std::vector &e); 62 | -------------------------------------------------------------------------------- /simulators/2_dirichlet/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(2_dirichlet) 2 | 3 | target_compile_options(2_dirichlet PRIVATE -g) 4 | set_target_properties(2_dirichlet PROPERTIES CUDA_SEPARABLE_COMPILATION ON) 5 | 6 | target_link_libraries(2_dirichlet PRIVATE muda cusolver cublas cusparse ) 7 | 8 | option(BUILD_SHARED_LIBS "Build shared libraries" OFF) 9 | 10 | include_directories(include) 11 | 12 | file(GLOB_RECURSE 2_dirichlet_CU_SOURCE CONFIGURE_DEPENDS "src/*.cu") 13 | target_sources(2_dirichlet PRIVATE ${2_dirichlet_CU_SOURCE}) 14 | 15 | file(GLOB_RECURSE 2_dirichlet_CPP_SOURCE CONFIGURE_DEPENDS "src/*.cpp") 16 | target_sources(2_dirichlet PRIVATE ${2_dirichlet_CPP_SOURCE}) 17 | 18 | target_link_libraries(2_dirichlet PRIVATE sfml-graphics) 19 | -------------------------------------------------------------------------------- /simulators/2_dirichlet/include/GravityEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "square_mesh.h" 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace muda; 11 | 12 | template 13 | class GravityEnergy 14 | { 15 | public: 16 | GravityEnergy(int N, T m); 17 | GravityEnergy(); 18 | ~GravityEnergy(); 19 | GravityEnergy(GravityEnergy &&rhs); 20 | GravityEnergy(const GravityEnergy &rhs); 21 | GravityEnergy &operator=(GravityEnergy &&rhs); 22 | GravityEnergy &operator=(const GravityEnergy &rhs); 23 | 24 | void update_x(const DeviceBuffer &x); 25 | void update_x_tilde(const DeviceBuffer &x_tilde); 26 | void update_m(T m); 27 | T val(); // Calculate the value of the energy 28 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 29 | 30 | private: 31 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 32 | struct Impl; 33 | // The private pointer to the implementation class Impl 34 | std::unique_ptr pimpl_; 35 | }; 36 | -------------------------------------------------------------------------------- /simulators/2_dirichlet/include/InertialEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "square_mesh.h" 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace muda; 11 | 12 | template 13 | class InertialEnergy 14 | { 15 | public: 16 | InertialEnergy(int N, T m); 17 | InertialEnergy(); 18 | ~InertialEnergy(); 19 | InertialEnergy(InertialEnergy &&rhs); 20 | InertialEnergy(const InertialEnergy &rhs); 21 | InertialEnergy &operator=(InertialEnergy &&rhs); 22 | 23 | void update_x(const DeviceBuffer &x); 24 | void generate_hess(); 25 | void update_x_tilde(const DeviceBuffer &x_tilde); 26 | void update_m(T m); 27 | T val(); // Calculate the value of the energy 28 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 29 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 30 | 31 | private: 32 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 33 | struct Impl; 34 | // The private pointer to the implementation class Impl 35 | std::unique_ptr pimpl_; 36 | }; 37 | -------------------------------------------------------------------------------- /simulators/2_dirichlet/include/MassSpringEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "uti.h" 6 | 7 | template 8 | class MassSpringEnergy 9 | { 10 | public: 11 | MassSpringEnergy(const std::vector &x, const std::vector &e, const std::vector &l2, const std::vector &k); 12 | MassSpringEnergy(); 13 | ~MassSpringEnergy(); 14 | MassSpringEnergy(MassSpringEnergy &&rhs); 15 | MassSpringEnergy(const MassSpringEnergy &rhs); 16 | MassSpringEnergy &operator=(MassSpringEnergy &&rhs); 17 | 18 | void update_x(const DeviceBuffer &x); 19 | void update_e(const std::vector &e); 20 | void update_l2(const std::vector &l2); 21 | void update_k(const std::vector &k); 22 | T val(); // Calculate the value of the energy 23 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 24 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 25 | 26 | private: 27 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 28 | struct Impl; 29 | // The private pointer to the implementation class Impl 30 | std::unique_ptr pimpl_; 31 | }; -------------------------------------------------------------------------------- /simulators/2_dirichlet/include/device_uti.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | // utility functions 6 | template 7 | T devicesum(const muda::DeviceBuffer &buffer); 8 | 9 | template 10 | void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); -------------------------------------------------------------------------------- /simulators/2_dirichlet/include/simulator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "square_mesh.h" 6 | #include 7 | template 8 | class DirichletSimulator 9 | { 10 | public: 11 | DirichletSimulator(); 12 | ~DirichletSimulator(); 13 | DirichletSimulator(DirichletSimulator &&rhs); 14 | DirichletSimulator &operator=(DirichletSimulator &&rhs); 15 | DirichletSimulator(T rho, T side_len, T initial_stretch, T K, T h, T tol, int n_seg); 16 | void run(); 17 | 18 | private: 19 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 20 | struct Impl; 21 | // The private pointer to the implementation class Impl 22 | std::unique_ptr pimpl_; 23 | }; 24 | -------------------------------------------------------------------------------- /simulators/2_dirichlet/include/square_mesh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | // Function to generate mesh points and edges 6 | template 7 | void generate(T side_length, int n_seg, std::vector &x, std::vector &e); 8 | -------------------------------------------------------------------------------- /simulators/2_dirichlet/include/uti.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace muda; 8 | 9 | template 10 | DeviceBuffer add_vector(const DeviceBuffer &a, const DeviceBuffer &b, const T &factor1 = 1, const T &factor2 = 1); 11 | 12 | template 13 | DeviceBuffer mult_vector(const DeviceBuffer &a, const T &b); 14 | 15 | template 16 | DeviceTripletMatrix add_triplet(const DeviceTripletMatrix &a, const DeviceTripletMatrix &b, const T &factor1 = 1, const T &factor2 = 1); 17 | 18 | template 19 | T max_vector(const DeviceBuffer &a); 20 | 21 | template 22 | void search_dir(const DeviceBuffer &grad, const DeviceTripletMatrix &hess, DeviceBuffer &dir, const DeviceBuffer &DBC); 23 | 24 | template 25 | void display_vec(const DeviceBuffer &vec); 26 | 27 | template 28 | void set_DBC(DeviceBuffer &grad, DeviceCSRMatrix &hess, const DeviceBuffer &DBC); -------------------------------------------------------------------------------- /simulators/2_dirichlet/src/GravityEnergy.cu: -------------------------------------------------------------------------------- 1 | #include "GravityEnergy.h" 2 | #include "uti.h" 3 | #include 4 | #include 5 | #include "device_uti.h" 6 | #define GRAVITY -9.81 7 | using namespace muda; 8 | 9 | template 10 | struct GravityEnergy::Impl 11 | { 12 | DeviceBuffer device_x, device_grad; 13 | int N; 14 | T m, val; 15 | Impl(int N, T m); 16 | }; 17 | template 18 | GravityEnergy::GravityEnergy() = default; 19 | 20 | template 21 | GravityEnergy::~GravityEnergy() = default; 22 | 23 | template 24 | GravityEnergy::GravityEnergy(GravityEnergy &&rhs) = default; 25 | 26 | template 27 | GravityEnergy &GravityEnergy::operator=(GravityEnergy &&rhs) = default; 28 | 29 | template 30 | GravityEnergy::GravityEnergy(const GravityEnergy &rhs) 31 | : pimpl_{std::make_unique(*rhs.pimpl_)} {} 32 | 33 | template 34 | GravityEnergy::GravityEnergy(int N, T m) : pimpl_{std::make_unique(N, m)} 35 | { 36 | } 37 | 38 | template 39 | GravityEnergy::Impl::Impl(int N_, T m_) : N(N_), m(m_) 40 | { 41 | device_x.resize(N * dim); 42 | device_grad.resize(N * dim); 43 | } 44 | 45 | template 46 | void GravityEnergy::update_x(const DeviceBuffer &x) 47 | { 48 | pimpl_->device_x.view().copy_from(x); 49 | } 50 | 51 | template 52 | void GravityEnergy::update_m(T m) 53 | { 54 | pimpl_->m = m; 55 | } 56 | 57 | template 58 | T GravityEnergy::val() 59 | { 60 | auto &device_x = pimpl_->device_x; 61 | auto &m = pimpl_->m; 62 | auto N = pimpl_->N * dim; 63 | DeviceBuffer device_val(N); 64 | ParallelFor(256) 65 | .apply(N, 66 | [device_val = device_val.viewer(), device_x = device_x.cviewer(), m] __device__(int i) mutable 67 | { 68 | device_val(i) = i % dim == 1 ? -m * GRAVITY * device_x(i) : 0; 69 | }) 70 | .wait(); 71 | return devicesum(device_val); 72 | } 73 | 74 | template 75 | const DeviceBuffer &GravityEnergy::grad() 76 | { 77 | auto &device_x = pimpl_->device_x; 78 | auto m = pimpl_->m; 79 | auto N = pimpl_->N * dim; 80 | auto &device_grad = pimpl_->device_grad; 81 | ParallelFor(256) 82 | .apply(N, 83 | [device_x = device_x.cviewer(), m, N, device_grad = device_grad.viewer()] __device__(int i) mutable 84 | { 85 | device_grad(i) = i % dim == 1 ? -m * GRAVITY : 0; 86 | }) 87 | .wait(); 88 | // display_vec(device_grad); 89 | return device_grad; 90 | } // Calculate the gradient of the energy 91 | 92 | template class GravityEnergy; 93 | template class GravityEnergy; 94 | template class GravityEnergy; 95 | template class GravityEnergy; 96 | -------------------------------------------------------------------------------- /simulators/2_dirichlet/src/InertialEnergy.cu: -------------------------------------------------------------------------------- 1 | #include "InertialEnergy.h" 2 | #include "uti.h" 3 | #include 4 | #include 5 | #include "device_uti.h" 6 | 7 | using namespace muda; 8 | 9 | template 10 | struct InertialEnergy::Impl 11 | { 12 | DeviceBuffer device_x, device_x_tilde, device_grad; 13 | DeviceTripletMatrix device_hess; 14 | int N; 15 | T m, val; 16 | Impl(int N, T m); 17 | }; 18 | template 19 | InertialEnergy::InertialEnergy() = default; 20 | 21 | template 22 | InertialEnergy::~InertialEnergy() = default; 23 | 24 | template 25 | InertialEnergy::InertialEnergy(InertialEnergy &&rhs) = default; 26 | 27 | template 28 | InertialEnergy &InertialEnergy::operator=(InertialEnergy &&rhs) = default; 29 | 30 | template 31 | InertialEnergy::InertialEnergy(const InertialEnergy &rhs) 32 | : pimpl_{std::make_unique(*rhs.pimpl_)} {} 33 | 34 | template 35 | InertialEnergy::InertialEnergy(int N, T m) : pimpl_{std::make_unique(N, m)} 36 | { 37 | generate_hess(); 38 | } 39 | 40 | template 41 | InertialEnergy::Impl::Impl(int N_, T m_) : N(N_), m(m_) 42 | { 43 | device_x.resize(N * dim); 44 | device_x_tilde.resize(N * dim); 45 | device_hess.resize_triplets(N * dim); 46 | device_hess.reshape(N * dim, N * dim); 47 | device_grad.resize(N * dim); 48 | } 49 | template 50 | void InertialEnergy::generate_hess() 51 | { 52 | auto &device_hess = pimpl_->device_hess; 53 | auto m = pimpl_->m; 54 | auto N = pimpl_->N; 55 | ParallelFor(256) 56 | .apply(N * dim, 57 | [device_hess_row_indices = device_hess.row_indices().viewer(), device_hess_col_indices = device_hess.col_indices().viewer(), 58 | device_hess_values = device_hess.values().viewer(), m] __device__(int i) mutable 59 | { 60 | device_hess_row_indices(i) = i; 61 | device_hess_col_indices(i) = i; 62 | device_hess_values(i) = m; 63 | }) 64 | .wait(); 65 | } 66 | 67 | template 68 | void InertialEnergy::update_x(const DeviceBuffer &x) 69 | { 70 | pimpl_->device_x.view().copy_from(x); 71 | } 72 | 73 | template 74 | void InertialEnergy::update_x_tilde(const DeviceBuffer &x_tilde) 75 | { 76 | pimpl_->device_x_tilde.view().copy_from(x_tilde); 77 | } 78 | 79 | template 80 | void InertialEnergy::update_m(T m) 81 | { 82 | pimpl_->m = m; 83 | } 84 | 85 | template 86 | T InertialEnergy::val() 87 | { 88 | auto &device_x = pimpl_->device_x; 89 | auto &device_x_tilde = pimpl_->device_x_tilde; 90 | auto &m = pimpl_->m; 91 | auto N = pimpl_->N * dim; 92 | DeviceBuffer device_val(N); 93 | ParallelFor(256) 94 | .apply(N, 95 | [device_val = device_val.viewer(), device_x = device_x.cviewer(), device_x_tilde = device_x_tilde.cviewer(), m] __device__(int i) mutable 96 | { 97 | device_val(i) = 0.5 * m * (device_x(i) - device_x_tilde(i)) * (device_x(i) - device_x_tilde(i)); 98 | }) 99 | .wait(); 100 | return devicesum(device_val); 101 | } 102 | 103 | template 104 | const DeviceBuffer &InertialEnergy::grad() 105 | { 106 | auto &device_x = pimpl_->device_x; 107 | auto &device_x_tilde = pimpl_->device_x_tilde; 108 | auto m = pimpl_->m; 109 | auto N = pimpl_->N * dim; 110 | auto &device_grad = pimpl_->device_grad; 111 | ParallelFor(256) 112 | .apply(N, 113 | [device_x = device_x.cviewer(), device_x_tilde = device_x_tilde.cviewer(), m, N, device_grad = device_grad.viewer()] __device__(int i) mutable 114 | { 115 | device_grad(i) = m * (device_x(i) - device_x_tilde(i)); 116 | }) 117 | .wait(); 118 | // display_vec(device_grad); 119 | return device_grad; 120 | } // Calculate the gradient of the energy 121 | 122 | template 123 | const DeviceTripletMatrix &InertialEnergy::hess() 124 | { 125 | return pimpl_->device_hess; 126 | } // Calculate the Hessian matrix of the energy 127 | 128 | template class InertialEnergy; 129 | template class InertialEnergy; 130 | template class InertialEnergy; 131 | template class InertialEnergy; 132 | -------------------------------------------------------------------------------- /simulators/2_dirichlet/src/device_uti.cu: -------------------------------------------------------------------------------- 1 | #include "device_uti.h" 2 | using namespace muda; 3 | 4 | template 5 | T devicesum(const DeviceBuffer &buffer) 6 | { 7 | T sum = 0.0f; // Result of the reduction 8 | T *d_out; // Device memory to store the result of the reduction 9 | cudaMalloc(&d_out, sizeof(T)); // Allocate memory for the result 10 | 11 | // DeviceReduce is assumed to be part of the 'muda' library or similar 12 | DeviceReduce().Sum(buffer.data(), d_out, buffer.size()); 13 | 14 | // Copy the result back to the host 15 | cudaMemcpy(&sum, d_out, sizeof(T), cudaMemcpyDeviceToHost); 16 | 17 | // Clean up 18 | cudaFree(d_out); 19 | return sum; 20 | } 21 | template float devicesum(const DeviceBuffer &); 22 | template double devicesum(const DeviceBuffer &); 23 | 24 | template 25 | void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD) 26 | { 27 | Eigen::SelfAdjointEigenSolver> eigensolver(hess); 28 | Eigen::Matrix lam = eigensolver.eigenvalues(); 29 | Eigen::Matrix V = eigensolver.eigenvectors(); 30 | // set all negative eigenvalues to zero 31 | Eigen::Matrix lamDiag; 32 | lamDiag.setZero(); 33 | for (int i = 0; i < Size; i++) 34 | if (lam(i) > 0) 35 | lamDiag(i, i) = lam(i); 36 | 37 | Eigen::Matrix VT = V.transpose(); 38 | 39 | PSD = V * lamDiag * VT; 40 | } 41 | 42 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 43 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 44 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 45 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); -------------------------------------------------------------------------------- /simulators/2_dirichlet/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "simulator.h" 2 | 3 | int main() 4 | { 5 | double rho = 1000, k = 1e3, initial_stretch = 1, n_seg = 20, h = 0.02, side_len = 1, tol = 0.01; 6 | // printf("Running mass-spring simulator with parameters: rho = %f, k = %f, initial_stretch = %f, n_seg = %d, h = %f, side_len = %f, tol = %f\n", rho, k, initial_stretch, n_seg, h, side_len, tol); 7 | DirichletSimulator simulator(rho, side_len, initial_stretch, k, h, tol, n_seg); 8 | simulator.run(); 9 | } -------------------------------------------------------------------------------- /simulators/2_dirichlet/src/square_mesh.cpp: -------------------------------------------------------------------------------- 1 | #include "square_mesh.h" 2 | template 3 | void generate(T side_length, int n_seg, std::vector &x, std::vector &e) 4 | { 5 | int dim = n_seg + 1; 6 | x.clear(); 7 | x.reserve(dim * dim * 2); // Preallocate space for all nodes 8 | 9 | T step = side_length / n_seg; 10 | 11 | // Populate the coordinates 12 | for (int i = 0; i < dim; i++) 13 | { 14 | for (int j = 0; j < dim; j++) 15 | { 16 | x.push_back(-side_length / 2 + i * step); 17 | x.push_back(-side_length / 2 + j * step); 18 | } 19 | } 20 | 21 | // Clear any existing data in e and reserve space for edges 22 | e.clear(); 23 | // Reserve space assuming maximum edge count (horizontal + vertical + 2*diagonal) 24 | e.reserve(2 * n_seg * (n_seg + 1) + 4 * n_seg * n_seg); 25 | 26 | // Horizontal edges 27 | for (int i = 0; i < n_seg; i++) 28 | { 29 | for (int j = 0; j < dim; j++) 30 | { 31 | e.push_back(i * dim + j); 32 | e.push_back((i + 1) * dim + j); 33 | } 34 | } 35 | 36 | // Vertical edges 37 | for (int i = 0; i < dim; i++) 38 | { 39 | for (int j = 0; j < n_seg; j++) 40 | { 41 | e.push_back(i * dim + j); 42 | e.push_back(i * dim + j + 1); 43 | } 44 | } 45 | 46 | // Diagonal edges 47 | for (int i = 0; i < n_seg; i++) 48 | { 49 | for (int j = 0; j < n_seg; j++) 50 | { 51 | e.push_back(i * dim + j); 52 | e.push_back((i + 1) * dim + j + 1); 53 | e.push_back((i + 1) * dim + j); 54 | e.push_back(i * dim + j + 1); 55 | } 56 | } 57 | } 58 | 59 | template void generate(float side_length, int n_seg, std::vector &x, std::vector &e); 60 | template void generate(double side_length, int n_seg, std::vector &x, std::vector &e); 61 | template void generate(long double side_length, int n_seg, std::vector &x, std::vector &e); 62 | -------------------------------------------------------------------------------- /simulators/3_contact/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(3_contact) 2 | 3 | target_compile_options(3_contact PRIVATE -g) 4 | set_target_properties(3_contact PROPERTIES CUDA_SEPARABLE_COMPILATION ON) 5 | 6 | target_link_libraries(3_contact PRIVATE muda cusolver cublas cusparse ) 7 | 8 | option(BUILD_SHARED_LIBS "Build shared libraries" OFF) 9 | 10 | include_directories(include) 11 | 12 | file(GLOB_RECURSE 3_contact_CU_SOURCE CONFIGURE_DEPENDS "src/*.cu") 13 | target_sources(3_contact PRIVATE ${3_contact_CU_SOURCE}) 14 | 15 | file(GLOB_RECURSE 3_contact_CPP_SOURCE CONFIGURE_DEPENDS "src/*.cpp") 16 | target_sources(3_contact PRIVATE ${3_contact_CPP_SOURCE}) 17 | 18 | target_link_libraries(3_contact PRIVATE sfml-graphics) 19 | -------------------------------------------------------------------------------- /simulators/3_contact/include/BarrierEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "uti.h" 6 | 7 | template 8 | class BarrierEnergy 9 | { 10 | public: 11 | BarrierEnergy(const std::vector &x, const std::vector &contact_area, T y_ground); 12 | BarrierEnergy(); 13 | ~BarrierEnergy(); 14 | BarrierEnergy(BarrierEnergy &&rhs); 15 | BarrierEnergy(const BarrierEnergy &rhs); 16 | BarrierEnergy &operator=(BarrierEnergy &&rhs); 17 | 18 | void update_x(const DeviceBuffer &x); 19 | T val(); // Calculate the value of the energy 20 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 21 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 22 | T init_step_size(const DeviceBuffer &p); // Calculate the initial step size for the line search 23 | 24 | private: 25 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 26 | struct Impl; 27 | // The private pointer to the implementation class Impl 28 | std::unique_ptr pimpl_; 29 | }; -------------------------------------------------------------------------------- /simulators/3_contact/include/GravityEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "square_mesh.h" 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace muda; 11 | 12 | template 13 | class GravityEnergy 14 | { 15 | public: 16 | GravityEnergy(int N, T m); 17 | GravityEnergy(); 18 | ~GravityEnergy(); 19 | GravityEnergy(GravityEnergy &&rhs); 20 | GravityEnergy(const GravityEnergy &rhs); 21 | GravityEnergy &operator=(GravityEnergy &&rhs); 22 | GravityEnergy &operator=(const GravityEnergy &rhs); 23 | 24 | void update_x(const DeviceBuffer &x); 25 | void update_x_tilde(const DeviceBuffer &x_tilde); 26 | void update_m(T m); 27 | T val(); // Calculate the value of the energy 28 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 29 | 30 | private: 31 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 32 | struct Impl; 33 | // The private pointer to the implementation class Impl 34 | std::unique_ptr pimpl_; 35 | }; 36 | -------------------------------------------------------------------------------- /simulators/3_contact/include/InertialEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "square_mesh.h" 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace muda; 11 | 12 | template 13 | class InertialEnergy 14 | { 15 | public: 16 | InertialEnergy(int N, T m); 17 | InertialEnergy(); 18 | ~InertialEnergy(); 19 | InertialEnergy(InertialEnergy &&rhs); 20 | InertialEnergy(const InertialEnergy &rhs); 21 | InertialEnergy &operator=(InertialEnergy &&rhs); 22 | 23 | void update_x(const DeviceBuffer &x); 24 | void generate_hess(); 25 | void update_x_tilde(const DeviceBuffer &x_tilde); 26 | void update_m(T m); 27 | T val(); // Calculate the value of the energy 28 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 29 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 30 | 31 | private: 32 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 33 | struct Impl; 34 | // The private pointer to the implementation class Impl 35 | std::unique_ptr pimpl_; 36 | }; 37 | -------------------------------------------------------------------------------- /simulators/3_contact/include/MassSpringEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "uti.h" 6 | 7 | template 8 | class MassSpringEnergy 9 | { 10 | public: 11 | MassSpringEnergy(const std::vector &x, const std::vector &e, const std::vector &l2, const std::vector &k); 12 | MassSpringEnergy(); 13 | ~MassSpringEnergy(); 14 | MassSpringEnergy(MassSpringEnergy &&rhs); 15 | MassSpringEnergy(const MassSpringEnergy &rhs); 16 | MassSpringEnergy &operator=(MassSpringEnergy &&rhs); 17 | 18 | void update_x(const DeviceBuffer &x); 19 | void update_e(const std::vector &e); 20 | void update_l2(const std::vector &l2); 21 | void update_k(const std::vector &k); 22 | T val(); // Calculate the value of the energy 23 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 24 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 25 | 26 | private: 27 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 28 | struct Impl; 29 | // The private pointer to the implementation class Impl 30 | std::unique_ptr pimpl_; 31 | }; -------------------------------------------------------------------------------- /simulators/3_contact/include/device_uti.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | // utility functions 6 | template 7 | T devicesum(const muda::DeviceBuffer &buffer); 8 | 9 | template 10 | void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); -------------------------------------------------------------------------------- /simulators/3_contact/include/simulator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "square_mesh.h" 6 | #include 7 | template 8 | class ContactSimulator 9 | { 10 | public: 11 | ContactSimulator(); 12 | ~ContactSimulator(); 13 | ContactSimulator(ContactSimulator &&rhs); 14 | ContactSimulator &operator=(ContactSimulator &&rhs); 15 | ContactSimulator(T rho, T side_len, T initial_stretch, T K, T h, T tol, int n_seg); 16 | void run(); 17 | 18 | private: 19 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 20 | struct Impl; 21 | // The private pointer to the implementation class Impl 22 | std::unique_ptr pimpl_; 23 | }; 24 | -------------------------------------------------------------------------------- /simulators/3_contact/include/square_mesh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | // Function to generate mesh points and edges 6 | template 7 | void generate(T side_length, int n_seg, std::vector &x, std::vector &e); 8 | -------------------------------------------------------------------------------- /simulators/3_contact/include/uti.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace muda; 8 | 9 | template 10 | DeviceBuffer add_vector(const DeviceBuffer &a, const DeviceBuffer &b, const T &factor1 = 1, const T &factor2 = 1); 11 | 12 | template 13 | DeviceBuffer mult_vector(const DeviceBuffer &a, const T &b); 14 | 15 | template 16 | DeviceTripletMatrix add_triplet(const DeviceTripletMatrix &a, const DeviceTripletMatrix &b, const T &factor1 = 1, const T &factor2 = 1); 17 | 18 | template 19 | T max_vector(const DeviceBuffer &a); 20 | 21 | template 22 | T min_vector(const DeviceBuffer &a); 23 | 24 | template 25 | void search_dir(const DeviceBuffer &grad, const DeviceTripletMatrix &hess, DeviceBuffer &dir, const DeviceBuffer &DBC); 26 | 27 | template 28 | void display_vec(const DeviceBuffer &vec); 29 | 30 | template 31 | void set_DBC(DeviceBuffer &grad, DeviceCSRMatrix &hess, const DeviceBuffer &DBC); -------------------------------------------------------------------------------- /simulators/3_contact/src/GravityEnergy.cu: -------------------------------------------------------------------------------- 1 | #include "GravityEnergy.h" 2 | #include "uti.h" 3 | #include 4 | #include 5 | #include "device_uti.h" 6 | #define GRAVITY -9.81 7 | using namespace muda; 8 | 9 | template 10 | struct GravityEnergy::Impl 11 | { 12 | DeviceBuffer device_x, device_grad; 13 | int N; 14 | T m, val; 15 | Impl(int N, T m); 16 | }; 17 | template 18 | GravityEnergy::GravityEnergy() = default; 19 | 20 | template 21 | GravityEnergy::~GravityEnergy() = default; 22 | 23 | template 24 | GravityEnergy::GravityEnergy(GravityEnergy &&rhs) = default; 25 | 26 | template 27 | GravityEnergy &GravityEnergy::operator=(GravityEnergy &&rhs) = default; 28 | 29 | template 30 | GravityEnergy::GravityEnergy(const GravityEnergy &rhs) 31 | : pimpl_{std::make_unique(*rhs.pimpl_)} {} 32 | 33 | template 34 | GravityEnergy::GravityEnergy(int N, T m) : pimpl_{std::make_unique(N, m)} 35 | { 36 | } 37 | 38 | template 39 | GravityEnergy::Impl::Impl(int N_, T m_) : N(N_), m(m_) 40 | { 41 | device_x.resize(N * dim); 42 | device_grad.resize(N * dim); 43 | } 44 | 45 | template 46 | void GravityEnergy::update_x(const DeviceBuffer &x) 47 | { 48 | pimpl_->device_x.view().copy_from(x); 49 | } 50 | 51 | template 52 | void GravityEnergy::update_m(T m) 53 | { 54 | pimpl_->m = m; 55 | } 56 | 57 | template 58 | T GravityEnergy::val() 59 | { 60 | auto &device_x = pimpl_->device_x; 61 | auto &m = pimpl_->m; 62 | auto N = pimpl_->N * dim; 63 | DeviceBuffer device_val(N); 64 | ParallelFor(256) 65 | .apply(N, 66 | [device_val = device_val.viewer(), device_x = device_x.cviewer(), m] __device__(int i) mutable 67 | { 68 | device_val(i) = i % dim == 1 ? -m * GRAVITY * device_x(i) : 0; 69 | }) 70 | .wait(); 71 | return devicesum(device_val); 72 | } 73 | 74 | template 75 | const DeviceBuffer &GravityEnergy::grad() 76 | { 77 | auto &device_x = pimpl_->device_x; 78 | auto m = pimpl_->m; 79 | auto N = pimpl_->N * dim; 80 | auto &device_grad = pimpl_->device_grad; 81 | ParallelFor(256) 82 | .apply(N, 83 | [device_x = device_x.cviewer(), m, N, device_grad = device_grad.viewer()] __device__(int i) mutable 84 | { 85 | device_grad(i) = i % dim == 1 ? -m * GRAVITY : 0; 86 | }) 87 | .wait(); 88 | // display_vec(device_grad); 89 | return device_grad; 90 | } // Calculate the gradient of the energy 91 | 92 | template class GravityEnergy; 93 | template class GravityEnergy; 94 | template class GravityEnergy; 95 | template class GravityEnergy; 96 | -------------------------------------------------------------------------------- /simulators/3_contact/src/InertialEnergy.cu: -------------------------------------------------------------------------------- 1 | #include "InertialEnergy.h" 2 | #include "uti.h" 3 | #include 4 | #include 5 | #include "device_uti.h" 6 | 7 | using namespace muda; 8 | 9 | template 10 | struct InertialEnergy::Impl 11 | { 12 | DeviceBuffer device_x, device_x_tilde, device_grad; 13 | DeviceTripletMatrix device_hess; 14 | int N; 15 | T m, val; 16 | Impl(int N, T m); 17 | }; 18 | template 19 | InertialEnergy::InertialEnergy() = default; 20 | 21 | template 22 | InertialEnergy::~InertialEnergy() = default; 23 | 24 | template 25 | InertialEnergy::InertialEnergy(InertialEnergy &&rhs) = default; 26 | 27 | template 28 | InertialEnergy &InertialEnergy::operator=(InertialEnergy &&rhs) = default; 29 | 30 | template 31 | InertialEnergy::InertialEnergy(const InertialEnergy &rhs) 32 | : pimpl_{std::make_unique(*rhs.pimpl_)} {} 33 | 34 | template 35 | InertialEnergy::InertialEnergy(int N, T m) : pimpl_{std::make_unique(N, m)} 36 | { 37 | generate_hess(); 38 | } 39 | 40 | template 41 | InertialEnergy::Impl::Impl(int N_, T m_) : N(N_), m(m_) 42 | { 43 | device_x.resize(N * dim); 44 | device_x_tilde.resize(N * dim); 45 | device_hess.resize_triplets(N * dim); 46 | device_hess.reshape(N * dim, N * dim); 47 | device_grad.resize(N * dim); 48 | } 49 | template 50 | void InertialEnergy::generate_hess() 51 | { 52 | auto &device_hess = pimpl_->device_hess; 53 | auto m = pimpl_->m; 54 | auto N = pimpl_->N; 55 | ParallelFor(256) 56 | .apply(N * dim, 57 | [device_hess_row_indices = device_hess.row_indices().viewer(), device_hess_col_indices = device_hess.col_indices().viewer(), 58 | device_hess_values = device_hess.values().viewer(), m] __device__(int i) mutable 59 | { 60 | device_hess_row_indices(i) = i; 61 | device_hess_col_indices(i) = i; 62 | device_hess_values(i) = m; 63 | }) 64 | .wait(); 65 | } 66 | 67 | template 68 | void InertialEnergy::update_x(const DeviceBuffer &x) 69 | { 70 | pimpl_->device_x.view().copy_from(x); 71 | } 72 | 73 | template 74 | void InertialEnergy::update_x_tilde(const DeviceBuffer &x_tilde) 75 | { 76 | pimpl_->device_x_tilde.view().copy_from(x_tilde); 77 | } 78 | 79 | template 80 | void InertialEnergy::update_m(T m) 81 | { 82 | pimpl_->m = m; 83 | } 84 | 85 | template 86 | T InertialEnergy::val() 87 | { 88 | auto &device_x = pimpl_->device_x; 89 | auto &device_x_tilde = pimpl_->device_x_tilde; 90 | auto &m = pimpl_->m; 91 | auto N = pimpl_->N * dim; 92 | DeviceBuffer device_val(N); 93 | ParallelFor(256) 94 | .apply(N, 95 | [device_val = device_val.viewer(), device_x = device_x.cviewer(), device_x_tilde = device_x_tilde.cviewer(), m] __device__(int i) mutable 96 | { 97 | device_val(i) = 0.5 * m * (device_x(i) - device_x_tilde(i)) * (device_x(i) - device_x_tilde(i)); 98 | }) 99 | .wait(); 100 | return devicesum(device_val); 101 | } 102 | 103 | template 104 | const DeviceBuffer &InertialEnergy::grad() 105 | { 106 | auto &device_x = pimpl_->device_x; 107 | auto &device_x_tilde = pimpl_->device_x_tilde; 108 | auto m = pimpl_->m; 109 | auto N = pimpl_->N * dim; 110 | auto &device_grad = pimpl_->device_grad; 111 | ParallelFor(256) 112 | .apply(N, 113 | [device_x = device_x.cviewer(), device_x_tilde = device_x_tilde.cviewer(), m, N, device_grad = device_grad.viewer()] __device__(int i) mutable 114 | { 115 | device_grad(i) = m * (device_x(i) - device_x_tilde(i)); 116 | }) 117 | .wait(); 118 | // display_vec(device_grad); 119 | return device_grad; 120 | } // Calculate the gradient of the energy 121 | 122 | template 123 | const DeviceTripletMatrix &InertialEnergy::hess() 124 | { 125 | return pimpl_->device_hess; 126 | } // Calculate the Hessian matrix of the energy 127 | 128 | template class InertialEnergy; 129 | template class InertialEnergy; 130 | template class InertialEnergy; 131 | template class InertialEnergy; 132 | -------------------------------------------------------------------------------- /simulators/3_contact/src/device_uti.cu: -------------------------------------------------------------------------------- 1 | #include "device_uti.h" 2 | using namespace muda; 3 | 4 | template 5 | T devicesum(const DeviceBuffer &buffer) 6 | { 7 | T sum = 0.0f; // Result of the reduction 8 | T *d_out; // Device memory to store the result of the reduction 9 | cudaMalloc(&d_out, sizeof(T)); // Allocate memory for the result 10 | 11 | // DeviceReduce is assumed to be part of the 'muda' library or similar 12 | DeviceReduce().Sum(buffer.data(), d_out, buffer.size()); 13 | 14 | // Copy the result back to the host 15 | cudaMemcpy(&sum, d_out, sizeof(T), cudaMemcpyDeviceToHost); 16 | 17 | // Clean up 18 | cudaFree(d_out); 19 | return sum; 20 | } 21 | template float devicesum(const DeviceBuffer &); 22 | template double devicesum(const DeviceBuffer &); 23 | 24 | template 25 | void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD) 26 | { 27 | Eigen::SelfAdjointEigenSolver> eigensolver(hess); 28 | Eigen::Matrix lam = eigensolver.eigenvalues(); 29 | Eigen::Matrix V = eigensolver.eigenvectors(); 30 | // set all negative eigenvalues to zero 31 | Eigen::Matrix lamDiag; 32 | lamDiag.setZero(); 33 | for (int i = 0; i < Size; i++) 34 | if (lam(i) > 0) 35 | lamDiag(i, i) = lam(i); 36 | 37 | Eigen::Matrix VT = V.transpose(); 38 | 39 | PSD = V * lamDiag * VT; 40 | } 41 | 42 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 43 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 44 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 45 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); -------------------------------------------------------------------------------- /simulators/3_contact/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "simulator.h" 2 | 3 | int main() 4 | { 5 | double rho = 1000, k = 4e4, initial_stretch = 1, n_seg = 15, h = 0.01, side_len = 1, tol = 0.01; 6 | ContactSimulator simulator(rho, side_len, initial_stretch, k, h, tol, n_seg); 7 | simulator.run(); 8 | } -------------------------------------------------------------------------------- /simulators/3_contact/src/square_mesh.cpp: -------------------------------------------------------------------------------- 1 | #include "square_mesh.h" 2 | template 3 | void generate(T side_length, int n_seg, std::vector &x, std::vector &e) 4 | { 5 | int dim = n_seg + 1; 6 | x.clear(); 7 | x.reserve(dim * dim * 2); // Preallocate space for all nodes 8 | 9 | T step = side_length / n_seg; 10 | 11 | // Populate the coordinates 12 | for (int i = 0; i < dim; i++) 13 | { 14 | for (int j = 0; j < dim; j++) 15 | { 16 | x.push_back(-side_length / 2 + i * step); 17 | x.push_back(-side_length / 2 + j * step); 18 | } 19 | } 20 | 21 | // Clear any existing data in e and reserve space for edges 22 | e.clear(); 23 | // Reserve space assuming maximum edge count (horizontal + vertical + 2*diagonal) 24 | e.reserve(2 * n_seg * (n_seg + 1) + 4 * n_seg * n_seg); 25 | 26 | // Horizontal edges 27 | for (int i = 0; i < n_seg; i++) 28 | { 29 | for (int j = 0; j < dim; j++) 30 | { 31 | e.push_back(i * dim + j); 32 | e.push_back((i + 1) * dim + j); 33 | } 34 | } 35 | 36 | // Vertical edges 37 | for (int i = 0; i < dim; i++) 38 | { 39 | for (int j = 0; j < n_seg; j++) 40 | { 41 | e.push_back(i * dim + j); 42 | e.push_back(i * dim + j + 1); 43 | } 44 | } 45 | 46 | // Diagonal edges 47 | for (int i = 0; i < n_seg; i++) 48 | { 49 | for (int j = 0; j < n_seg; j++) 50 | { 51 | e.push_back(i * dim + j); 52 | e.push_back((i + 1) * dim + j + 1); 53 | e.push_back((i + 1) * dim + j); 54 | e.push_back(i * dim + j + 1); 55 | } 56 | } 57 | } 58 | 59 | template void generate(float side_length, int n_seg, std::vector &x, std::vector &e); 60 | template void generate(double side_length, int n_seg, std::vector &x, std::vector &e); 61 | template void generate(long double side_length, int n_seg, std::vector &x, std::vector &e); 62 | -------------------------------------------------------------------------------- /simulators/4_friction/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(4_friction) 2 | 3 | target_compile_options(4_friction PRIVATE -g) 4 | set_target_properties(4_friction PROPERTIES CUDA_SEPARABLE_COMPILATION ON) 5 | 6 | target_link_libraries(4_friction PRIVATE muda cusolver cublas cusparse ) 7 | 8 | option(BUILD_SHARED_LIBS "Build shared libraries" OFF) 9 | 10 | include_directories(include) 11 | 12 | file(GLOB_RECURSE 4_friction_CU_SOURCE CONFIGURE_DEPENDS "src/*.cu") 13 | target_sources(4_friction PRIVATE ${4_friction_CU_SOURCE}) 14 | 15 | file(GLOB_RECURSE 4_friction_CPP_SOURCE CONFIGURE_DEPENDS "src/*.cpp") 16 | target_sources(4_friction PRIVATE ${4_friction_CPP_SOURCE}) 17 | 18 | target_link_libraries(4_friction PRIVATE sfml-graphics) 19 | -------------------------------------------------------------------------------- /simulators/4_friction/include/BarrierEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "uti.h" 6 | 7 | template 8 | class BarrierEnergy 9 | { 10 | public: 11 | BarrierEnergy(const std::vector &x, const std::vector &n, const std::vector &o, const std::vector &contact_area); 12 | BarrierEnergy(); 13 | ~BarrierEnergy(); 14 | BarrierEnergy(BarrierEnergy &&rhs); 15 | BarrierEnergy(const BarrierEnergy &rhs); 16 | BarrierEnergy &operator=(BarrierEnergy &&rhs); 17 | 18 | void update_x(const DeviceBuffer &x); 19 | T val(); // Calculate the value of the energy 20 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 21 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 22 | void compute_mu_lambda(T mu, DeviceBuffer &device_mu_lambda); 23 | T init_step_size(const DeviceBuffer &p); // Calculate the initial step size for the line search 24 | 25 | private: 26 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 27 | struct Impl; 28 | // The private pointer to the implementation class Impl 29 | std::unique_ptr pimpl_; 30 | }; -------------------------------------------------------------------------------- /simulators/4_friction/include/FrictionEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "uti.h" 7 | 8 | template 9 | class FrictionEnergy 10 | { 11 | public: 12 | FrictionEnergy(const std::vector &v, T hhat, const std::vector &n); 13 | FrictionEnergy(); 14 | ~FrictionEnergy(); 15 | FrictionEnergy(FrictionEnergy &&rhs); 16 | FrictionEnergy(const FrictionEnergy &rhs); 17 | FrictionEnergy &operator=(FrictionEnergy &&rhs); 18 | 19 | void update_v(const DeviceBuffer &v); 20 | DeviceBuffer &get_mu_lambda(); 21 | T val(); // Calculate the value of the energy 22 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 23 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 24 | 25 | private: 26 | struct Impl; 27 | std::unique_ptr pimpl_; 28 | T __device__ f0(T vbarnorm, T Epsv, T hhat); 29 | T __device__ f1_div_vbarnorm(T vbarnorm, T Epsv); 30 | T __device__ f_hess_term(T vbarnorm, T Epsv); 31 | }; 32 | -------------------------------------------------------------------------------- /simulators/4_friction/include/GravityEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "square_mesh.h" 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace muda; 11 | 12 | template 13 | class GravityEnergy 14 | { 15 | public: 16 | GravityEnergy(int N, T m); 17 | GravityEnergy(); 18 | ~GravityEnergy(); 19 | GravityEnergy(GravityEnergy &&rhs); 20 | GravityEnergy(const GravityEnergy &rhs); 21 | GravityEnergy &operator=(GravityEnergy &&rhs); 22 | GravityEnergy &operator=(const GravityEnergy &rhs); 23 | 24 | void update_x(const DeviceBuffer &x); 25 | void update_x_tilde(const DeviceBuffer &x_tilde); 26 | void update_m(T m); 27 | T val(); // Calculate the value of the energy 28 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 29 | 30 | private: 31 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 32 | struct Impl; 33 | // The private pointer to the implementation class Impl 34 | std::unique_ptr pimpl_; 35 | }; 36 | -------------------------------------------------------------------------------- /simulators/4_friction/include/InertialEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "square_mesh.h" 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace muda; 11 | 12 | template 13 | class InertialEnergy 14 | { 15 | public: 16 | InertialEnergy(int N, T m); 17 | InertialEnergy(); 18 | ~InertialEnergy(); 19 | InertialEnergy(InertialEnergy &&rhs); 20 | InertialEnergy(const InertialEnergy &rhs); 21 | InertialEnergy &operator=(InertialEnergy &&rhs); 22 | 23 | void update_x(const DeviceBuffer &x); 24 | void generate_hess(); 25 | void update_x_tilde(const DeviceBuffer &x_tilde); 26 | void update_m(T m); 27 | T val(); // Calculate the value of the energy 28 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 29 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 30 | 31 | private: 32 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 33 | struct Impl; 34 | // The private pointer to the implementation class Impl 35 | std::unique_ptr pimpl_; 36 | }; 37 | -------------------------------------------------------------------------------- /simulators/4_friction/include/MassSpringEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "uti.h" 6 | 7 | template 8 | class MassSpringEnergy 9 | { 10 | public: 11 | MassSpringEnergy(const std::vector &x, const std::vector &e, const std::vector &l2, const std::vector &k); 12 | MassSpringEnergy(); 13 | ~MassSpringEnergy(); 14 | MassSpringEnergy(MassSpringEnergy &&rhs); 15 | MassSpringEnergy(const MassSpringEnergy &rhs); 16 | MassSpringEnergy &operator=(MassSpringEnergy &&rhs); 17 | 18 | void update_x(const DeviceBuffer &x); 19 | void update_e(const std::vector &e); 20 | void update_l2(const std::vector &l2); 21 | void update_k(const std::vector &k); 22 | T val(); // Calculate the value of the energy 23 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 24 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 25 | 26 | private: 27 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 28 | struct Impl; 29 | // The private pointer to the implementation class Impl 30 | std::unique_ptr pimpl_; 31 | }; -------------------------------------------------------------------------------- /simulators/4_friction/include/device_uti.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | // utility functions 6 | template 7 | T devicesum(const muda::DeviceBuffer &buffer); 8 | 9 | template 10 | void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); -------------------------------------------------------------------------------- /simulators/4_friction/include/simulator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "square_mesh.h" 6 | #include 7 | template 8 | class FrictionSimulator 9 | { 10 | public: 11 | FrictionSimulator(); 12 | ~FrictionSimulator(); 13 | FrictionSimulator(FrictionSimulator &&rhs); 14 | FrictionSimulator &operator=(FrictionSimulator &&rhs); 15 | FrictionSimulator(T rho, T side_len, T initial_stretch, T K, T h, T tol, T mu, int n_seg); 16 | void run(); 17 | 18 | private: 19 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 20 | struct Impl; 21 | // The private pointer to the implementation class Impl 22 | std::unique_ptr pimpl_; 23 | }; 24 | -------------------------------------------------------------------------------- /simulators/4_friction/include/square_mesh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | // Function to generate mesh points and edges 6 | template 7 | void generate(T side_length, int n_seg, std::vector &x, std::vector &e); 8 | -------------------------------------------------------------------------------- /simulators/4_friction/include/uti.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace muda; 8 | 9 | template 10 | DeviceBuffer add_vector(const DeviceBuffer &a, const DeviceBuffer &b, const T &factor1 = 1, const T &factor2 = 1); 11 | 12 | template 13 | DeviceBuffer mult_vector(const DeviceBuffer &a, const T &b); 14 | 15 | template 16 | DeviceTripletMatrix add_triplet(const DeviceTripletMatrix &a, const DeviceTripletMatrix &b, const T &factor1 = 1, const T &factor2 = 1); 17 | 18 | template 19 | T max_vector(const DeviceBuffer &a); 20 | 21 | template 22 | T min_vector(const DeviceBuffer &a); 23 | 24 | template 25 | void search_dir(const DeviceBuffer &grad, const DeviceTripletMatrix &hess, DeviceBuffer &dir, const DeviceBuffer &DBC); 26 | 27 | template 28 | void display_vec(const DeviceBuffer &vec); 29 | 30 | template 31 | void set_DBC(DeviceBuffer &grad, DeviceCSRMatrix &hess, const DeviceBuffer &DBC); -------------------------------------------------------------------------------- /simulators/4_friction/src/GravityEnergy.cu: -------------------------------------------------------------------------------- 1 | #include "GravityEnergy.h" 2 | #include "uti.h" 3 | #include 4 | #include 5 | #include "device_uti.h" 6 | #define GRAVITY -9.81 7 | using namespace muda; 8 | 9 | template 10 | struct GravityEnergy::Impl 11 | { 12 | DeviceBuffer device_x, device_grad; 13 | int N; 14 | T m, val; 15 | Impl(int N, T m); 16 | }; 17 | template 18 | GravityEnergy::GravityEnergy() = default; 19 | 20 | template 21 | GravityEnergy::~GravityEnergy() = default; 22 | 23 | template 24 | GravityEnergy::GravityEnergy(GravityEnergy &&rhs) = default; 25 | 26 | template 27 | GravityEnergy &GravityEnergy::operator=(GravityEnergy &&rhs) = default; 28 | 29 | template 30 | GravityEnergy::GravityEnergy(const GravityEnergy &rhs) 31 | : pimpl_{std::make_unique(*rhs.pimpl_)} {} 32 | 33 | template 34 | GravityEnergy::GravityEnergy(int N, T m) : pimpl_{std::make_unique(N, m)} 35 | { 36 | } 37 | 38 | template 39 | GravityEnergy::Impl::Impl(int N_, T m_) : N(N_), m(m_) 40 | { 41 | device_x.resize(N * dim); 42 | device_grad.resize(N * dim); 43 | } 44 | 45 | template 46 | void GravityEnergy::update_x(const DeviceBuffer &x) 47 | { 48 | pimpl_->device_x.view().copy_from(x); 49 | } 50 | 51 | template 52 | void GravityEnergy::update_m(T m) 53 | { 54 | pimpl_->m = m; 55 | } 56 | 57 | template 58 | T GravityEnergy::val() 59 | { 60 | auto &device_x = pimpl_->device_x; 61 | auto &m = pimpl_->m; 62 | auto N = pimpl_->N * dim; 63 | DeviceBuffer device_val(N); 64 | ParallelFor(256) 65 | .apply(N, 66 | [device_val = device_val.viewer(), device_x = device_x.cviewer(), m] __device__(int i) mutable 67 | { 68 | device_val(i) = i % dim == 1 ? -m * GRAVITY * device_x(i) : 0; 69 | }) 70 | .wait(); 71 | return devicesum(device_val); 72 | } 73 | 74 | template 75 | const DeviceBuffer &GravityEnergy::grad() 76 | { 77 | auto &device_x = pimpl_->device_x; 78 | auto m = pimpl_->m; 79 | auto N = pimpl_->N * dim; 80 | auto &device_grad = pimpl_->device_grad; 81 | ParallelFor(256) 82 | .apply(N, 83 | [device_x = device_x.cviewer(), m, N, device_grad = device_grad.viewer()] __device__(int i) mutable 84 | { 85 | device_grad(i) = i % dim == 1 ? -m * GRAVITY : 0; 86 | }) 87 | .wait(); 88 | // display_vec(device_grad); 89 | return device_grad; 90 | } // Calculate the gradient of the energy 91 | 92 | template class GravityEnergy; 93 | template class GravityEnergy; 94 | template class GravityEnergy; 95 | template class GravityEnergy; 96 | -------------------------------------------------------------------------------- /simulators/4_friction/src/InertialEnergy.cu: -------------------------------------------------------------------------------- 1 | #include "InertialEnergy.h" 2 | #include "uti.h" 3 | #include 4 | #include 5 | #include "device_uti.h" 6 | 7 | using namespace muda; 8 | 9 | template 10 | struct InertialEnergy::Impl 11 | { 12 | DeviceBuffer device_x, device_x_tilde, device_grad; 13 | DeviceTripletMatrix device_hess; 14 | int N; 15 | T m, val; 16 | Impl(int N, T m); 17 | }; 18 | template 19 | InertialEnergy::InertialEnergy() = default; 20 | 21 | template 22 | InertialEnergy::~InertialEnergy() = default; 23 | 24 | template 25 | InertialEnergy::InertialEnergy(InertialEnergy &&rhs) = default; 26 | 27 | template 28 | InertialEnergy &InertialEnergy::operator=(InertialEnergy &&rhs) = default; 29 | 30 | template 31 | InertialEnergy::InertialEnergy(const InertialEnergy &rhs) 32 | : pimpl_{std::make_unique(*rhs.pimpl_)} {} 33 | 34 | template 35 | InertialEnergy::InertialEnergy(int N, T m) : pimpl_{std::make_unique(N, m)} 36 | { 37 | generate_hess(); 38 | } 39 | 40 | template 41 | InertialEnergy::Impl::Impl(int N_, T m_) : N(N_), m(m_) 42 | { 43 | device_x.resize(N * dim); 44 | device_x_tilde.resize(N * dim); 45 | device_hess.resize_triplets(N * dim); 46 | device_hess.reshape(N * dim, N * dim); 47 | device_grad.resize(N * dim); 48 | } 49 | template 50 | void InertialEnergy::generate_hess() 51 | { 52 | auto &device_hess = pimpl_->device_hess; 53 | auto m = pimpl_->m; 54 | auto N = pimpl_->N; 55 | ParallelFor(256) 56 | .apply(N * dim, 57 | [device_hess_row_indices = device_hess.row_indices().viewer(), device_hess_col_indices = device_hess.col_indices().viewer(), 58 | device_hess_values = device_hess.values().viewer(), m] __device__(int i) mutable 59 | { 60 | device_hess_row_indices(i) = i; 61 | device_hess_col_indices(i) = i; 62 | device_hess_values(i) = m; 63 | }) 64 | .wait(); 65 | } 66 | 67 | template 68 | void InertialEnergy::update_x(const DeviceBuffer &x) 69 | { 70 | pimpl_->device_x.view().copy_from(x); 71 | } 72 | 73 | template 74 | void InertialEnergy::update_x_tilde(const DeviceBuffer &x_tilde) 75 | { 76 | pimpl_->device_x_tilde.view().copy_from(x_tilde); 77 | } 78 | 79 | template 80 | void InertialEnergy::update_m(T m) 81 | { 82 | pimpl_->m = m; 83 | } 84 | 85 | template 86 | T InertialEnergy::val() 87 | { 88 | auto &device_x = pimpl_->device_x; 89 | auto &device_x_tilde = pimpl_->device_x_tilde; 90 | auto &m = pimpl_->m; 91 | auto N = pimpl_->N * dim; 92 | DeviceBuffer device_val(N); 93 | ParallelFor(256) 94 | .apply(N, 95 | [device_val = device_val.viewer(), device_x = device_x.cviewer(), device_x_tilde = device_x_tilde.cviewer(), m] __device__(int i) mutable 96 | { 97 | device_val(i) = 0.5 * m * (device_x(i) - device_x_tilde(i)) * (device_x(i) - device_x_tilde(i)); 98 | }) 99 | .wait(); 100 | return devicesum(device_val); 101 | } 102 | 103 | template 104 | const DeviceBuffer &InertialEnergy::grad() 105 | { 106 | auto &device_x = pimpl_->device_x; 107 | auto &device_x_tilde = pimpl_->device_x_tilde; 108 | auto m = pimpl_->m; 109 | auto N = pimpl_->N * dim; 110 | auto &device_grad = pimpl_->device_grad; 111 | ParallelFor(256) 112 | .apply(N, 113 | [device_x = device_x.cviewer(), device_x_tilde = device_x_tilde.cviewer(), m, N, device_grad = device_grad.viewer()] __device__(int i) mutable 114 | { 115 | device_grad(i) = m * (device_x(i) - device_x_tilde(i)); 116 | }) 117 | .wait(); 118 | // display_vec(device_grad); 119 | return device_grad; 120 | } // Calculate the gradient of the energy 121 | 122 | template 123 | const DeviceTripletMatrix &InertialEnergy::hess() 124 | { 125 | return pimpl_->device_hess; 126 | } // Calculate the Hessian matrix of the energy 127 | 128 | template class InertialEnergy; 129 | template class InertialEnergy; 130 | template class InertialEnergy; 131 | template class InertialEnergy; 132 | -------------------------------------------------------------------------------- /simulators/4_friction/src/device_uti.cu: -------------------------------------------------------------------------------- 1 | #include "device_uti.h" 2 | using namespace muda; 3 | 4 | template 5 | T devicesum(const DeviceBuffer &buffer) 6 | { 7 | T sum = 0.0f; // Result of the reduction 8 | T *d_out; // Device memory to store the result of the reduction 9 | cudaMalloc(&d_out, sizeof(T)); // Allocate memory for the result 10 | 11 | // DeviceReduce is assumed to be part of the 'muda' library or similar 12 | DeviceReduce().Sum(buffer.data(), d_out, buffer.size()); 13 | 14 | // Copy the result back to the host 15 | cudaMemcpy(&sum, d_out, sizeof(T), cudaMemcpyDeviceToHost); 16 | 17 | // Clean up 18 | cudaFree(d_out); 19 | return sum; 20 | } 21 | template float devicesum(const DeviceBuffer &); 22 | template double devicesum(const DeviceBuffer &); 23 | 24 | template 25 | void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD) 26 | { 27 | Eigen::SelfAdjointEigenSolver> eigensolver(hess); 28 | Eigen::Matrix lam = eigensolver.eigenvalues(); 29 | Eigen::Matrix V = eigensolver.eigenvectors(); 30 | // set all negative eigenvalues to zero 31 | Eigen::Matrix lamDiag; 32 | lamDiag.setZero(); 33 | for (int i = 0; i < Size; i++) 34 | if (lam(i) > 0) 35 | lamDiag(i, i) = lam(i); 36 | 37 | Eigen::Matrix VT = V.transpose(); 38 | 39 | PSD = V * lamDiag * VT; 40 | } 41 | 42 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 43 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 44 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 45 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 46 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 47 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 48 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 49 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); -------------------------------------------------------------------------------- /simulators/4_friction/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "simulator.h" 2 | 3 | int main() 4 | { 5 | double rho = 1000, k = 4e4, initial_stretch = 1, n_seg = 15, h = 0.01, side_len = 1, tol = 0.01, mu = 0.11; 6 | // printf("Running mass-spring simulator with parameters: rho = %f, k = %f, initial_stretch = %f, n_seg = %d, h = %f, side_len = %f, tol = %f\n", rho, k, initial_stretch, n_seg, h, side_len, tol); 7 | FrictionSimulator simulator(rho, side_len, initial_stretch, k, h, tol, mu, n_seg); 8 | simulator.run(); 9 | } -------------------------------------------------------------------------------- /simulators/4_friction/src/square_mesh.cpp: -------------------------------------------------------------------------------- 1 | #include "square_mesh.h" 2 | template 3 | void generate(T side_length, int n_seg, std::vector &x, std::vector &e) 4 | { 5 | int dim = n_seg + 1; 6 | x.clear(); 7 | x.reserve(dim * dim * 2); // Preallocate space for all nodes 8 | 9 | T step = side_length / n_seg; 10 | 11 | // Populate the coordinates 12 | for (int i = 0; i < dim; i++) 13 | { 14 | for (int j = 0; j < dim; j++) 15 | { 16 | x.push_back(-side_length / 2 + i * step); 17 | x.push_back(-side_length / 2 + j * step); 18 | } 19 | } 20 | 21 | // Clear any existing data in e and reserve space for edges 22 | e.clear(); 23 | // Reserve space assuming maximum edge count (horizontal + vertical + 2*diagonal) 24 | e.reserve(2 * n_seg * (n_seg + 1) + 4 * n_seg * n_seg); 25 | 26 | // Horizontal edges 27 | for (int i = 0; i < n_seg; i++) 28 | { 29 | for (int j = 0; j < dim; j++) 30 | { 31 | e.push_back(i * dim + j); 32 | e.push_back((i + 1) * dim + j); 33 | } 34 | } 35 | 36 | // Vertical edges 37 | for (int i = 0; i < dim; i++) 38 | { 39 | for (int j = 0; j < n_seg; j++) 40 | { 41 | e.push_back(i * dim + j); 42 | e.push_back(i * dim + j + 1); 43 | } 44 | } 45 | 46 | // Diagonal edges 47 | for (int i = 0; i < n_seg; i++) 48 | { 49 | for (int j = 0; j < n_seg; j++) 50 | { 51 | e.push_back(i * dim + j); 52 | e.push_back((i + 1) * dim + j + 1); 53 | e.push_back((i + 1) * dim + j); 54 | e.push_back(i * dim + j + 1); 55 | } 56 | } 57 | } 58 | 59 | template void generate(float side_length, int n_seg, std::vector &x, std::vector &e); 60 | template void generate(double side_length, int n_seg, std::vector &x, std::vector &e); 61 | template void generate(long double side_length, int n_seg, std::vector &x, std::vector &e); 62 | -------------------------------------------------------------------------------- /simulators/5_mov_dirichlet/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(5_mov_dirichlet) 2 | 3 | target_compile_options(5_mov_dirichlet PRIVATE -g) 4 | set_target_properties(5_mov_dirichlet PROPERTIES CUDA_SEPARABLE_COMPILATION ON) 5 | 6 | target_link_libraries(5_mov_dirichlet PRIVATE muda cusolver cublas cusparse ) 7 | 8 | option(BUILD_SHARED_LIBS "Build shared libraries" OFF) 9 | 10 | include_directories(include) 11 | 12 | file(GLOB_RECURSE 5_mov_dirichlet_CU_SOURCE CONFIGURE_DEPENDS "src/*.cu") 13 | target_sources(5_mov_dirichlet PRIVATE ${5_mov_dirichlet_CU_SOURCE}) 14 | 15 | file(GLOB_RECURSE 5_mov_dirichlet_CPP_SOURCE CONFIGURE_DEPENDS "src/*.cpp") 16 | target_sources(5_mov_dirichlet PRIVATE ${5_mov_dirichlet_CPP_SOURCE}) 17 | 18 | target_link_libraries(5_mov_dirichlet PRIVATE sfml-graphics) 19 | -------------------------------------------------------------------------------- /simulators/5_mov_dirichlet/include/BarrierEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "uti.h" 6 | 7 | template 8 | class BarrierEnergy 9 | { 10 | public: 11 | BarrierEnergy(const std::vector &x, const std::vector &n, const std::vector &o, const std::vector &contact_area); 12 | BarrierEnergy(); 13 | ~BarrierEnergy(); 14 | BarrierEnergy(BarrierEnergy &&rhs); 15 | BarrierEnergy(const BarrierEnergy &rhs); 16 | BarrierEnergy &operator=(BarrierEnergy &&rhs); 17 | 18 | void update_x(const DeviceBuffer &x); 19 | T val(); // Calculate the value of the energy 20 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 21 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 22 | void compute_mu_lambda(T mu, DeviceBuffer &device_mu_lambda); 23 | T init_step_size(const DeviceBuffer &p); // Calculate the initial step size for the line search 24 | 25 | private: 26 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 27 | struct Impl; 28 | // The private pointer to the implementation class Impl 29 | std::unique_ptr pimpl_; 30 | }; -------------------------------------------------------------------------------- /simulators/5_mov_dirichlet/include/FrictionEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "uti.h" 7 | 8 | template 9 | class FrictionEnergy 10 | { 11 | public: 12 | FrictionEnergy(const std::vector &v, T hhat, const std::vector &n); 13 | FrictionEnergy(); 14 | ~FrictionEnergy(); 15 | FrictionEnergy(FrictionEnergy &&rhs); 16 | FrictionEnergy(const FrictionEnergy &rhs); 17 | FrictionEnergy &operator=(FrictionEnergy &&rhs); 18 | 19 | void update_v(const DeviceBuffer &v); 20 | DeviceBuffer &get_mu_lambda(); 21 | T val(); // Calculate the value of the energy 22 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 23 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 24 | 25 | private: 26 | struct Impl; 27 | std::unique_ptr pimpl_; 28 | T __device__ f0(T vbarnorm, T Epsv, T hhat); 29 | T __device__ f1_div_vbarnorm(T vbarnorm, T Epsv); 30 | T __device__ f_hess_term(T vbarnorm, T Epsv); 31 | }; 32 | -------------------------------------------------------------------------------- /simulators/5_mov_dirichlet/include/GravityEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "square_mesh.h" 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace muda; 11 | 12 | template 13 | class GravityEnergy 14 | { 15 | public: 16 | GravityEnergy(int N, T m); 17 | GravityEnergy(); 18 | ~GravityEnergy(); 19 | GravityEnergy(GravityEnergy &&rhs); 20 | GravityEnergy(const GravityEnergy &rhs); 21 | GravityEnergy &operator=(GravityEnergy &&rhs); 22 | GravityEnergy &operator=(const GravityEnergy &rhs); 23 | 24 | void update_x(const DeviceBuffer &x); 25 | void update_x_tilde(const DeviceBuffer &x_tilde); 26 | void update_m(T m); 27 | T val(); // Calculate the value of the energy 28 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 29 | 30 | private: 31 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 32 | struct Impl; 33 | // The private pointer to the implementation class Impl 34 | std::unique_ptr pimpl_; 35 | }; 36 | -------------------------------------------------------------------------------- /simulators/5_mov_dirichlet/include/InertialEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "square_mesh.h" 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace muda; 11 | 12 | template 13 | class InertialEnergy 14 | { 15 | public: 16 | InertialEnergy(int N, T m); 17 | InertialEnergy(); 18 | ~InertialEnergy(); 19 | InertialEnergy(InertialEnergy &&rhs); 20 | InertialEnergy(const InertialEnergy &rhs); 21 | InertialEnergy &operator=(InertialEnergy &&rhs); 22 | 23 | void update_x(const DeviceBuffer &x); 24 | void generate_hess(); 25 | void update_x_tilde(const DeviceBuffer &x_tilde); 26 | void update_m(T m); 27 | T val(); // Calculate the value of the energy 28 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 29 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 30 | 31 | private: 32 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 33 | struct Impl; 34 | // The private pointer to the implementation class Impl 35 | std::unique_ptr pimpl_; 36 | }; 37 | -------------------------------------------------------------------------------- /simulators/5_mov_dirichlet/include/MassSpringEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "uti.h" 6 | 7 | template 8 | class MassSpringEnergy 9 | { 10 | public: 11 | MassSpringEnergy(const std::vector &x, const std::vector &e, const std::vector &l2, const std::vector &k); 12 | MassSpringEnergy(); 13 | ~MassSpringEnergy(); 14 | MassSpringEnergy(MassSpringEnergy &&rhs); 15 | MassSpringEnergy(const MassSpringEnergy &rhs); 16 | MassSpringEnergy &operator=(MassSpringEnergy &&rhs); 17 | 18 | void update_x(const DeviceBuffer &x); 19 | void update_e(const std::vector &e); 20 | void update_l2(const std::vector &l2); 21 | void update_k(const std::vector &k); 22 | T val(); // Calculate the value of the energy 23 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 24 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 25 | 26 | private: 27 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 28 | struct Impl; 29 | // The private pointer to the implementation class Impl 30 | std::unique_ptr pimpl_; 31 | }; -------------------------------------------------------------------------------- /simulators/5_mov_dirichlet/include/SparseMatrix.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | template 6 | class SparseMatrix 7 | { 8 | public: 9 | SparseMatrix(int size); 10 | SparseMatrix(); 11 | ~SparseMatrix(); 12 | SparseMatrix(SparseMatrix &&rhs); 13 | SparseMatrix &operator=(SparseMatrix &&rhs); 14 | SparseMatrix &operator=(SparseMatrix &rhs); 15 | SparseMatrix &operator*(const T &a); 16 | SparseMatrix(const SparseMatrix &rhs); 17 | void set_value(int row, int col, T val, int loc); 18 | void set_diagonal(T val); 19 | 20 | const std::vector &get_row_buffer() const; 21 | const std::vector &get_col_buffer() const; 22 | const std::vector &get_val_buffer() const; 23 | std::vector &set_row_buffer(); 24 | std::vector &set_col_buffer(); 25 | std::vector &set_val_buffer(); 26 | SparseMatrix &combine(const SparseMatrix &other); 27 | 28 | int get_size() const; 29 | 30 | private: 31 | int size; 32 | std::vector row_idx; 33 | std::vector col_idx; 34 | std::vector val; 35 | }; 36 | -------------------------------------------------------------------------------- /simulators/5_mov_dirichlet/include/SpringEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "uti.h" 7 | #include "device_uti.h" 8 | 9 | template 10 | class SpringEnergy 11 | { 12 | public: 13 | SpringEnergy(const std::vector &x, const std::vector &m, const std::vector &DBC, T k); 14 | SpringEnergy(); 15 | ~SpringEnergy(); 16 | SpringEnergy(SpringEnergy &&rhs); 17 | SpringEnergy(const SpringEnergy &rhs); 18 | SpringEnergy &operator=(SpringEnergy &&rhs); 19 | 20 | void update_x(const DeviceBuffer &x); 21 | void update_DBC_target(const std::vector &DBC_target); 22 | void update_k(T new_k); 23 | T val(); // Calculate the value of the energy 24 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 25 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 26 | 27 | private: 28 | struct Impl; 29 | std::unique_ptr pimpl_; 30 | }; 31 | -------------------------------------------------------------------------------- /simulators/5_mov_dirichlet/include/device_uti.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | // utility functions 6 | template 7 | T devicesum(const muda::DeviceBuffer &buffer); 8 | 9 | template 10 | void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); -------------------------------------------------------------------------------- /simulators/5_mov_dirichlet/include/simulator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "square_mesh.h" 6 | #include 7 | template 8 | class MovDirichletSimulator 9 | { 10 | public: 11 | MovDirichletSimulator(); 12 | ~MovDirichletSimulator(); 13 | MovDirichletSimulator(MovDirichletSimulator &&rhs); 14 | MovDirichletSimulator &operator=(MovDirichletSimulator &&rhs); 15 | MovDirichletSimulator(T rho, T side_len, T initial_stretch, T K, T h, T tol, T mu, int n_seg); 16 | void run(); 17 | 18 | private: 19 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 20 | struct Impl; 21 | // The private pointer to the implementation class Impl 22 | std::unique_ptr pimpl_; 23 | }; 24 | -------------------------------------------------------------------------------- /simulators/5_mov_dirichlet/include/square_mesh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | // Function to generate mesh points and edges 6 | template 7 | void generate(T side_length, int n_seg, std::vector &x, std::vector &e); 8 | -------------------------------------------------------------------------------- /simulators/5_mov_dirichlet/include/uti.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace muda; 8 | 9 | template 10 | DeviceBuffer add_vector(const DeviceBuffer &a, const DeviceBuffer &b, const T &factor1 = 1, const T &factor2 = 1); 11 | 12 | template 13 | DeviceBuffer mult_vector(const DeviceBuffer &a, const T &b); 14 | 15 | template 16 | DeviceTripletMatrix add_triplet(const DeviceTripletMatrix &a, const DeviceTripletMatrix &b, const T &factor1 = 1, const T &factor2 = 1); 17 | 18 | template 19 | T max_vector(const DeviceBuffer &a); 20 | 21 | template 22 | T min_vector(const DeviceBuffer &a); 23 | 24 | template 25 | void search_dir(const DeviceBuffer &grad, const DeviceTripletMatrix &hess, DeviceBuffer &dir, const DeviceBuffer &DBC, const std::vector &DBC_target, std::vector &DBC_satified); 26 | 27 | template 28 | void display_vec(const DeviceBuffer &vec); 29 | 30 | template 31 | void set_DBC(DeviceBuffer &grad, DeviceCSRMatrix &hess, const DeviceBuffer &DBC, const std::vector &DBC_target, std::vector &DBC_satified); -------------------------------------------------------------------------------- /simulators/5_mov_dirichlet/src/GravityEnergy.cu: -------------------------------------------------------------------------------- 1 | #include "GravityEnergy.h" 2 | #include "uti.h" 3 | #include 4 | #include 5 | #include "device_uti.h" 6 | #define GRAVITY -9.81 7 | using namespace muda; 8 | 9 | template 10 | struct GravityEnergy::Impl 11 | { 12 | DeviceBuffer device_x, device_grad; 13 | int N; 14 | T m, val; 15 | Impl(int N, T m); 16 | }; 17 | template 18 | GravityEnergy::GravityEnergy() = default; 19 | 20 | template 21 | GravityEnergy::~GravityEnergy() = default; 22 | 23 | template 24 | GravityEnergy::GravityEnergy(GravityEnergy &&rhs) = default; 25 | 26 | template 27 | GravityEnergy &GravityEnergy::operator=(GravityEnergy &&rhs) = default; 28 | 29 | template 30 | GravityEnergy::GravityEnergy(const GravityEnergy &rhs) 31 | : pimpl_{std::make_unique(*rhs.pimpl_)} {} 32 | 33 | template 34 | GravityEnergy::GravityEnergy(int N, T m) : pimpl_{std::make_unique(N, m)} 35 | { 36 | } 37 | 38 | template 39 | GravityEnergy::Impl::Impl(int N_, T m_) : N(N_), m(m_) 40 | { 41 | device_x.resize(N * dim); 42 | device_grad.resize(N * dim); 43 | } 44 | 45 | template 46 | void GravityEnergy::update_x(const DeviceBuffer &x) 47 | { 48 | pimpl_->device_x.view().copy_from(x); 49 | } 50 | 51 | template 52 | void GravityEnergy::update_m(T m) 53 | { 54 | pimpl_->m = m; 55 | } 56 | 57 | template 58 | T GravityEnergy::val() 59 | { 60 | auto &device_x = pimpl_->device_x; 61 | auto &m = pimpl_->m; 62 | auto N = pimpl_->N * dim; 63 | DeviceBuffer device_val(N); 64 | ParallelFor(256) 65 | .apply(N, 66 | [device_val = device_val.viewer(), device_x = device_x.cviewer(), m] __device__(int i) mutable 67 | { 68 | device_val(i) = i % dim == 1 ? -m * GRAVITY * device_x(i) : 0; 69 | }) 70 | .wait(); 71 | return devicesum(device_val); 72 | } 73 | 74 | template 75 | const DeviceBuffer &GravityEnergy::grad() 76 | { 77 | auto &device_x = pimpl_->device_x; 78 | auto m = pimpl_->m; 79 | auto N = pimpl_->N * dim; 80 | auto &device_grad = pimpl_->device_grad; 81 | ParallelFor(256) 82 | .apply(N, 83 | [device_x = device_x.cviewer(), m, N, device_grad = device_grad.viewer()] __device__(int i) mutable 84 | { 85 | device_grad(i) = i % dim == 1 ? -m * GRAVITY : 0; 86 | }) 87 | .wait(); 88 | // display_vec(device_grad); 89 | return device_grad; 90 | } // Calculate the gradient of the energy 91 | 92 | template class GravityEnergy; 93 | template class GravityEnergy; 94 | template class GravityEnergy; 95 | template class GravityEnergy; 96 | -------------------------------------------------------------------------------- /simulators/5_mov_dirichlet/src/InertialEnergy.cu: -------------------------------------------------------------------------------- 1 | #include "InertialEnergy.h" 2 | #include "uti.h" 3 | #include 4 | #include 5 | #include "device_uti.h" 6 | 7 | using namespace muda; 8 | 9 | template 10 | struct InertialEnergy::Impl 11 | { 12 | DeviceBuffer device_x, device_x_tilde, device_grad; 13 | DeviceTripletMatrix device_hess; 14 | int N; 15 | T m, val; 16 | Impl(int N, T m); 17 | }; 18 | template 19 | InertialEnergy::InertialEnergy() = default; 20 | 21 | template 22 | InertialEnergy::~InertialEnergy() = default; 23 | 24 | template 25 | InertialEnergy::InertialEnergy(InertialEnergy &&rhs) = default; 26 | 27 | template 28 | InertialEnergy &InertialEnergy::operator=(InertialEnergy &&rhs) = default; 29 | 30 | template 31 | InertialEnergy::InertialEnergy(const InertialEnergy &rhs) 32 | : pimpl_{std::make_unique(*rhs.pimpl_)} {} 33 | 34 | template 35 | InertialEnergy::InertialEnergy(int N, T m) : pimpl_{std::make_unique(N, m)} 36 | { 37 | generate_hess(); 38 | } 39 | 40 | template 41 | InertialEnergy::Impl::Impl(int N_, T m_) : N(N_), m(m_) 42 | { 43 | device_x.resize(N * dim); 44 | device_x_tilde.resize(N * dim); 45 | device_hess.resize_triplets(N * dim); 46 | device_hess.reshape(N * dim, N * dim); 47 | device_grad.resize(N * dim); 48 | } 49 | template 50 | void InertialEnergy::generate_hess() 51 | { 52 | auto &device_hess = pimpl_->device_hess; 53 | auto m = pimpl_->m; 54 | auto N = pimpl_->N; 55 | ParallelFor(256) 56 | .apply(N * dim, 57 | [device_hess_row_indices = device_hess.row_indices().viewer(), device_hess_col_indices = device_hess.col_indices().viewer(), 58 | device_hess_values = device_hess.values().viewer(), m] __device__(int i) mutable 59 | { 60 | device_hess_row_indices(i) = i; 61 | device_hess_col_indices(i) = i; 62 | device_hess_values(i) = m; 63 | }) 64 | .wait(); 65 | } 66 | 67 | template 68 | void InertialEnergy::update_x(const DeviceBuffer &x) 69 | { 70 | pimpl_->device_x.view().copy_from(x); 71 | } 72 | 73 | template 74 | void InertialEnergy::update_x_tilde(const DeviceBuffer &x_tilde) 75 | { 76 | pimpl_->device_x_tilde.view().copy_from(x_tilde); 77 | } 78 | 79 | template 80 | void InertialEnergy::update_m(T m) 81 | { 82 | pimpl_->m = m; 83 | } 84 | 85 | template 86 | T InertialEnergy::val() 87 | { 88 | auto &device_x = pimpl_->device_x; 89 | auto &device_x_tilde = pimpl_->device_x_tilde; 90 | auto &m = pimpl_->m; 91 | auto N = pimpl_->N * dim; 92 | DeviceBuffer device_val(N); 93 | ParallelFor(256) 94 | .apply(N, 95 | [device_val = device_val.viewer(), device_x = device_x.cviewer(), device_x_tilde = device_x_tilde.cviewer(), m] __device__(int i) mutable 96 | { 97 | device_val(i) = 0.5 * m * (device_x(i) - device_x_tilde(i)) * (device_x(i) - device_x_tilde(i)); 98 | }) 99 | .wait(); 100 | return devicesum(device_val); 101 | } 102 | 103 | template 104 | const DeviceBuffer &InertialEnergy::grad() 105 | { 106 | auto &device_x = pimpl_->device_x; 107 | auto &device_x_tilde = pimpl_->device_x_tilde; 108 | auto m = pimpl_->m; 109 | auto N = pimpl_->N * dim; 110 | auto &device_grad = pimpl_->device_grad; 111 | ParallelFor(256) 112 | .apply(N, 113 | [device_x = device_x.cviewer(), device_x_tilde = device_x_tilde.cviewer(), m, N, device_grad = device_grad.viewer()] __device__(int i) mutable 114 | { 115 | device_grad(i) = m * (device_x(i) - device_x_tilde(i)); 116 | }) 117 | .wait(); 118 | // display_vec(device_grad); 119 | return device_grad; 120 | } // Calculate the gradient of the energy 121 | 122 | template 123 | const DeviceTripletMatrix &InertialEnergy::hess() 124 | { 125 | return pimpl_->device_hess; 126 | } // Calculate the Hessian matrix of the energy 127 | 128 | template class InertialEnergy; 129 | template class InertialEnergy; 130 | template class InertialEnergy; 131 | template class InertialEnergy; 132 | -------------------------------------------------------------------------------- /simulators/5_mov_dirichlet/src/device_uti.cu: -------------------------------------------------------------------------------- 1 | #include "device_uti.h" 2 | using namespace muda; 3 | 4 | template 5 | T devicesum(const DeviceBuffer &buffer) 6 | { 7 | T sum = 0.0f; // Result of the reduction 8 | T *d_out; // Device memory to store the result of the reduction 9 | cudaMalloc(&d_out, sizeof(T)); // Allocate memory for the result 10 | 11 | // DeviceReduce is assumed to be part of the 'muda' library or similar 12 | DeviceReduce().Sum(buffer.data(), d_out, buffer.size()); 13 | 14 | // Copy the result back to the host 15 | cudaMemcpy(&sum, d_out, sizeof(T), cudaMemcpyDeviceToHost); 16 | 17 | // Clean up 18 | cudaFree(d_out); 19 | return sum; 20 | } 21 | template float devicesum(const DeviceBuffer &); 22 | template double devicesum(const DeviceBuffer &); 23 | 24 | template 25 | void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD) 26 | { 27 | Eigen::SelfAdjointEigenSolver> eigensolver(hess); 28 | Eigen::Matrix lam = eigensolver.eigenvalues(); 29 | Eigen::Matrix V = eigensolver.eigenvectors(); 30 | // set all negative eigenvalues to zero 31 | Eigen::Matrix lamDiag; 32 | lamDiag.setZero(); 33 | for (int i = 0; i < Size; i++) 34 | if (lam(i) > 0) 35 | lamDiag(i, i) = lam(i); 36 | 37 | Eigen::Matrix VT = V.transpose(); 38 | 39 | PSD = V * lamDiag * VT; 40 | } 41 | 42 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 43 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 44 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 45 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 46 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 47 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 48 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 49 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); -------------------------------------------------------------------------------- /simulators/5_mov_dirichlet/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "simulator.h" 2 | 3 | int main() 4 | { 5 | double rho = 1000, k = 4e4, initial_stretch = 1, n_seg = 10, h = 0.01, side_len = 1, tol = 0.01, mu = 0.11; 6 | // printf("Running mass-spring simulator with parameters: rho = %f, k = %f, initial_stretch = %f, n_seg = %d, h = %f, side_len = %f, tol = %f\n", rho, k, initial_stretch, n_seg, h, side_len, tol); 7 | MovDirichletSimulator simulator(rho, side_len, initial_stretch, k, h, tol, mu, n_seg); 8 | simulator.run(); 9 | } -------------------------------------------------------------------------------- /simulators/5_mov_dirichlet/src/square_mesh.cpp: -------------------------------------------------------------------------------- 1 | #include "square_mesh.h" 2 | template 3 | void generate(T side_length, int n_seg, std::vector &x, std::vector &e) 4 | { 5 | int dim = n_seg + 1; 6 | x.clear(); 7 | x.reserve(dim * dim * 2); // Preallocate space for all nodes 8 | 9 | T step = side_length / n_seg; 10 | 11 | // Populate the coordinates 12 | for (int i = 0; i < dim; i++) 13 | { 14 | for (int j = 0; j < dim; j++) 15 | { 16 | x.push_back(-side_length / 2 + i * step); 17 | x.push_back(-side_length / 2 + j * step); 18 | } 19 | } 20 | 21 | // Clear any existing data in e and reserve space for edges 22 | e.clear(); 23 | // Reserve space assuming maximum edge count (horizontal + vertical + 2*diagonal) 24 | e.reserve(2 * n_seg * (n_seg + 1) + 4 * n_seg * n_seg); 25 | 26 | // Horizontal edges 27 | for (int i = 0; i < n_seg; i++) 28 | { 29 | for (int j = 0; j < dim; j++) 30 | { 31 | e.push_back(i * dim + j); 32 | e.push_back((i + 1) * dim + j); 33 | } 34 | } 35 | 36 | // Vertical edges 37 | for (int i = 0; i < dim; i++) 38 | { 39 | for (int j = 0; j < n_seg; j++) 40 | { 41 | e.push_back(i * dim + j); 42 | e.push_back(i * dim + j + 1); 43 | } 44 | } 45 | 46 | // Diagonal edges 47 | for (int i = 0; i < n_seg; i++) 48 | { 49 | for (int j = 0; j < n_seg; j++) 50 | { 51 | e.push_back(i * dim + j); 52 | e.push_back((i + 1) * dim + j + 1); 53 | e.push_back((i + 1) * dim + j); 54 | e.push_back(i * dim + j + 1); 55 | } 56 | } 57 | } 58 | 59 | template void generate(float side_length, int n_seg, std::vector &x, std::vector &e); 60 | template void generate(double side_length, int n_seg, std::vector &x, std::vector &e); 61 | template void generate(long double side_length, int n_seg, std::vector &x, std::vector &e); 62 | -------------------------------------------------------------------------------- /simulators/6_inv_free/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(6_inv_free) 2 | 3 | target_compile_options(6_inv_free PRIVATE -g) 4 | set_target_properties(6_inv_free PROPERTIES CUDA_SEPARABLE_COMPILATION ON) 5 | 6 | target_link_libraries(6_inv_free PRIVATE muda cusolver cublas cusparse) 7 | 8 | option(BUILD_SHARED_LIBS "Build shared libraries" OFF) 9 | 10 | include_directories(include) 11 | 12 | file(GLOB_RECURSE 6_inv_free_CU_SOURCE CONFIGURE_DEPENDS "src/*.cu") 13 | target_sources(6_inv_free PRIVATE ${6_inv_free_CU_SOURCE}) 14 | 15 | file(GLOB_RECURSE 6_inv_free_CPP_SOURCE CONFIGURE_DEPENDS "src/*.cpp") 16 | target_sources(6_inv_free PRIVATE ${6_inv_free_CPP_SOURCE}) 17 | 18 | target_link_libraries(6_inv_free PRIVATE sfml-graphics) 19 | -------------------------------------------------------------------------------- /simulators/6_inv_free/include/BarrierEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "uti.h" 6 | 7 | template 8 | class BarrierEnergy 9 | { 10 | public: 11 | BarrierEnergy(const std::vector &x, const std::vector &n, const std::vector &o, const std::vector &contact_area); 12 | BarrierEnergy(); 13 | ~BarrierEnergy(); 14 | BarrierEnergy(BarrierEnergy &&rhs); 15 | BarrierEnergy(const BarrierEnergy &rhs); 16 | BarrierEnergy &operator=(BarrierEnergy &&rhs); 17 | 18 | void update_x(const DeviceBuffer &x); 19 | T val(); // Calculate the value of the energy 20 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 21 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 22 | void compute_mu_lambda(T mu, DeviceBuffer &device_mu_lambda); 23 | T init_step_size(const DeviceBuffer &p); // Calculate the initial step size for the line search 24 | 25 | private: 26 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 27 | struct Impl; 28 | // The private pointer to the implementation class Impl 29 | std::unique_ptr pimpl_; 30 | }; -------------------------------------------------------------------------------- /simulators/6_inv_free/include/FrictionEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "uti.h" 7 | 8 | template 9 | class FrictionEnergy 10 | { 11 | public: 12 | FrictionEnergy(const std::vector &v, T hhat, const std::vector &n); 13 | FrictionEnergy(); 14 | ~FrictionEnergy(); 15 | FrictionEnergy(FrictionEnergy &&rhs); 16 | FrictionEnergy(const FrictionEnergy &rhs); 17 | FrictionEnergy &operator=(FrictionEnergy &&rhs); 18 | 19 | void update_v(const DeviceBuffer &v); 20 | DeviceBuffer &get_mu_lambda(); 21 | T val(); // Calculate the value of the energy 22 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 23 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 24 | 25 | private: 26 | struct Impl; 27 | std::unique_ptr pimpl_; 28 | T __device__ f0(T vbarnorm, T Epsv, T hhat); 29 | T __device__ f1_div_vbarnorm(T vbarnorm, T Epsv); 30 | T __device__ f_hess_term(T vbarnorm, T Epsv); 31 | }; 32 | -------------------------------------------------------------------------------- /simulators/6_inv_free/include/GravityEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "square_mesh.h" 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace muda; 11 | 12 | template 13 | class GravityEnergy 14 | { 15 | public: 16 | GravityEnergy(int N, T m); 17 | GravityEnergy(); 18 | ~GravityEnergy(); 19 | GravityEnergy(GravityEnergy &&rhs); 20 | GravityEnergy(const GravityEnergy &rhs); 21 | GravityEnergy &operator=(GravityEnergy &&rhs); 22 | GravityEnergy &operator=(const GravityEnergy &rhs); 23 | 24 | void update_x(const DeviceBuffer &x); 25 | void update_x_tilde(const DeviceBuffer &x_tilde); 26 | void update_m(T m); 27 | T val(); // Calculate the value of the energy 28 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 29 | 30 | private: 31 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 32 | struct Impl; 33 | // The private pointer to the implementation class Impl 34 | std::unique_ptr pimpl_; 35 | }; 36 | -------------------------------------------------------------------------------- /simulators/6_inv_free/include/InertialEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "square_mesh.h" 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace muda; 11 | 12 | template 13 | class InertialEnergy 14 | { 15 | public: 16 | InertialEnergy(int N, T m); 17 | InertialEnergy(); 18 | ~InertialEnergy(); 19 | InertialEnergy(InertialEnergy &&rhs); 20 | InertialEnergy(const InertialEnergy &rhs); 21 | InertialEnergy &operator=(InertialEnergy &&rhs); 22 | 23 | void update_x(const DeviceBuffer &x); 24 | void generate_hess(); 25 | void update_x_tilde(const DeviceBuffer &x_tilde); 26 | void update_m(T m); 27 | T val(); // Calculate the value of the energy 28 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 29 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 30 | 31 | private: 32 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 33 | struct Impl; 34 | // The private pointer to the implementation class Impl 35 | std::unique_ptr pimpl_; 36 | }; 37 | -------------------------------------------------------------------------------- /simulators/6_inv_free/include/NeoHookeanEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "uti.h" 6 | #include "device_uti.h" 7 | 8 | template 9 | class NeoHookeanEnergy 10 | { 11 | public: 12 | NeoHookeanEnergy(const std::vector &x, const std::vector &e, T mu, T lam); 13 | NeoHookeanEnergy(); 14 | ~NeoHookeanEnergy(); 15 | NeoHookeanEnergy(NeoHookeanEnergy &&rhs); 16 | NeoHookeanEnergy(const NeoHookeanEnergy &rhs); 17 | NeoHookeanEnergy &operator=(NeoHookeanEnergy &&rhs); 18 | 19 | void update_x(const DeviceBuffer &x); 20 | void init_vol_IB(); 21 | T val(); // Calculate the value of the energy 22 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 23 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 24 | T init_step_size(const DeviceBuffer &p); // Calculate the initial step size for the line search 25 | 26 | private: 27 | struct Impl; 28 | std::unique_ptr pimpl_; 29 | }; 30 | -------------------------------------------------------------------------------- /simulators/6_inv_free/include/NeoHookean_auto.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Eigen/Dense" 3 | #include 4 | #include 5 | #include 6 | #include 7 | template 8 | __device__ __host__ void NeoHookeanEnergyVal(T &E, const T &Mu, const T &Lambda, const Eigen::Vector &X, const Eigen::Matrix &IB, const T &vol); 9 | 10 | template 11 | __device__ __host__ void NeoHookeanEnergyGradient(Eigen::Vector &G, const T &Mu, const T &Lambda, const Eigen::Vector &X, const Eigen::Matrix &IB, const T &vol); 12 | 13 | template 14 | __device__ __host__ void NeoHookeanEnergyHessian(Eigen::Matrix &H, const T &Mu, const T &Lambda, const Eigen::Vector &X, const Eigen::Matrix &IB, const T &vol); -------------------------------------------------------------------------------- /simulators/6_inv_free/include/SpringEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "uti.h" 7 | #include "device_uti.h" 8 | 9 | template 10 | class SpringEnergy 11 | { 12 | public: 13 | SpringEnergy(const std::vector &x, const std::vector &m, const std::vector &DBC, T k); 14 | SpringEnergy(); 15 | ~SpringEnergy(); 16 | SpringEnergy(SpringEnergy &&rhs); 17 | SpringEnergy(const SpringEnergy &rhs); 18 | SpringEnergy &operator=(SpringEnergy &&rhs); 19 | 20 | void update_x(const DeviceBuffer &x); 21 | void update_DBC_target(const std::vector &DBC_target); 22 | void update_k(T new_k); 23 | T val(); // Calculate the value of the energy 24 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 25 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 26 | 27 | private: 28 | struct Impl; 29 | std::unique_ptr pimpl_; 30 | }; 31 | -------------------------------------------------------------------------------- /simulators/6_inv_free/include/device_uti.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | // utility functions 6 | template 7 | T devicesum(const muda::DeviceBuffer &buffer); 8 | 9 | template 10 | void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); -------------------------------------------------------------------------------- /simulators/6_inv_free/include/simulator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "square_mesh.h" 6 | #include 7 | template 8 | class InvFreeSimulator 9 | { 10 | public: 11 | InvFreeSimulator(); 12 | ~InvFreeSimulator(); 13 | InvFreeSimulator(InvFreeSimulator &&rhs); 14 | InvFreeSimulator &operator=(InvFreeSimulator &&rhs); 15 | InvFreeSimulator(T rho, T side_len, T initial_stretch, T K, T h, T tol, T mu, T Mu_, T Lam_, int n_seg); 16 | void run(); 17 | 18 | private: 19 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 20 | struct Impl; 21 | // The private pointer to the implementation class Impl 22 | std::unique_ptr pimpl_; 23 | }; 24 | -------------------------------------------------------------------------------- /simulators/6_inv_free/include/square_mesh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | // Function to generate mesh points and edges 6 | template 7 | void generate(T side_length, int n_seg, std::vector &x, std::vector &e); 8 | -------------------------------------------------------------------------------- /simulators/6_inv_free/include/uti.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace muda; 8 | 9 | template 10 | DeviceBuffer add_vector(const DeviceBuffer &a, const DeviceBuffer &b, const T &factor1 = 1, const T &factor2 = 1); 11 | 12 | template 13 | DeviceBuffer mult_vector(const DeviceBuffer &a, const T &b); 14 | 15 | template 16 | DeviceTripletMatrix add_triplet(const DeviceTripletMatrix &a, const DeviceTripletMatrix &b, const T &factor1 = 1, const T &factor2 = 1); 17 | 18 | template 19 | T max_vector(const DeviceBuffer &a); 20 | 21 | template 22 | T min_vector(const DeviceBuffer &a); 23 | 24 | template 25 | void search_dir(const DeviceBuffer &grad, const DeviceTripletMatrix &hess, DeviceBuffer &dir, const DeviceBuffer &DBC, const std::vector &DBC_target, std::vector &DBC_satified); 26 | 27 | template 28 | void display_vec(const DeviceBuffer &vec); 29 | 30 | template 31 | void set_DBC(DeviceBuffer &grad, DeviceCSRMatrix &hess, const DeviceBuffer &DBC, const std::vector &DBC_target, std::vector &DBC_satified); 32 | 33 | template 34 | __device__ T smallest_positive_real_root_quad(T a, T b, T c); -------------------------------------------------------------------------------- /simulators/6_inv_free/src/GravityEnergy.cu: -------------------------------------------------------------------------------- 1 | #include "GravityEnergy.h" 2 | #include "uti.h" 3 | #include 4 | #include 5 | #include "device_uti.h" 6 | #define GRAVITY -9.81 7 | using namespace muda; 8 | 9 | template 10 | struct GravityEnergy::Impl 11 | { 12 | DeviceBuffer device_x, device_grad; 13 | int N; 14 | T m, val; 15 | Impl(int N, T m); 16 | }; 17 | template 18 | GravityEnergy::GravityEnergy() = default; 19 | 20 | template 21 | GravityEnergy::~GravityEnergy() = default; 22 | 23 | template 24 | GravityEnergy::GravityEnergy(GravityEnergy &&rhs) = default; 25 | 26 | template 27 | GravityEnergy &GravityEnergy::operator=(GravityEnergy &&rhs) = default; 28 | 29 | template 30 | GravityEnergy::GravityEnergy(const GravityEnergy &rhs) 31 | : pimpl_{std::make_unique(*rhs.pimpl_)} {} 32 | 33 | template 34 | GravityEnergy::GravityEnergy(int N, T m) : pimpl_{std::make_unique(N, m)} 35 | { 36 | } 37 | 38 | template 39 | GravityEnergy::Impl::Impl(int N_, T m_) : N(N_), m(m_) 40 | { 41 | device_x.resize(N * dim); 42 | device_grad.resize(N * dim); 43 | } 44 | 45 | template 46 | void GravityEnergy::update_x(const DeviceBuffer &x) 47 | { 48 | pimpl_->device_x.view().copy_from(x); 49 | } 50 | 51 | template 52 | void GravityEnergy::update_m(T m) 53 | { 54 | pimpl_->m = m; 55 | } 56 | 57 | template 58 | T GravityEnergy::val() 59 | { 60 | auto &device_x = pimpl_->device_x; 61 | auto &m = pimpl_->m; 62 | auto N = pimpl_->N * dim; 63 | DeviceBuffer device_val(N); 64 | ParallelFor(256) 65 | .apply(N, 66 | [device_val = device_val.viewer(), device_x = device_x.cviewer(), m] __device__(int i) mutable 67 | { 68 | device_val(i) = i % dim == 1 ? -m * GRAVITY * device_x(i) : 0; 69 | }) 70 | .wait(); 71 | return devicesum(device_val); 72 | } 73 | 74 | template 75 | const DeviceBuffer &GravityEnergy::grad() 76 | { 77 | auto &device_x = pimpl_->device_x; 78 | auto m = pimpl_->m; 79 | auto N = pimpl_->N * dim; 80 | auto &device_grad = pimpl_->device_grad; 81 | ParallelFor(256) 82 | .apply(N, 83 | [device_x = device_x.cviewer(), m, N, device_grad = device_grad.viewer()] __device__(int i) mutable 84 | { 85 | device_grad(i) = i % dim == 1 ? -m * GRAVITY : 0; 86 | }) 87 | .wait(); 88 | // display_vec(device_grad); 89 | return device_grad; 90 | } // Calculate the gradient of the energy 91 | 92 | template class GravityEnergy; 93 | template class GravityEnergy; 94 | template class GravityEnergy; 95 | template class GravityEnergy; 96 | -------------------------------------------------------------------------------- /simulators/6_inv_free/src/InertialEnergy.cu: -------------------------------------------------------------------------------- 1 | #include "InertialEnergy.h" 2 | #include "uti.h" 3 | #include 4 | #include 5 | #include "device_uti.h" 6 | 7 | using namespace muda; 8 | 9 | template 10 | struct InertialEnergy::Impl 11 | { 12 | DeviceBuffer device_x, device_x_tilde, device_grad; 13 | DeviceTripletMatrix device_hess; 14 | int N; 15 | T m, val; 16 | Impl(int N, T m); 17 | }; 18 | template 19 | InertialEnergy::InertialEnergy() = default; 20 | 21 | template 22 | InertialEnergy::~InertialEnergy() = default; 23 | 24 | template 25 | InertialEnergy::InertialEnergy(InertialEnergy &&rhs) = default; 26 | 27 | template 28 | InertialEnergy &InertialEnergy::operator=(InertialEnergy &&rhs) = default; 29 | 30 | template 31 | InertialEnergy::InertialEnergy(const InertialEnergy &rhs) 32 | : pimpl_{std::make_unique(*rhs.pimpl_)} {} 33 | 34 | template 35 | InertialEnergy::InertialEnergy(int N, T m) : pimpl_{std::make_unique(N, m)} 36 | { 37 | generate_hess(); 38 | } 39 | 40 | template 41 | InertialEnergy::Impl::Impl(int N_, T m_) : N(N_), m(m_) 42 | { 43 | device_x.resize(N * dim); 44 | device_x_tilde.resize(N * dim); 45 | device_hess.resize_triplets(N * dim); 46 | device_hess.reshape(N * dim, N * dim); 47 | device_grad.resize(N * dim); 48 | } 49 | template 50 | void InertialEnergy::generate_hess() 51 | { 52 | auto &device_hess = pimpl_->device_hess; 53 | auto m = pimpl_->m; 54 | auto N = pimpl_->N; 55 | ParallelFor(256) 56 | .apply(N * dim, 57 | [device_hess_row_indices = device_hess.row_indices().viewer(), device_hess_col_indices = device_hess.col_indices().viewer(), 58 | device_hess_values = device_hess.values().viewer(), m] __device__(int i) mutable 59 | { 60 | device_hess_row_indices(i) = i; 61 | device_hess_col_indices(i) = i; 62 | device_hess_values(i) = m; 63 | }) 64 | .wait(); 65 | } 66 | 67 | template 68 | void InertialEnergy::update_x(const DeviceBuffer &x) 69 | { 70 | pimpl_->device_x.view().copy_from(x); 71 | } 72 | 73 | template 74 | void InertialEnergy::update_x_tilde(const DeviceBuffer &x_tilde) 75 | { 76 | pimpl_->device_x_tilde.view().copy_from(x_tilde); 77 | } 78 | 79 | template 80 | void InertialEnergy::update_m(T m) 81 | { 82 | pimpl_->m = m; 83 | } 84 | 85 | template 86 | T InertialEnergy::val() 87 | { 88 | auto &device_x = pimpl_->device_x; 89 | auto &device_x_tilde = pimpl_->device_x_tilde; 90 | auto &m = pimpl_->m; 91 | auto N = pimpl_->N * dim; 92 | DeviceBuffer device_val(N); 93 | ParallelFor(256) 94 | .apply(N, 95 | [device_val = device_val.viewer(), device_x = device_x.cviewer(), device_x_tilde = device_x_tilde.cviewer(), m] __device__(int i) mutable 96 | { 97 | device_val(i) = 0.5 * m * (device_x(i) - device_x_tilde(i)) * (device_x(i) - device_x_tilde(i)); 98 | }) 99 | .wait(); 100 | return devicesum(device_val); 101 | } 102 | 103 | template 104 | const DeviceBuffer &InertialEnergy::grad() 105 | { 106 | auto &device_x = pimpl_->device_x; 107 | auto &device_x_tilde = pimpl_->device_x_tilde; 108 | auto m = pimpl_->m; 109 | auto N = pimpl_->N * dim; 110 | auto &device_grad = pimpl_->device_grad; 111 | ParallelFor(256) 112 | .apply(N, 113 | [device_x = device_x.cviewer(), device_x_tilde = device_x_tilde.cviewer(), m, N, device_grad = device_grad.viewer()] __device__(int i) mutable 114 | { 115 | device_grad(i) = m * (device_x(i) - device_x_tilde(i)); 116 | }) 117 | .wait(); 118 | // display_vec(device_grad); 119 | return device_grad; 120 | } // Calculate the gradient of the energy 121 | 122 | template 123 | const DeviceTripletMatrix &InertialEnergy::hess() 124 | { 125 | return pimpl_->device_hess; 126 | } // Calculate the Hessian matrix of the energy 127 | 128 | template class InertialEnergy; 129 | template class InertialEnergy; 130 | template class InertialEnergy; 131 | template class InertialEnergy; 132 | -------------------------------------------------------------------------------- /simulators/6_inv_free/src/device_uti.cu: -------------------------------------------------------------------------------- 1 | #include "device_uti.h" 2 | using namespace muda; 3 | 4 | template 5 | T devicesum(const DeviceBuffer &buffer) 6 | { 7 | T sum = 0.0f; // Result of the reduction 8 | T *d_out; // Device memory to store the result of the reduction 9 | cudaMalloc(&d_out, sizeof(T)); // Allocate memory for the result 10 | 11 | // DeviceReduce is assumed to be part of the 'muda' library or similar 12 | DeviceReduce().Sum(buffer.data(), d_out, buffer.size()); 13 | 14 | // Copy the result back to the host 15 | cudaMemcpy(&sum, d_out, sizeof(T), cudaMemcpyDeviceToHost); 16 | 17 | // Clean up 18 | cudaFree(d_out); 19 | return sum; 20 | } 21 | template float devicesum(const DeviceBuffer &); 22 | template double devicesum(const DeviceBuffer &); 23 | 24 | template 25 | void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD) 26 | { 27 | Eigen::SelfAdjointEigenSolver> eigensolver(hess); 28 | Eigen::Matrix lam = eigensolver.eigenvalues(); 29 | Eigen::Matrix V = eigensolver.eigenvectors(); 30 | // set all negative eigenvalues to zero 31 | Eigen::Matrix lamDiag; 32 | lamDiag.setZero(); 33 | for (int i = 0; i < Size; i++) 34 | if (lam(i) > 0) 35 | lamDiag(i, i) = lam(i); 36 | 37 | Eigen::Matrix VT = V.transpose(); 38 | 39 | PSD = V * lamDiag * VT; 40 | } 41 | 42 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 43 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 44 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 45 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 46 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 47 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 48 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 49 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); -------------------------------------------------------------------------------- /simulators/6_inv_free/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "simulator.h" 2 | #include "Eigen/Dense" 3 | #include 4 | int main() 5 | { 6 | double nu = 0.4, E = 1e5; 7 | double Mu = E / (2 * (1 + nu)), Lam = E * nu / ((1 + nu) * (1 - 2 * nu)); 8 | double rho = 1000, 9 | k = 4e4, initial_stretch = 1, n_seg = 10, h = 0.01, side_len = 1, tol = 0.01, mu = 0.11; 10 | // printf("Running mass-spring simulator with parameters: rho = %f, k = %f, initial_stretch = %f, n_seg = %d, h = %f, side_len = %f, tol = %f\n", rho, k, initial_stretch, n_seg, h, side_len, tol); 11 | InvFreeSimulator simulator(rho, side_len, initial_stretch, k, h, tol, mu, Mu, Lam, n_seg); 12 | simulator.run(); 13 | } -------------------------------------------------------------------------------- /simulators/6_inv_free/src/square_mesh.cpp: -------------------------------------------------------------------------------- 1 | #include "square_mesh.h" 2 | template 3 | void generate(T side_length, int n_seg, std::vector &x, std::vector &e) 4 | { 5 | int dim = n_seg + 1; 6 | int num_nodes = dim * dim; 7 | x.resize(num_nodes * 2); 8 | 9 | T step = side_length / n_seg; 10 | 11 | // Populate the coordinates 12 | for (int i = 0; i < dim; ++i) 13 | { 14 | for (int j = 0; j < dim; ++j) 15 | { 16 | x[(i * dim + j) * 2] = -side_length / 2 + i * step; 17 | x[(i * dim + j) * 2 + 1] = -side_length / 2 + j * step; 18 | } 19 | } 20 | 21 | // Clear and reserve space for edges 22 | e.clear(); 23 | e.reserve(2 * n_seg * n_seg * 3); 24 | 25 | // Triangulate the grid 26 | for (int i = 0; i < n_seg; ++i) 27 | { 28 | for (int j = 0; j < n_seg; ++j) 29 | { 30 | if ((i % 2) ^ (j % 2)) 31 | { 32 | e.push_back(i * dim + j); 33 | e.push_back((i + 1) * dim + j); 34 | e.push_back(i * dim + j + 1); 35 | 36 | e.push_back((i + 1) * dim + j); 37 | e.push_back((i + 1) * dim + j + 1); 38 | e.push_back(i * dim + j + 1); 39 | } 40 | else 41 | { 42 | e.push_back(i * dim + j); 43 | e.push_back((i + 1) * dim + j); 44 | e.push_back((i + 1) * dim + j + 1); 45 | 46 | e.push_back(i * dim + j); 47 | e.push_back((i + 1) * dim + j + 1); 48 | e.push_back(i * dim + j + 1); 49 | } 50 | } 51 | } 52 | } 53 | 54 | template void generate(float side_length, int n_seg, std::vector &x, std::vector &e); 55 | template void generate(double side_length, int n_seg, std::vector &x, std::vector &e); 56 | template void generate(long double side_length, int n_seg, std::vector &x, std::vector &e); 57 | -------------------------------------------------------------------------------- /simulators/7_self_contact/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(7_self_contact) 2 | 3 | target_compile_options(7_self_contact PRIVATE -g) 4 | set_target_properties(7_self_contact PROPERTIES CUDA_SEPARABLE_COMPILATION ON) 5 | 6 | target_link_libraries(7_self_contact PRIVATE muda cusolver cublas cusparse) 7 | 8 | option(BUILD_SHARED_LIBS "Build shared libraries" OFF) 9 | 10 | include_directories(include) 11 | 12 | file(GLOB_RECURSE 7_self_contact_CU_SOURCE CONFIGURE_DEPENDS "src/*.cu") 13 | target_sources(7_self_contact PRIVATE ${7_self_contact_CU_SOURCE}) 14 | 15 | file(GLOB_RECURSE 7_self_contact_CPP_SOURCE CONFIGURE_DEPENDS "src/*.cpp") 16 | target_sources(7_self_contact PRIVATE ${7_self_contact_CPP_SOURCE}) 17 | 18 | target_link_libraries(7_self_contact PRIVATE sfml-graphics) 19 | -------------------------------------------------------------------------------- /simulators/7_self_contact/include/BarrierEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "uti.h" 6 | 7 | template 8 | class BarrierEnergy 9 | { 10 | public: 11 | BarrierEnergy(const std::vector &x, const std::vector &n, const std::vector &o, const std::vector &bp, const std::vector &be, const std::vector &contact_area); 12 | BarrierEnergy(); 13 | ~BarrierEnergy(); 14 | BarrierEnergy(BarrierEnergy &&rhs); 15 | BarrierEnergy(const BarrierEnergy &rhs); 16 | BarrierEnergy &operator=(BarrierEnergy &&rhs); 17 | 18 | void update_x(const DeviceBuffer &x); 19 | T val(); // Calculate the value of the energy 20 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 21 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 22 | void compute_mu_lambda(T mu, DeviceBuffer& device_mu_lambda); 23 | T init_step_size(const DeviceBuffer &p); // Calculate the initial step size for the line search 24 | 25 | private: 26 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 27 | struct Impl; 28 | // The private pointer to the implementation class Impl 29 | std::unique_ptr pimpl_; 30 | }; -------------------------------------------------------------------------------- /simulators/7_self_contact/include/FrictionEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "uti.h" 7 | 8 | template 9 | class FrictionEnergy 10 | { 11 | public: 12 | FrictionEnergy(const std::vector &v, T hhat, const std::vector &n); 13 | FrictionEnergy(); 14 | ~FrictionEnergy(); 15 | FrictionEnergy(FrictionEnergy &&rhs); 16 | FrictionEnergy(const FrictionEnergy &rhs); 17 | FrictionEnergy &operator=(FrictionEnergy &&rhs); 18 | 19 | void update_v(const DeviceBuffer &v); 20 | DeviceBuffer& get_mu_lambda(); 21 | T val(); // Calculate the value of the energy 22 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 23 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 24 | 25 | private: 26 | struct Impl; 27 | std::unique_ptr pimpl_; 28 | T __device__ f0(T vbarnorm, T Epsv, T hhat); 29 | T __device__ f1_div_vbarnorm(T vbarnorm, T Epsv); 30 | T __device__ f_hess_term(T vbarnorm, T Epsv); 31 | }; 32 | -------------------------------------------------------------------------------- /simulators/7_self_contact/include/GravityEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "square_mesh.h" 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace muda; 11 | 12 | template 13 | class GravityEnergy 14 | { 15 | public: 16 | GravityEnergy(int N, T m); 17 | GravityEnergy(); 18 | ~GravityEnergy(); 19 | GravityEnergy(GravityEnergy &&rhs); 20 | GravityEnergy(const GravityEnergy &rhs); 21 | GravityEnergy &operator=(GravityEnergy &&rhs); 22 | GravityEnergy &operator=(const GravityEnergy &rhs); 23 | 24 | void update_x(const DeviceBuffer &x); 25 | void update_x_tilde(const DeviceBuffer &x_tilde); 26 | void update_m(T m); 27 | T val(); // Calculate the value of the energy 28 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 29 | 30 | private: 31 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 32 | struct Impl; 33 | // The private pointer to the implementation class Impl 34 | std::unique_ptr pimpl_; 35 | }; 36 | -------------------------------------------------------------------------------- /simulators/7_self_contact/include/InertialEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "square_mesh.h" 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace muda; 11 | 12 | template 13 | class InertialEnergy 14 | { 15 | public: 16 | InertialEnergy(int N, T m); 17 | InertialEnergy(); 18 | ~InertialEnergy(); 19 | InertialEnergy(InertialEnergy &&rhs); 20 | InertialEnergy(const InertialEnergy &rhs); 21 | InertialEnergy &operator=(InertialEnergy &&rhs); 22 | 23 | void update_x(const DeviceBuffer &x); 24 | void generate_hess(); 25 | void update_x_tilde(const DeviceBuffer &x_tilde); 26 | void update_m(T m); 27 | T val(); // Calculate the value of the energy 28 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 29 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 30 | 31 | private: 32 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 33 | struct Impl; 34 | // The private pointer to the implementation class Impl 35 | std::unique_ptr pimpl_; 36 | }; 37 | -------------------------------------------------------------------------------- /simulators/7_self_contact/include/NeoHookeanEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "uti.h" 6 | #include "device_uti.h" 7 | 8 | template 9 | class NeoHookeanEnergy 10 | { 11 | public: 12 | NeoHookeanEnergy(const std::vector &x, const std::vector &e, T mu, T lam); 13 | NeoHookeanEnergy(); 14 | ~NeoHookeanEnergy(); 15 | NeoHookeanEnergy(NeoHookeanEnergy &&rhs); 16 | NeoHookeanEnergy(const NeoHookeanEnergy &rhs); 17 | NeoHookeanEnergy &operator=(NeoHookeanEnergy &&rhs); 18 | 19 | void update_x(const DeviceBuffer &x); 20 | void init_vol_IB(); 21 | T val(); // Calculate the value of the energy 22 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 23 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 24 | T init_step_size(const DeviceBuffer &p); // Calculate the initial step size for the line search 25 | 26 | private: 27 | struct Impl; 28 | std::unique_ptr pimpl_; 29 | // static __device__ void polar_svd(const Eigen::Matrix &F, Eigen::Matrix &U, Eigen::Matrix &V, Eigen::Matrix &s); 30 | // static __device__ Eigen::Matrix dPsi_div_dsigma(const Eigen::Matrix &s, T mu, T lam); 31 | // static __device__ Eigen::Matrix d2Psi_div_dsigma2(const Eigen::Matrix &s, T mu, T lam); 32 | // static __device__ T B_left_coef(const Eigen::Matrix &s, T mu, T lam); 33 | // static __device__ T Psi(const Eigen::Matrix &F, T mu, T lam); 34 | // static __device__ Eigen::Matrix dPsi_div_dF(const Eigen::Matrix &F, T mu, T lam); 35 | // static __device__ Eigen::Matrix d2Psi_div_dF2(const Eigen::Matrix &F, T mu, T lam); 36 | // static __device__ Eigen::Matrix dPsi_div_dx(const Eigen::Matrix &P, const Eigen::Matrix &IB); 37 | // static __device__ Eigen::Matrix d2Psi_div_dx2(const Eigen::Matrix &dP_div_dF, const Eigen::Matrix &IB); 38 | }; 39 | -------------------------------------------------------------------------------- /simulators/7_self_contact/include/NeoHookean_auto.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Eigen/Dense" 3 | #include 4 | #include 5 | #include 6 | #include 7 | template 8 | __device__ __host__ void NeoHookeanEnergyVal(T &E, const T &Mu, const T &Lambda, const Eigen::Vector &X, const Eigen::Matrix &IB, const T &vol); 9 | 10 | template 11 | __device__ __host__ void NeoHookeanEnergyGradient(Eigen::Vector &G, const T &Mu, const T &Lambda, const Eigen::Vector &X, const Eigen::Matrix &IB, const T &vol); 12 | 13 | template 14 | __device__ __host__ void NeoHookeanEnergyHessian(Eigen::Matrix &H, const T &Mu, const T &Lambda, const Eigen::Vector &X, const Eigen::Matrix &IB, const T &vol); -------------------------------------------------------------------------------- /simulators/7_self_contact/include/SparseMatrix.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | template 6 | class SparseMatrix 7 | { 8 | public: 9 | SparseMatrix(int size); 10 | SparseMatrix(); 11 | ~SparseMatrix(); 12 | SparseMatrix(SparseMatrix &&rhs); 13 | SparseMatrix &operator=(SparseMatrix &&rhs); 14 | SparseMatrix &operator=(SparseMatrix &rhs); 15 | SparseMatrix &operator*(const T &a); 16 | SparseMatrix(const SparseMatrix &rhs); 17 | void set_value(int row, int col, T val, int loc); 18 | void set_diagonal(T val); 19 | 20 | const std::vector &get_row_buffer() const; 21 | const std::vector &get_col_buffer() const; 22 | const std::vector &get_val_buffer() const; 23 | std::vector &set_row_buffer(); 24 | std::vector &set_col_buffer(); 25 | std::vector &set_val_buffer(); 26 | SparseMatrix &combine(const SparseMatrix &other); 27 | 28 | int get_size() const; 29 | 30 | private: 31 | int size; 32 | std::vector row_idx; 33 | std::vector col_idx; 34 | std::vector val; 35 | }; 36 | -------------------------------------------------------------------------------- /simulators/7_self_contact/include/SpringEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "uti.h" 7 | #include "device_uti.h" 8 | 9 | template 10 | class SpringEnergy 11 | { 12 | public: 13 | SpringEnergy(const std::vector &x, const std::vector &m, const std::vector &DBC, T k); 14 | SpringEnergy(); 15 | ~SpringEnergy(); 16 | SpringEnergy(SpringEnergy &&rhs); 17 | SpringEnergy(const SpringEnergy &rhs); 18 | SpringEnergy &operator=(SpringEnergy &&rhs); 19 | 20 | void update_x(const DeviceBuffer &x); 21 | void update_DBC_target(const std::vector &DBC_target); 22 | void update_k(T new_k); 23 | T val(); // Calculate the value of the energy 24 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 25 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 26 | 27 | private: 28 | struct Impl; 29 | std::unique_ptr pimpl_; 30 | }; 31 | -------------------------------------------------------------------------------- /simulators/7_self_contact/include/device_uti.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | // utility functions 6 | template 7 | T devicesum(const muda::DeviceBuffer &buffer); 8 | 9 | template 10 | void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); -------------------------------------------------------------------------------- /simulators/7_self_contact/include/distance.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Eigen/Dense" 3 | #include 4 | 5 | template 6 | __device__ __host__ void PointLineDistanceVal(T &val, const Eigen::Vector &p, const Eigen::Vector &e0, const Eigen::Vector &e1); 7 | 8 | template 9 | __device__ __host__ void PointLineDistanceGrad(Eigen::Vector &grad, const Eigen::Vector &p, const Eigen::Vector &e0, const Eigen::Vector &e1); 10 | 11 | template 12 | __device__ __host__ void PointLineDistanceHess(Eigen::Matrix &hess, const Eigen::Vector &p, const Eigen::Vector &e0, const Eigen::Vector &e1); 13 | 14 | template 15 | __device__ __host__ T PointPointDistanceVal(const Eigen::Vector &p0, const Eigen::Vector &p1); 16 | 17 | template 18 | __device__ __host__ Eigen::Matrix PointPointDistanceGrad(const Eigen::Vector &p0, const Eigen::Vector &p1); 19 | 20 | template 21 | __device__ __host__ Eigen::Matrix PointPointDistanceHess(const Eigen::Vector &p0, const Eigen::Vector &p1); 22 | 23 | template 24 | __device__ __host__ T PointEdgeDistanceVal(const Eigen::Vector &p, const Eigen::Vector &e0, const Eigen::Vector &e1); 25 | 26 | template 27 | __device__ __host__ Eigen::Matrix PointEdgeDistanceGrad(const Eigen::Vector &p, const Eigen::Vector &e0, const Eigen::Vector &e1); 28 | 29 | template 30 | __device__ __host__ Eigen::Matrix PointEdgeDistanceHess(const Eigen::Vector &p, const Eigen::Vector &e0, const Eigen::Vector &e1); 31 | 32 | template 33 | __device__ __host__ bool bbox_overlap(const Eigen::Matrix &p, const Eigen::Matrix &e0, const Eigen::Matrix &e1, 34 | const Eigen::Matrix &dp, const Eigen::Matrix &de0, const Eigen::Matrix &de1, 35 | T toc_upperbound); 36 | 37 | template 38 | __device__ __host__ T narrow_phase_CCD(Eigen::Matrix p, Eigen::Matrix e0, Eigen::Matrix e1, 39 | Eigen::Matrix dp, Eigen::Matrix de0, Eigen::Matrix de1, 40 | T toc_upperbound); -------------------------------------------------------------------------------- /simulators/7_self_contact/include/simulator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "square_mesh.h" 6 | #include 7 | template 8 | class SelfContactSimulator 9 | { 10 | public: 11 | SelfContactSimulator(); 12 | ~SelfContactSimulator(); 13 | SelfContactSimulator(SelfContactSimulator &&rhs); 14 | SelfContactSimulator &operator=(SelfContactSimulator &&rhs); 15 | SelfContactSimulator(T rho, T side_len, T initial_stretch, T K, T h, T tol, T mu, T Mu_, T Lam_, int n_seg); 16 | void run(); 17 | 18 | private: 19 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 20 | struct Impl; 21 | // The private pointer to the implementation class Impl 22 | std::unique_ptr pimpl_; 23 | }; 24 | -------------------------------------------------------------------------------- /simulators/7_self_contact/include/square_mesh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | // Function to generate mesh points and edges 6 | template 7 | void generate(T side_length, int n_seg, std::vector &x, std::vector &e); 8 | 9 | void find_boundary(const std::vector &e, std::vector &bp, std::vector &be); -------------------------------------------------------------------------------- /simulators/7_self_contact/include/uti.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace muda; 8 | 9 | template 10 | DeviceBuffer add_vector(const DeviceBuffer &a, const DeviceBuffer &b, const T &factor1 = 1, const T &factor2 = 1); 11 | 12 | template 13 | DeviceBuffer mult_vector(const DeviceBuffer &a, const T &b); 14 | 15 | template 16 | DeviceTripletMatrix add_triplet(const DeviceTripletMatrix &a, const DeviceTripletMatrix &b, const T &factor1 = 1, const T &factor2 = 1); 17 | 18 | template 19 | T max_vector(const DeviceBuffer &a); 20 | 21 | template 22 | T min_vector(const DeviceBuffer &a); 23 | 24 | template 25 | void search_dir(const DeviceBuffer &grad, const DeviceTripletMatrix &hess, DeviceBuffer &dir, const DeviceBuffer &DBC, const std::vector &DBC_target, std::vector &DBC_satified); 26 | 27 | template 28 | void display_vec(const DeviceBuffer &vec); 29 | 30 | template 31 | void set_DBC(DeviceBuffer &grad, DeviceCSRMatrix &hess, const DeviceBuffer &DBC, const std::vector &DBC_target, std::vector &DBC_satified); 32 | 33 | template 34 | __device__ T smallest_positive_real_root_quad(T a, T b, T c); -------------------------------------------------------------------------------- /simulators/7_self_contact/src/GravityEnergy.cu: -------------------------------------------------------------------------------- 1 | #include "GravityEnergy.h" 2 | #include "uti.h" 3 | #include 4 | #include 5 | #include "device_uti.h" 6 | #define GRAVITY -9.81 7 | using namespace muda; 8 | 9 | template 10 | struct GravityEnergy::Impl 11 | { 12 | DeviceBuffer device_x, device_grad; 13 | int N; 14 | T m, val; 15 | Impl(int N, T m); 16 | }; 17 | template 18 | GravityEnergy::GravityEnergy() = default; 19 | 20 | template 21 | GravityEnergy::~GravityEnergy() = default; 22 | 23 | template 24 | GravityEnergy::GravityEnergy(GravityEnergy &&rhs) = default; 25 | 26 | template 27 | GravityEnergy &GravityEnergy::operator=(GravityEnergy &&rhs) = default; 28 | 29 | template 30 | GravityEnergy::GravityEnergy(const GravityEnergy &rhs) 31 | : pimpl_{std::make_unique(*rhs.pimpl_)} {} 32 | 33 | template 34 | GravityEnergy::GravityEnergy(int N, T m) : pimpl_{std::make_unique(N, m)} 35 | { 36 | } 37 | 38 | template 39 | GravityEnergy::Impl::Impl(int N_, T m_) : N(N_), m(m_) 40 | { 41 | device_x.resize(N * dim); 42 | device_grad.resize(N * dim); 43 | } 44 | 45 | template 46 | void GravityEnergy::update_x(const DeviceBuffer &x) 47 | { 48 | pimpl_->device_x.view().copy_from(x); 49 | } 50 | 51 | template 52 | void GravityEnergy::update_m(T m) 53 | { 54 | pimpl_->m = m; 55 | } 56 | 57 | template 58 | T GravityEnergy::val() 59 | { 60 | auto &device_x = pimpl_->device_x; 61 | auto &m = pimpl_->m; 62 | auto N = pimpl_->N * dim; 63 | DeviceBuffer device_val(N); 64 | ParallelFor(256) 65 | .apply(N, 66 | [device_val = device_val.viewer(), device_x = device_x.cviewer(), m] __device__(int i) mutable 67 | { 68 | device_val(i) = i % dim == 1 ? -m * GRAVITY * device_x(i) : 0; 69 | }) 70 | .wait(); 71 | return devicesum(device_val); 72 | } 73 | 74 | template 75 | const DeviceBuffer &GravityEnergy::grad() 76 | { 77 | auto &device_x = pimpl_->device_x; 78 | auto m = pimpl_->m; 79 | auto N = pimpl_->N * dim; 80 | auto &device_grad = pimpl_->device_grad; 81 | ParallelFor(256) 82 | .apply(N, 83 | [device_x = device_x.cviewer(), m, N, device_grad = device_grad.viewer()] __device__(int i) mutable 84 | { 85 | device_grad(i) = i % dim == 1 ? -m * GRAVITY : 0; 86 | }) 87 | .wait(); 88 | // display_vec(device_grad); 89 | return device_grad; 90 | } // Calculate the gradient of the energy 91 | 92 | template class GravityEnergy; 93 | template class GravityEnergy; 94 | template class GravityEnergy; 95 | template class GravityEnergy; 96 | -------------------------------------------------------------------------------- /simulators/7_self_contact/src/InertialEnergy.cu: -------------------------------------------------------------------------------- 1 | #include "InertialEnergy.h" 2 | #include "uti.h" 3 | #include 4 | #include 5 | #include "device_uti.h" 6 | 7 | using namespace muda; 8 | 9 | template 10 | struct InertialEnergy::Impl 11 | { 12 | DeviceBuffer device_x, device_x_tilde, device_grad; 13 | DeviceTripletMatrix device_hess; 14 | int N; 15 | T m, val; 16 | Impl(int N, T m); 17 | }; 18 | template 19 | InertialEnergy::InertialEnergy() = default; 20 | 21 | template 22 | InertialEnergy::~InertialEnergy() = default; 23 | 24 | template 25 | InertialEnergy::InertialEnergy(InertialEnergy &&rhs) = default; 26 | 27 | template 28 | InertialEnergy &InertialEnergy::operator=(InertialEnergy &&rhs) = default; 29 | 30 | template 31 | InertialEnergy::InertialEnergy(const InertialEnergy &rhs) 32 | : pimpl_{std::make_unique(*rhs.pimpl_)} {} 33 | 34 | template 35 | InertialEnergy::InertialEnergy(int N, T m) : pimpl_{std::make_unique(N, m)} 36 | { 37 | generate_hess(); 38 | } 39 | 40 | template 41 | InertialEnergy::Impl::Impl(int N_, T m_) : N(N_), m(m_) 42 | { 43 | device_x.resize(N * dim); 44 | device_x_tilde.resize(N * dim); 45 | device_hess.resize_triplets(N * dim); 46 | device_hess.reshape(N * dim, N * dim); 47 | device_grad.resize(N * dim); 48 | } 49 | template 50 | void InertialEnergy::generate_hess() 51 | { 52 | auto &device_hess = pimpl_->device_hess; 53 | auto m = pimpl_->m; 54 | auto N = pimpl_->N; 55 | ParallelFor(256) 56 | .apply(N * dim, 57 | [device_hess_row_indices = device_hess.row_indices().viewer(), device_hess_col_indices = device_hess.col_indices().viewer(), 58 | device_hess_values = device_hess.values().viewer(), m] __device__(int i) mutable 59 | { 60 | device_hess_row_indices(i) = i; 61 | device_hess_col_indices(i) = i; 62 | device_hess_values(i) = m; 63 | }) 64 | .wait(); 65 | } 66 | 67 | template 68 | void InertialEnergy::update_x(const DeviceBuffer &x) 69 | { 70 | pimpl_->device_x.view().copy_from(x); 71 | } 72 | 73 | template 74 | void InertialEnergy::update_x_tilde(const DeviceBuffer &x_tilde) 75 | { 76 | pimpl_->device_x_tilde.view().copy_from(x_tilde); 77 | } 78 | 79 | template 80 | void InertialEnergy::update_m(T m) 81 | { 82 | pimpl_->m = m; 83 | } 84 | 85 | template 86 | T InertialEnergy::val() 87 | { 88 | auto &device_x = pimpl_->device_x; 89 | auto &device_x_tilde = pimpl_->device_x_tilde; 90 | auto &m = pimpl_->m; 91 | auto N = pimpl_->N * dim; 92 | DeviceBuffer device_val(N); 93 | ParallelFor(256) 94 | .apply(N, 95 | [device_val = device_val.viewer(), device_x = device_x.cviewer(), device_x_tilde = device_x_tilde.cviewer(), m] __device__(int i) mutable 96 | { 97 | device_val(i) = 0.5 * m * (device_x(i) - device_x_tilde(i)) * (device_x(i) - device_x_tilde(i)); 98 | }) 99 | .wait(); 100 | return devicesum(device_val); 101 | } 102 | 103 | template 104 | const DeviceBuffer &InertialEnergy::grad() 105 | { 106 | auto &device_x = pimpl_->device_x; 107 | auto &device_x_tilde = pimpl_->device_x_tilde; 108 | auto m = pimpl_->m; 109 | auto N = pimpl_->N * dim; 110 | auto &device_grad = pimpl_->device_grad; 111 | ParallelFor(256) 112 | .apply(N, 113 | [device_x = device_x.cviewer(), device_x_tilde = device_x_tilde.cviewer(), m, N, device_grad = device_grad.viewer()] __device__(int i) mutable 114 | { 115 | device_grad(i) = m * (device_x(i) - device_x_tilde(i)); 116 | }) 117 | .wait(); 118 | // display_vec(device_grad); 119 | return device_grad; 120 | } // Calculate the gradient of the energy 121 | 122 | template 123 | const DeviceTripletMatrix &InertialEnergy::hess() 124 | { 125 | return pimpl_->device_hess; 126 | } // Calculate the Hessian matrix of the energy 127 | 128 | template class InertialEnergy; 129 | template class InertialEnergy; 130 | template class InertialEnergy; 131 | template class InertialEnergy; 132 | -------------------------------------------------------------------------------- /simulators/7_self_contact/src/device_uti.cu: -------------------------------------------------------------------------------- 1 | #include "device_uti.h" 2 | using namespace muda; 3 | 4 | template 5 | T devicesum(const DeviceBuffer &buffer) 6 | { 7 | T sum = 0.0f; // Result of the reduction 8 | T *d_out; // Device memory to store the result of the reduction 9 | cudaMalloc(&d_out, sizeof(T)); // Allocate memory for the result 10 | 11 | // DeviceReduce is assumed to be part of the 'muda' library or similar 12 | DeviceReduce().Sum(buffer.data(), d_out, buffer.size()); 13 | 14 | // Copy the result back to the host 15 | cudaMemcpy(&sum, d_out, sizeof(T), cudaMemcpyDeviceToHost); 16 | 17 | // Clean up 18 | cudaFree(d_out); 19 | return sum; 20 | } 21 | template float devicesum(const DeviceBuffer &); 22 | template double devicesum(const DeviceBuffer &); 23 | 24 | template 25 | void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD) 26 | { 27 | Eigen::SelfAdjointEigenSolver> eigensolver(hess); 28 | Eigen::Matrix lam = eigensolver.eigenvalues(); 29 | Eigen::Matrix V = eigensolver.eigenvectors(); 30 | // set all negative eigenvalues to zero 31 | Eigen::Matrix lamDiag; 32 | lamDiag.setZero(); 33 | for (int i = 0; i < Size; i++) 34 | if (lam(i) > 0) 35 | lamDiag(i, i) = lam(i); 36 | 37 | Eigen::Matrix VT = V.transpose(); 38 | 39 | PSD = V * lamDiag * VT; 40 | } 41 | 42 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 43 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 44 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 45 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 46 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 47 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 48 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 49 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); -------------------------------------------------------------------------------- /simulators/7_self_contact/src/distance/CCD.cu: -------------------------------------------------------------------------------- 1 | #include "distance.h" 2 | template 3 | __device__ __host__ bool bbox_overlap(const Eigen::Matrix &p, const Eigen::Matrix &e0, const Eigen::Matrix &e1, 4 | const Eigen::Matrix &dp, const Eigen::Matrix &de0, const Eigen::Matrix &de1, 5 | T toc_upperbound) 6 | { 7 | Eigen::Matrix max_p = p.cwiseMax(p + toc_upperbound * dp); // point trajectory bbox top-right 8 | Eigen::Matrix min_p = p.cwiseMin(p + toc_upperbound * dp); // point trajectory bbox bottom-left 9 | Eigen::Matrix max_e = e0.cwiseMax(e0 + toc_upperbound * de0).cwiseMax(e1.cwiseMax(e1 + toc_upperbound * de1)); // edge trajectory bbox top-right 10 | Eigen::Matrix min_e = e0.cwiseMin(e0 + toc_upperbound * de0).cwiseMin(e1.cwiseMin(e1 + toc_upperbound * de1)); // edge trajectory bbox bottom-left 11 | 12 | if (min_p[0] > max_e[0] || min_p[1] > max_e[1] || min_e[0] > max_p[0] || min_e[1] > max_p[1]) // no overlap 13 | { 14 | return false; 15 | } 16 | else 17 | { 18 | return true; 19 | } 20 | } 21 | 22 | template 23 | __device__ __host__ T narrow_phase_CCD(Eigen::Matrix p, Eigen::Matrix e0, Eigen::Matrix e1, 24 | Eigen::Matrix dp, Eigen::Matrix de0, Eigen::Matrix de1, 25 | T toc_upperbound) 26 | { 27 | // use relative displacement for faster convergence 28 | Eigen::Matrix mov = (dp + de0 + de1) / 3.0; 29 | de0 -= mov; 30 | de1 -= mov; 31 | dp -= mov; 32 | T maxDispMag = dp.norm() + std::sqrt(std::max(de0.dot(de0), de1.dot(de1))); 33 | if (maxDispMag == 0) 34 | { 35 | return toc_upperbound; 36 | } 37 | T eta = 0.1; // calculate the toc that first brings the distance to 0.1x the current distance 38 | T dist2_cur = PointEdgeDistanceVal(p, e0, e1); 39 | T dist_cur = std::sqrt(dist2_cur); 40 | T gap = eta * dist_cur; 41 | // iteratively move the point and edge towards each other and 42 | // grow the toc estimate without numerical errors 43 | T toc = 0; 44 | while (true) 45 | { 46 | T tocLowerBound = (1 - eta) * dist_cur / maxDispMag; 47 | 48 | p += tocLowerBound * dp; 49 | e0 += tocLowerBound * de0; 50 | e1 += tocLowerBound * de1; 51 | dist2_cur = PointEdgeDistanceVal(p, e0, e1); 52 | dist_cur = std::sqrt(dist2_cur); 53 | if (toc != 0 && dist_cur < gap) 54 | { 55 | break; 56 | } 57 | 58 | toc += tocLowerBound; 59 | if (toc > toc_upperbound) 60 | { 61 | return toc_upperbound; 62 | } 63 | } 64 | 65 | return toc; 66 | } 67 | 68 | template __device__ __host__ bool bbox_overlap(const Eigen::Matrix &p, const Eigen::Matrix &e0, const Eigen::Matrix &e1, 69 | const Eigen::Matrix &dp, const Eigen::Matrix &de0, const Eigen::Matrix &de1, 70 | float toc_upperbound); 71 | template __device__ __host__ bool bbox_overlap(const Eigen::Matrix &p, const Eigen::Matrix &e0, const Eigen::Matrix &e1, 72 | const Eigen::Matrix &dp, const Eigen::Matrix &de0, const Eigen::Matrix &de1, 73 | double toc_upperbound); 74 | template __device__ __host__ float narrow_phase_CCD(Eigen::Matrix p, Eigen::Matrix e0, Eigen::Matrix e1, 75 | Eigen::Matrix dp, Eigen::Matrix de0, Eigen::Matrix de1, 76 | float toc_upperbound); 77 | 78 | template __device__ __host__ double narrow_phase_CCD(Eigen::Matrix p, Eigen::Matrix e0, Eigen::Matrix e1, 79 | Eigen::Matrix dp, Eigen::Matrix de0, Eigen::Matrix de1, 80 | double toc_upperbound); -------------------------------------------------------------------------------- /simulators/7_self_contact/src/distance/PointEdgeDistance.cu: -------------------------------------------------------------------------------- 1 | #include "distance.h" 2 | 3 | template 4 | __device__ __host__ T PointEdgeDistanceVal(const Eigen::Vector &p, const Eigen::Vector &e0, const Eigen::Vector &e1) 5 | { 6 | Eigen::Vector e = e1 - e0; 7 | T ratio = e.dot(p - e0) / e.dot(e); 8 | if (ratio < 0) 9 | { 10 | return PointPointDistanceVal(p, e0); 11 | } 12 | else if (ratio > 1) 13 | { 14 | return PointPointDistanceVal(p, e1); 15 | } 16 | else 17 | { 18 | T val; 19 | PointLineDistanceVal(val, p, e0, e1); 20 | return val; 21 | } 22 | } 23 | 24 | template 25 | __device__ __host__ Eigen::Matrix PointEdgeDistanceGrad(const Eigen::Vector &p, const Eigen::Vector &e0, const Eigen::Vector &e1) 26 | { 27 | Eigen::Vector e = e1 - e0; 28 | T ratio = e.dot(p - e0) / e.dot(e); 29 | if (ratio < 0) 30 | { 31 | Eigen::Matrix g_PP = PointPointDistanceGrad(p, e0); 32 | Eigen::Matrix gradient; 33 | gradient << g_PP.template segment<2>(0), g_PP.template segment<2>(2), Eigen::Matrix::Zero(); 34 | return gradient; 35 | } 36 | else if (ratio > 1) 37 | { 38 | Eigen::Matrix g_PP = PointPointDistanceGrad(p, e1); 39 | Eigen::Matrix gradient; 40 | gradient << g_PP.template segment<2>(0), Eigen::Matrix::Zero(), g_PP.template segment<2>(2); 41 | return gradient; 42 | } 43 | else 44 | { 45 | Eigen::Matrix grad; 46 | PointLineDistanceGrad(grad, p, e0, e1); 47 | return grad; 48 | } 49 | } 50 | 51 | template 52 | __device__ __host__ Eigen::Matrix PointEdgeDistanceHess(const Eigen::Vector &p, const Eigen::Vector &e0, const Eigen::Vector &e1) 53 | { 54 | Eigen::Vector e = e1 - e0; 55 | T ratio = e.dot(p - e0) / e.dot(e); 56 | if (ratio < 0) 57 | { 58 | Eigen::Matrix H_PP = PointPointDistanceHess(p, e0); 59 | Eigen::Matrix H; 60 | H.setZero(); 61 | H.template block<2, 2>(0, 0) = H_PP.template block<2, 2>(0, 0); 62 | H.template block<2, 2>(0, 2) = H_PP.template block<2, 2>(0, 2); 63 | H.template block<2, 2>(2, 0) = H_PP.template block<2, 2>(2, 0); 64 | H.template block<2, 2>(2, 2) = H_PP.template block<2, 2>(2, 2); 65 | return H; 66 | } 67 | else if (ratio > 1) 68 | { 69 | Eigen::Matrix H_PP = PointPointDistanceHess(p, e1); 70 | Eigen::Matrix H; 71 | H.setZero(); 72 | H.template block<2, 2>(0, 0) = H_PP.template block<2, 2>(0, 0); 73 | H.template block<2, 2>(0, 4) = H_PP.template block<2, 2>(0, 2); 74 | H.template block<2, 2>(4, 0) = H_PP.template block<2, 2>(2, 0); 75 | H.template block<2, 2>(4, 4) = H_PP.template block<2, 2>(2, 2); 76 | return H; 77 | } 78 | else 79 | { 80 | Eigen::Matrix hess; 81 | PointLineDistanceHess(hess, p, e0, e1); 82 | return hess; 83 | } 84 | } 85 | 86 | template __device__ __host__ float PointEdgeDistanceVal(const Eigen::Vector2f &p, const Eigen::Vector2f &e0, const Eigen::Vector2f &e1); 87 | template __device__ __host__ Eigen::Matrix PointEdgeDistanceGrad(const Eigen::Vector2f &p, const Eigen::Vector2f &e0, const Eigen::Vector2f &e1); 88 | template __device__ __host__ Eigen::Matrix PointEdgeDistanceHess(const Eigen::Vector2f &p, const Eigen::Vector2f &e0, const Eigen::Vector2f &e1); 89 | 90 | template __device__ __host__ double PointEdgeDistanceVal(const Eigen::Vector2d &p, const Eigen::Vector2d &e0, const Eigen::Vector2d &e1); 91 | template __device__ __host__ Eigen::Matrix PointEdgeDistanceGrad(const Eigen::Vector2d &p, const Eigen::Vector2d &e0, const Eigen::Vector2d &e1); 92 | template __device__ __host__ Eigen::Matrix PointEdgeDistanceHess(const Eigen::Vector2d &p, const Eigen::Vector2d &e0, const Eigen::Vector2d &e1); 93 | -------------------------------------------------------------------------------- /simulators/7_self_contact/src/distance/PointPointDistance.cu: -------------------------------------------------------------------------------- 1 | #include "distance.h" 2 | 3 | template 4 | __device__ __host__ T PointPointDistanceVal(const Eigen::Vector &p0, const Eigen::Vector &p1) 5 | { 6 | Eigen::Vector e = p0 - p1; 7 | return e.dot(e); 8 | } 9 | 10 | template 11 | __device__ __host__ Eigen::Matrix PointPointDistanceGrad(const Eigen::Vector &p0, const Eigen::Vector &p1) 12 | { 13 | Eigen::Vector e = p0 - p1; 14 | Eigen::Matrix gradient; 15 | gradient << 2 * e(0), 2 * e(1), -2 * e(0), -2 * e(1); 16 | return gradient; 17 | } 18 | 19 | template 20 | __device__ __host__ Eigen::Matrix PointPointDistanceHess(const Eigen::Vector &p0, const Eigen::Vector &p1) 21 | { 22 | Eigen::Matrix H = Eigen::Matrix::Zero(); 23 | H(0, 0) = H(1, 1) = H(2, 2) = H(3, 3) = 2; 24 | H(0, 2) = H(1, 3) = H(2, 0) = H(3, 1) = -2; 25 | return H; 26 | } 27 | 28 | template __device__ __host__ float PointPointDistanceVal(const Eigen::Vector2f &p0, const Eigen::Vector2f &p1); 29 | template __device__ __host__ Eigen::Matrix PointPointDistanceGrad(const Eigen::Vector2f &p0, const Eigen::Vector2f &p1); 30 | template __device__ __host__ Eigen::Matrix PointPointDistanceHess(const Eigen::Vector2f &p0, const Eigen::Vector2f &p1); 31 | 32 | template __device__ __host__ double PointPointDistanceVal(const Eigen::Vector2d &p0, const Eigen::Vector2d &p1); 33 | template __device__ __host__ Eigen::Matrix PointPointDistanceGrad(const Eigen::Vector2d &p0, const Eigen::Vector2d &p1); 34 | template __device__ __host__ Eigen::Matrix PointPointDistanceHess(const Eigen::Vector2d &p0, const Eigen::Vector2d &p1); -------------------------------------------------------------------------------- /simulators/7_self_contact/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "simulator.h" 2 | #include "Eigen/Dense" 3 | #include 4 | int main() 5 | { 6 | double nu = 0.4, E = 1e5; 7 | double Mu = E / (2 * (1 + nu)), Lam = E * nu / ((1 + nu) * (1 - 2 * nu)); 8 | double rho = 1000, 9 | k = 4e4, initial_stretch = 1, n_seg = 6, h = 0.01, side_len = 0.45, tol = 0.01, mu = 0.4; 10 | SelfContactSimulator simulator(rho, side_len, initial_stretch, k, h, tol, mu, Mu, Lam, n_seg); 11 | simulator.run(); 12 | } -------------------------------------------------------------------------------- /simulators/7_self_contact/src/square_mesh.cpp: -------------------------------------------------------------------------------- 1 | #include "square_mesh.h" 2 | #include 3 | template 4 | void generate(T side_length, int n_seg, std::vector &x, std::vector &e) 5 | { 6 | int dim = n_seg + 1; 7 | int num_nodes = dim * dim; 8 | x.resize(num_nodes * 2); 9 | 10 | T step = side_length / n_seg; 11 | 12 | // Populate the coordinates 13 | for (int i = 0; i < dim; ++i) 14 | { 15 | for (int j = 0; j < dim; ++j) 16 | { 17 | x[(i * dim + j) * 2] = -side_length / 2 + i * step; 18 | x[(i * dim + j) * 2 + 1] = -side_length / 2 + j * step; 19 | } 20 | } 21 | 22 | // Clear and reserve space for edges 23 | e.clear(); 24 | e.reserve(2 * n_seg * n_seg * 3); 25 | 26 | // Triangulate the grid 27 | for (int i = 0; i < n_seg; ++i) 28 | { 29 | for (int j = 0; j < n_seg; ++j) 30 | { 31 | if ((i % 2) ^ (j % 2)) 32 | { 33 | e.push_back(i * dim + j); 34 | e.push_back((i + 1) * dim + j); 35 | e.push_back(i * dim + j + 1); 36 | 37 | e.push_back((i + 1) * dim + j); 38 | e.push_back((i + 1) * dim + j + 1); 39 | e.push_back(i * dim + j + 1); 40 | } 41 | else 42 | { 43 | e.push_back(i * dim + j); 44 | e.push_back((i + 1) * dim + j); 45 | e.push_back((i + 1) * dim + j + 1); 46 | 47 | e.push_back(i * dim + j); 48 | e.push_back((i + 1) * dim + j + 1); 49 | e.push_back(i * dim + j + 1); 50 | } 51 | } 52 | } 53 | } 54 | 55 | template void generate(float side_length, int n_seg, std::vector &x, std::vector &e); 56 | template void generate(double side_length, int n_seg, std::vector &x, std::vector &e); 57 | template void generate(long double side_length, int n_seg, std::vector &x, std::vector &e); 58 | 59 | void find_boundary(const std::vector &e, std::vector &bp, std::vector &be) 60 | { 61 | // index all half-edges for fast query 62 | std::set> edge_set; 63 | for (size_t i = 0; i < e.size() / 3; i++) 64 | { 65 | for (int j = 0; j < 3; ++j) 66 | { 67 | edge_set.insert({e[i * 3 + j], e[i * 3 + (j + 1) % 3]}); 68 | } 69 | } 70 | 71 | // find boundary points and edges 72 | std::set bp_set; 73 | for (const auto &eI : edge_set) 74 | { 75 | if (edge_set.find({eI.second, eI.first}) == edge_set.end()) 76 | { 77 | // if the inverse edge of a half-edge does not exist, 78 | // then it is a boundary edge 79 | be.push_back(eI.first); 80 | be.push_back(eI.second); 81 | bp_set.insert(eI.first); 82 | bp_set.insert(eI.second); 83 | } 84 | } 85 | 86 | // Convert set to vector 87 | bp.assign(bp_set.begin(), bp_set.end()); 88 | } 89 | -------------------------------------------------------------------------------- /simulators/8_self_friction/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(8_self_friction) 2 | 3 | target_compile_options(8_self_friction PRIVATE -g) 4 | set_target_properties(8_self_friction PROPERTIES CUDA_SEPARABLE_COMPILATION ON) 5 | 6 | target_link_libraries(8_self_friction PRIVATE muda cusolver cublas cusparse) 7 | 8 | option(BUILD_SHARED_LIBS "Build shared libraries" OFF) 9 | 10 | include_directories(include) 11 | 12 | file(GLOB_RECURSE 8_self_friction_CU_SOURCE CONFIGURE_DEPENDS "src/*.cu") 13 | target_sources(8_self_friction PRIVATE ${8_self_friction_CU_SOURCE}) 14 | 15 | file(GLOB_RECURSE 8_self_friction_CPP_SOURCE CONFIGURE_DEPENDS "src/*.cpp") 16 | target_sources(8_self_friction PRIVATE ${8_self_friction_CPP_SOURCE}) 17 | 18 | target_link_libraries(8_self_friction PRIVATE sfml-graphics) 19 | -------------------------------------------------------------------------------- /simulators/8_self_friction/include/BarrierEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "uti.h" 6 | 7 | template 8 | class BarrierEnergy 9 | { 10 | public: 11 | BarrierEnergy(const std::vector &x, const std::vector &n, const std::vector &o, const std::vector &bp, const std::vector &be, const std::vector &contact_area); 12 | BarrierEnergy(); 13 | ~BarrierEnergy(); 14 | BarrierEnergy(BarrierEnergy &&rhs); 15 | BarrierEnergy(const BarrierEnergy &rhs); 16 | BarrierEnergy &operator=(BarrierEnergy &&rhs); 17 | 18 | void update_x(const DeviceBuffer &x); 19 | T val(); // Calculate the value of the energy 20 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 21 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 22 | void compute_mu_lambda(T mu, DeviceBuffer &device_mu_lambda, DeviceBuffer& device_mu_lambda_self, DeviceBuffer>& device_n_self, DeviceBuffer& device_r_self); 23 | T init_step_size(const DeviceBuffer &p); // Calculate the initial step size for the line search 24 | 25 | private: 26 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 27 | struct Impl; 28 | // The private pointer to the implementation class Impl 29 | std::unique_ptr pimpl_; 30 | }; -------------------------------------------------------------------------------- /simulators/8_self_friction/include/FrictionEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "uti.h" 7 | 8 | template 9 | class FrictionEnergy 10 | { 11 | public: 12 | FrictionEnergy(const std::vector &v, T hhat, const std::vector &n, const std::vector& bp, const std::vector& be, int npe); 13 | FrictionEnergy(); 14 | ~FrictionEnergy(); 15 | FrictionEnergy(FrictionEnergy &&rhs); 16 | FrictionEnergy(const FrictionEnergy &rhs); 17 | FrictionEnergy &operator=(FrictionEnergy &&rhs); 18 | 19 | void update_v(const DeviceBuffer &v); 20 | DeviceBuffer &get_mu_lambda(); 21 | DeviceBuffer& get_mu_lambda_self(); 22 | DeviceBuffer>& get_n_self(); 23 | DeviceBuffer& get_r_self(); 24 | T val(); // Calculate the value of the energy 25 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 26 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 27 | 28 | private: 29 | struct Impl; 30 | std::unique_ptr pimpl_; 31 | T __device__ f0(T vbarnorm, T Epsv, T hhat); 32 | T __device__ f1_div_vbarnorm(T vbarnorm, T Epsv); 33 | T __device__ f_hess_term(T vbarnorm, T Epsv); 34 | }; 35 | -------------------------------------------------------------------------------- /simulators/8_self_friction/include/GravityEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "square_mesh.h" 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace muda; 11 | 12 | template 13 | class GravityEnergy 14 | { 15 | public: 16 | GravityEnergy(int N, T m); 17 | GravityEnergy(); 18 | ~GravityEnergy(); 19 | GravityEnergy(GravityEnergy &&rhs); 20 | GravityEnergy(const GravityEnergy &rhs); 21 | GravityEnergy &operator=(GravityEnergy &&rhs); 22 | GravityEnergy &operator=(const GravityEnergy &rhs); 23 | 24 | void update_x(const DeviceBuffer &x); 25 | void update_x_tilde(const DeviceBuffer &x_tilde); 26 | void update_m(T m); 27 | T val(); // Calculate the value of the energy 28 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 29 | 30 | private: 31 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 32 | struct Impl; 33 | // The private pointer to the implementation class Impl 34 | std::unique_ptr pimpl_; 35 | }; 36 | -------------------------------------------------------------------------------- /simulators/8_self_friction/include/InertialEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "square_mesh.h" 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace muda; 11 | 12 | template 13 | class InertialEnergy 14 | { 15 | public: 16 | InertialEnergy(int N, T m); 17 | InertialEnergy(); 18 | ~InertialEnergy(); 19 | InertialEnergy(InertialEnergy &&rhs); 20 | InertialEnergy(const InertialEnergy &rhs); 21 | InertialEnergy &operator=(InertialEnergy &&rhs); 22 | 23 | void update_x(const DeviceBuffer &x); 24 | void generate_hess(); 25 | void update_x_tilde(const DeviceBuffer &x_tilde); 26 | void update_m(T m); 27 | T val(); // Calculate the value of the energy 28 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 29 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 30 | 31 | private: 32 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 33 | struct Impl; 34 | // The private pointer to the implementation class Impl 35 | std::unique_ptr pimpl_; 36 | }; 37 | -------------------------------------------------------------------------------- /simulators/8_self_friction/include/NeoHookeanEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "uti.h" 6 | #include "device_uti.h" 7 | 8 | template 9 | class NeoHookeanEnergy 10 | { 11 | public: 12 | NeoHookeanEnergy(const std::vector &x, const std::vector &e, T mu, T lam); 13 | NeoHookeanEnergy(); 14 | ~NeoHookeanEnergy(); 15 | NeoHookeanEnergy(NeoHookeanEnergy &&rhs); 16 | NeoHookeanEnergy(const NeoHookeanEnergy &rhs); 17 | NeoHookeanEnergy &operator=(NeoHookeanEnergy &&rhs); 18 | 19 | void update_x(const DeviceBuffer &x); 20 | void init_vol_IB(); 21 | T val(); // Calculate the value of the energy 22 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 23 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 24 | T init_step_size(const DeviceBuffer &p); // Calculate the initial step size for the line search 25 | 26 | private: 27 | struct Impl; 28 | std::unique_ptr pimpl_; 29 | // static __device__ void polar_svd(const Eigen::Matrix &F, Eigen::Matrix &U, Eigen::Matrix &V, Eigen::Matrix &s); 30 | // static __device__ Eigen::Matrix dPsi_div_dsigma(const Eigen::Matrix &s, T mu, T lam); 31 | // static __device__ Eigen::Matrix d2Psi_div_dsigma2(const Eigen::Matrix &s, T mu, T lam); 32 | // static __device__ T B_left_coef(const Eigen::Matrix &s, T mu, T lam); 33 | // static __device__ T Psi(const Eigen::Matrix &F, T mu, T lam); 34 | // static __device__ Eigen::Matrix dPsi_div_dF(const Eigen::Matrix &F, T mu, T lam); 35 | // static __device__ Eigen::Matrix d2Psi_div_dF2(const Eigen::Matrix &F, T mu, T lam); 36 | // static __device__ Eigen::Matrix dPsi_div_dx(const Eigen::Matrix &P, const Eigen::Matrix &IB); 37 | // static __device__ Eigen::Matrix d2Psi_div_dx2(const Eigen::Matrix &dP_div_dF, const Eigen::Matrix &IB); 38 | }; 39 | -------------------------------------------------------------------------------- /simulators/8_self_friction/include/NeoHookean_auto.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Eigen/Dense" 3 | #include 4 | #include 5 | #include 6 | #include 7 | template 8 | __device__ __host__ void NeoHookeanEnergyVal(T &E, const T &Mu, const T &Lambda, const Eigen::Vector &X, const Eigen::Matrix &IB, const T &vol); 9 | 10 | template 11 | __device__ __host__ void NeoHookeanEnergyGradient(Eigen::Vector &G, const T &Mu, const T &Lambda, const Eigen::Vector &X, const Eigen::Matrix &IB, const T &vol); 12 | 13 | template 14 | __device__ __host__ void NeoHookeanEnergyHessian(Eigen::Matrix &H, const T &Mu, const T &Lambda, const Eigen::Vector &X, const Eigen::Matrix &IB, const T &vol); -------------------------------------------------------------------------------- /simulators/8_self_friction/include/SparseMatrix.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | template 6 | class SparseMatrix 7 | { 8 | public: 9 | SparseMatrix(int size); 10 | SparseMatrix(); 11 | ~SparseMatrix(); 12 | SparseMatrix(SparseMatrix &&rhs); 13 | SparseMatrix &operator=(SparseMatrix &&rhs); 14 | SparseMatrix &operator=(SparseMatrix &rhs); 15 | SparseMatrix &operator*(const T &a); 16 | SparseMatrix(const SparseMatrix &rhs); 17 | void set_value(int row, int col, T val, int loc); 18 | void set_diagonal(T val); 19 | 20 | const std::vector &get_row_buffer() const; 21 | const std::vector &get_col_buffer() const; 22 | const std::vector &get_val_buffer() const; 23 | std::vector &set_row_buffer(); 24 | std::vector &set_col_buffer(); 25 | std::vector &set_val_buffer(); 26 | SparseMatrix &combine(const SparseMatrix &other); 27 | 28 | int get_size() const; 29 | 30 | private: 31 | int size; 32 | std::vector row_idx; 33 | std::vector col_idx; 34 | std::vector val; 35 | }; 36 | -------------------------------------------------------------------------------- /simulators/8_self_friction/include/SpringEnergy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "uti.h" 7 | #include "device_uti.h" 8 | 9 | template 10 | class SpringEnergy 11 | { 12 | public: 13 | SpringEnergy(const std::vector &x, const std::vector &m, const std::vector &DBC, T k); 14 | SpringEnergy(); 15 | ~SpringEnergy(); 16 | SpringEnergy(SpringEnergy &&rhs); 17 | SpringEnergy(const SpringEnergy &rhs); 18 | SpringEnergy &operator=(SpringEnergy &&rhs); 19 | 20 | void update_x(const DeviceBuffer &x); 21 | void update_DBC_target(const std::vector &DBC_target); 22 | void update_k(T new_k); 23 | T val(); // Calculate the value of the energy 24 | const DeviceBuffer &grad(); // Calculate the gradient of the energy 25 | const DeviceTripletMatrix &hess(); // Calculate the Hessian matrix of the energy 26 | 27 | private: 28 | struct Impl; 29 | std::unique_ptr pimpl_; 30 | }; 31 | -------------------------------------------------------------------------------- /simulators/8_self_friction/include/device_uti.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | // utility functions 6 | template 7 | T devicesum(const muda::DeviceBuffer &buffer); 8 | 9 | template 10 | void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); -------------------------------------------------------------------------------- /simulators/8_self_friction/include/distance.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Eigen/Dense" 3 | #include 4 | 5 | template 6 | __device__ __host__ void PointLineDistanceVal(T &val, const Eigen::Vector &p, const Eigen::Vector &e0, const Eigen::Vector &e1); 7 | 8 | template 9 | __device__ __host__ void PointLineDistanceGrad(Eigen::Vector &grad, const Eigen::Vector &p, const Eigen::Vector &e0, const Eigen::Vector &e1); 10 | 11 | template 12 | __device__ __host__ void PointLineDistanceHess(Eigen::Matrix &hess, const Eigen::Vector &p, const Eigen::Vector &e0, const Eigen::Vector &e1); 13 | 14 | template 15 | __device__ __host__ T PointPointDistanceVal(const Eigen::Vector &p0, const Eigen::Vector &p1); 16 | 17 | template 18 | __device__ __host__ Eigen::Matrix PointPointDistanceGrad(const Eigen::Vector &p0, const Eigen::Vector &p1); 19 | 20 | template 21 | __device__ __host__ Eigen::Matrix PointPointDistanceHess(const Eigen::Vector &p0, const Eigen::Vector &p1); 22 | 23 | template 24 | __device__ __host__ T PointEdgeDistanceVal(const Eigen::Vector &p, const Eigen::Vector &e0, const Eigen::Vector &e1); 25 | 26 | template 27 | __device__ __host__ Eigen::Matrix PointEdgeDistanceGrad(const Eigen::Vector &p, const Eigen::Vector &e0, const Eigen::Vector &e1); 28 | 29 | template 30 | __device__ __host__ Eigen::Matrix PointEdgeDistanceHess(const Eigen::Vector &p, const Eigen::Vector &e0, const Eigen::Vector &e1); 31 | 32 | template 33 | __device__ __host__ void PointEdgeDistanceTangent(const Eigen::Vector& p, const Eigen::Vector& e0, const Eigen::Vector& e1, Eigen::Matrix& n,T& r); 34 | 35 | template 36 | __device__ __host__ bool bbox_overlap(const Eigen::Matrix &p, const Eigen::Matrix &e0, const Eigen::Matrix &e1, 37 | const Eigen::Matrix &dp, const Eigen::Matrix &de0, const Eigen::Matrix &de1, 38 | T toc_upperbound); 39 | 40 | template 41 | __device__ __host__ T narrow_phase_CCD(Eigen::Matrix p, Eigen::Matrix e0, Eigen::Matrix e1, 42 | Eigen::Matrix dp, Eigen::Matrix de0, Eigen::Matrix de1, 43 | T toc_upperbound); -------------------------------------------------------------------------------- /simulators/8_self_friction/include/simulator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "square_mesh.h" 6 | #include 7 | template 8 | class SelfFrictionSimulator 9 | { 10 | public: 11 | SelfFrictionSimulator(); 12 | ~SelfFrictionSimulator(); 13 | SelfFrictionSimulator(SelfFrictionSimulator &&rhs); 14 | SelfFrictionSimulator &operator=(SelfFrictionSimulator &&rhs); 15 | SelfFrictionSimulator(T rho, T side_len, T initial_stretch, T K, T h, T tol, T mu, T Mu_, T Lam_, int n_seg); 16 | void run(); 17 | 18 | private: 19 | // The implementation details of the VecAdder class are placed in the implementation class declared here. 20 | struct Impl; 21 | // The private pointer to the implementation class Impl 22 | std::unique_ptr pimpl_; 23 | }; 24 | -------------------------------------------------------------------------------- /simulators/8_self_friction/include/square_mesh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | // Function to generate mesh points and edges 6 | template 7 | void generate(T side_length, int n_seg, std::vector &x, std::vector &e); 8 | 9 | void find_boundary(const std::vector &e, std::vector &bp, std::vector &be); -------------------------------------------------------------------------------- /simulators/8_self_friction/include/uti.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace muda; 8 | 9 | template 10 | DeviceBuffer add_vector(const DeviceBuffer &a, const DeviceBuffer &b, const T &factor1 = 1, const T &factor2 = 1); 11 | 12 | template 13 | DeviceBuffer mult_vector(const DeviceBuffer &a, const T &b); 14 | 15 | template 16 | DeviceTripletMatrix add_triplet(const DeviceTripletMatrix &a, const DeviceTripletMatrix &b, const T &factor1 = 1, const T &factor2 = 1); 17 | 18 | template 19 | T max_vector(const DeviceBuffer &a); 20 | 21 | template 22 | T min_vector(const DeviceBuffer &a); 23 | 24 | template 25 | void search_dir(const DeviceBuffer &grad, const DeviceTripletMatrix &hess, DeviceBuffer &dir, const DeviceBuffer &DBC, const std::vector &DBC_target, std::vector &DBC_satified); 26 | 27 | template 28 | void display_vec(const DeviceBuffer &vec); 29 | 30 | template 31 | void set_DBC(DeviceBuffer &grad, DeviceCSRMatrix &hess, const DeviceBuffer &DBC, const std::vector &DBC_target, std::vector &DBC_satified); 32 | 33 | template 34 | __device__ T smallest_positive_real_root_quad(T a, T b, T c); -------------------------------------------------------------------------------- /simulators/8_self_friction/src/GravityEnergy.cu: -------------------------------------------------------------------------------- 1 | #include "GravityEnergy.h" 2 | #include "uti.h" 3 | #include 4 | #include 5 | #include "device_uti.h" 6 | #define GRAVITY -9.81 7 | using namespace muda; 8 | 9 | template 10 | struct GravityEnergy::Impl 11 | { 12 | DeviceBuffer device_x, device_grad; 13 | int N; 14 | T m, val; 15 | Impl(int N, T m); 16 | }; 17 | template 18 | GravityEnergy::GravityEnergy() = default; 19 | 20 | template 21 | GravityEnergy::~GravityEnergy() = default; 22 | 23 | template 24 | GravityEnergy::GravityEnergy(GravityEnergy &&rhs) = default; 25 | 26 | template 27 | GravityEnergy &GravityEnergy::operator=(GravityEnergy &&rhs) = default; 28 | 29 | template 30 | GravityEnergy::GravityEnergy(const GravityEnergy &rhs) 31 | : pimpl_{std::make_unique(*rhs.pimpl_)} {} 32 | 33 | template 34 | GravityEnergy::GravityEnergy(int N, T m) : pimpl_{std::make_unique(N, m)} 35 | { 36 | } 37 | 38 | template 39 | GravityEnergy::Impl::Impl(int N_, T m_) : N(N_), m(m_) 40 | { 41 | device_x.resize(N * dim); 42 | device_grad.resize(N * dim); 43 | } 44 | 45 | template 46 | void GravityEnergy::update_x(const DeviceBuffer &x) 47 | { 48 | pimpl_->device_x.view().copy_from(x); 49 | } 50 | 51 | template 52 | void GravityEnergy::update_m(T m) 53 | { 54 | pimpl_->m = m; 55 | } 56 | 57 | template 58 | T GravityEnergy::val() 59 | { 60 | auto &device_x = pimpl_->device_x; 61 | auto &m = pimpl_->m; 62 | auto N = pimpl_->N * dim; 63 | DeviceBuffer device_val(N); 64 | ParallelFor(256) 65 | .apply(N, 66 | [device_val = device_val.viewer(), device_x = device_x.cviewer(), m] __device__(int i) mutable 67 | { 68 | device_val(i) = i % dim == 1 ? -m * GRAVITY * device_x(i) : 0; 69 | }) 70 | .wait(); 71 | return devicesum(device_val); 72 | } 73 | 74 | template 75 | const DeviceBuffer &GravityEnergy::grad() 76 | { 77 | auto &device_x = pimpl_->device_x; 78 | auto m = pimpl_->m; 79 | auto N = pimpl_->N * dim; 80 | auto &device_grad = pimpl_->device_grad; 81 | ParallelFor(256) 82 | .apply(N, 83 | [device_x = device_x.cviewer(), m, N, device_grad = device_grad.viewer()] __device__(int i) mutable 84 | { 85 | device_grad(i) = i % dim == 1 ? -m * GRAVITY : 0; 86 | }) 87 | .wait(); 88 | // display_vec(device_grad); 89 | return device_grad; 90 | } // Calculate the gradient of the energy 91 | 92 | template class GravityEnergy; 93 | template class GravityEnergy; 94 | template class GravityEnergy; 95 | template class GravityEnergy; 96 | -------------------------------------------------------------------------------- /simulators/8_self_friction/src/InertialEnergy.cu: -------------------------------------------------------------------------------- 1 | #include "InertialEnergy.h" 2 | #include "uti.h" 3 | #include 4 | #include 5 | #include "device_uti.h" 6 | 7 | using namespace muda; 8 | 9 | template 10 | struct InertialEnergy::Impl 11 | { 12 | DeviceBuffer device_x, device_x_tilde, device_grad; 13 | DeviceTripletMatrix device_hess; 14 | int N; 15 | T m, val; 16 | Impl(int N, T m); 17 | }; 18 | template 19 | InertialEnergy::InertialEnergy() = default; 20 | 21 | template 22 | InertialEnergy::~InertialEnergy() = default; 23 | 24 | template 25 | InertialEnergy::InertialEnergy(InertialEnergy &&rhs) = default; 26 | 27 | template 28 | InertialEnergy &InertialEnergy::operator=(InertialEnergy &&rhs) = default; 29 | 30 | template 31 | InertialEnergy::InertialEnergy(const InertialEnergy &rhs) 32 | : pimpl_{std::make_unique(*rhs.pimpl_)} {} 33 | 34 | template 35 | InertialEnergy::InertialEnergy(int N, T m) : pimpl_{std::make_unique(N, m)} 36 | { 37 | generate_hess(); 38 | } 39 | 40 | template 41 | InertialEnergy::Impl::Impl(int N_, T m_) : N(N_), m(m_) 42 | { 43 | device_x.resize(N * dim); 44 | device_x_tilde.resize(N * dim); 45 | device_hess.resize_triplets(N * dim); 46 | device_hess.reshape(N * dim, N * dim); 47 | device_grad.resize(N * dim); 48 | } 49 | template 50 | void InertialEnergy::generate_hess() 51 | { 52 | auto &device_hess = pimpl_->device_hess; 53 | auto m = pimpl_->m; 54 | auto N = pimpl_->N; 55 | ParallelFor(256) 56 | .apply(N * dim, 57 | [device_hess_row_indices = device_hess.row_indices().viewer(), device_hess_col_indices = device_hess.col_indices().viewer(), 58 | device_hess_values = device_hess.values().viewer(), m] __device__(int i) mutable 59 | { 60 | device_hess_row_indices(i) = i; 61 | device_hess_col_indices(i) = i; 62 | device_hess_values(i) = m; 63 | }) 64 | .wait(); 65 | } 66 | 67 | template 68 | void InertialEnergy::update_x(const DeviceBuffer &x) 69 | { 70 | pimpl_->device_x.view().copy_from(x); 71 | } 72 | 73 | template 74 | void InertialEnergy::update_x_tilde(const DeviceBuffer &x_tilde) 75 | { 76 | pimpl_->device_x_tilde.view().copy_from(x_tilde); 77 | } 78 | 79 | template 80 | void InertialEnergy::update_m(T m) 81 | { 82 | pimpl_->m = m; 83 | } 84 | 85 | template 86 | T InertialEnergy::val() 87 | { 88 | auto &device_x = pimpl_->device_x; 89 | auto &device_x_tilde = pimpl_->device_x_tilde; 90 | auto &m = pimpl_->m; 91 | auto N = pimpl_->N * dim; 92 | DeviceBuffer device_val(N); 93 | ParallelFor(256) 94 | .apply(N, 95 | [device_val = device_val.viewer(), device_x = device_x.cviewer(), device_x_tilde = device_x_tilde.cviewer(), m] __device__(int i) mutable 96 | { 97 | device_val(i) = 0.5 * m * (device_x(i) - device_x_tilde(i)) * (device_x(i) - device_x_tilde(i)); 98 | }) 99 | .wait(); 100 | return devicesum(device_val); 101 | } 102 | 103 | template 104 | const DeviceBuffer &InertialEnergy::grad() 105 | { 106 | auto &device_x = pimpl_->device_x; 107 | auto &device_x_tilde = pimpl_->device_x_tilde; 108 | auto m = pimpl_->m; 109 | auto N = pimpl_->N * dim; 110 | auto &device_grad = pimpl_->device_grad; 111 | ParallelFor(256) 112 | .apply(N, 113 | [device_x = device_x.cviewer(), device_x_tilde = device_x_tilde.cviewer(), m, N, device_grad = device_grad.viewer()] __device__(int i) mutable 114 | { 115 | device_grad(i) = m * (device_x(i) - device_x_tilde(i)); 116 | }) 117 | .wait(); 118 | // display_vec(device_grad); 119 | return device_grad; 120 | } // Calculate the gradient of the energy 121 | 122 | template 123 | const DeviceTripletMatrix &InertialEnergy::hess() 124 | { 125 | return pimpl_->device_hess; 126 | } // Calculate the Hessian matrix of the energy 127 | 128 | template class InertialEnergy; 129 | template class InertialEnergy; 130 | template class InertialEnergy; 131 | template class InertialEnergy; 132 | -------------------------------------------------------------------------------- /simulators/8_self_friction/src/device_uti.cu: -------------------------------------------------------------------------------- 1 | #include "device_uti.h" 2 | using namespace muda; 3 | 4 | template 5 | T devicesum(const DeviceBuffer &buffer) 6 | { 7 | T sum = 0.0f; // Result of the reduction 8 | T *d_out; // Device memory to store the result of the reduction 9 | cudaMalloc(&d_out, sizeof(T)); // Allocate memory for the result 10 | 11 | // DeviceReduce is assumed to be part of the 'muda' library or similar 12 | DeviceReduce().Sum(buffer.data(), d_out, buffer.size()); 13 | 14 | // Copy the result back to the host 15 | cudaMemcpy(&sum, d_out, sizeof(T), cudaMemcpyDeviceToHost); 16 | 17 | // Clean up 18 | cudaFree(d_out); 19 | return sum; 20 | } 21 | template float devicesum(const DeviceBuffer &); 22 | template double devicesum(const DeviceBuffer &); 23 | 24 | template 25 | void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD) 26 | { 27 | Eigen::SelfAdjointEigenSolver> eigensolver(hess); 28 | Eigen::Matrix lam = eigensolver.eigenvalues(); 29 | Eigen::Matrix V = eigensolver.eigenvectors(); 30 | // set all negative eigenvalues to zero 31 | Eigen::Matrix lamDiag; 32 | lamDiag.setZero(); 33 | for (int i = 0; i < Size; i++) 34 | if (lam(i) > 0) 35 | lamDiag(i, i) = lam(i); 36 | 37 | Eigen::Matrix VT = V.transpose(); 38 | 39 | PSD = V * lamDiag * VT; 40 | } 41 | 42 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 43 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 44 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 45 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 46 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 47 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 48 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); 49 | template void __device__ make_PSD(const Eigen::Matrix &hess, Eigen::Matrix &PSD); -------------------------------------------------------------------------------- /simulators/8_self_friction/src/distance/CCD.cu: -------------------------------------------------------------------------------- 1 | #include "distance.h" 2 | template 3 | __device__ __host__ bool bbox_overlap(const Eigen::Matrix &p, const Eigen::Matrix &e0, const Eigen::Matrix &e1, 4 | const Eigen::Matrix &dp, const Eigen::Matrix &de0, const Eigen::Matrix &de1, 5 | T toc_upperbound) 6 | { 7 | Eigen::Matrix max_p = p.cwiseMax(p + toc_upperbound * dp); // point trajectory bbox top-right 8 | Eigen::Matrix min_p = p.cwiseMin(p + toc_upperbound * dp); // point trajectory bbox bottom-left 9 | Eigen::Matrix max_e = e0.cwiseMax(e0 + toc_upperbound * de0).cwiseMax(e1.cwiseMax(e1 + toc_upperbound * de1)); // edge trajectory bbox top-right 10 | Eigen::Matrix min_e = e0.cwiseMin(e0 + toc_upperbound * de0).cwiseMin(e1.cwiseMin(e1 + toc_upperbound * de1)); // edge trajectory bbox bottom-left 11 | 12 | if (min_p[0] > max_e[0] || min_p[1] > max_e[1] || min_e[0] > max_p[0] || min_e[1] > max_p[1]) // no overlap 13 | { 14 | return false; 15 | } 16 | else 17 | { 18 | return true; 19 | } 20 | } 21 | 22 | template 23 | __device__ __host__ T narrow_phase_CCD(Eigen::Matrix p, Eigen::Matrix e0, Eigen::Matrix e1, 24 | Eigen::Matrix dp, Eigen::Matrix de0, Eigen::Matrix de1, 25 | T toc_upperbound) 26 | { 27 | // use relative displacement for faster convergence 28 | Eigen::Matrix mov = (dp + de0 + de1) / 3.0; 29 | de0 -= mov; 30 | de1 -= mov; 31 | dp -= mov; 32 | T maxDispMag = dp.norm() + std::sqrt(std::max(de0.dot(de0), de1.dot(de1))); 33 | if (maxDispMag == 0) 34 | { 35 | return toc_upperbound; 36 | } 37 | T eta = 0.1; // calculate the toc that first brings the distance to 0.1x the current distance 38 | T dist2_cur = PointEdgeDistanceVal(p, e0, e1); 39 | T dist_cur = std::sqrt(dist2_cur); 40 | T gap = eta * dist_cur; 41 | // iteratively move the point and edge towards each other and 42 | // grow the toc estimate without numerical errors 43 | T toc = 0; 44 | while (true) 45 | { 46 | T tocLowerBound = (1 - eta) * dist_cur / maxDispMag; 47 | 48 | p += tocLowerBound * dp; 49 | e0 += tocLowerBound * de0; 50 | e1 += tocLowerBound * de1; 51 | dist2_cur = PointEdgeDistanceVal(p, e0, e1); 52 | dist_cur = std::sqrt(dist2_cur); 53 | if (toc != 0 && dist_cur < gap) 54 | { 55 | break; 56 | } 57 | 58 | toc += tocLowerBound; 59 | if (toc > toc_upperbound) 60 | { 61 | return toc_upperbound; 62 | } 63 | } 64 | 65 | return toc; 66 | } 67 | 68 | template __device__ __host__ bool bbox_overlap(const Eigen::Matrix &p, const Eigen::Matrix &e0, const Eigen::Matrix &e1, 69 | const Eigen::Matrix &dp, const Eigen::Matrix &de0, const Eigen::Matrix &de1, 70 | float toc_upperbound); 71 | template __device__ __host__ bool bbox_overlap(const Eigen::Matrix &p, const Eigen::Matrix &e0, const Eigen::Matrix &e1, 72 | const Eigen::Matrix &dp, const Eigen::Matrix &de0, const Eigen::Matrix &de1, 73 | double toc_upperbound); 74 | template __device__ __host__ float narrow_phase_CCD(Eigen::Matrix p, Eigen::Matrix e0, Eigen::Matrix e1, 75 | Eigen::Matrix dp, Eigen::Matrix de0, Eigen::Matrix de1, 76 | float toc_upperbound); 77 | 78 | template __device__ __host__ double narrow_phase_CCD(Eigen::Matrix p, Eigen::Matrix e0, Eigen::Matrix e1, 79 | Eigen::Matrix dp, Eigen::Matrix de0, Eigen::Matrix de1, 80 | double toc_upperbound); -------------------------------------------------------------------------------- /simulators/8_self_friction/src/distance/PointEdgeDistance.cu: -------------------------------------------------------------------------------- 1 | #include "distance.h" 2 | 3 | template 4 | __device__ __host__ T PointEdgeDistanceVal(const Eigen::Vector &p, const Eigen::Vector &e0, const Eigen::Vector &e1) 5 | { 6 | Eigen::Vector e = e1 - e0; 7 | T ratio = e.dot(p - e0) / e.dot(e); 8 | if (ratio < 0) 9 | { 10 | return PointPointDistanceVal(p, e0); 11 | } 12 | else if (ratio > 1) 13 | { 14 | return PointPointDistanceVal(p, e1); 15 | } 16 | else 17 | { 18 | T val; 19 | PointLineDistanceVal(val, p, e0, e1); 20 | return val; 21 | } 22 | } 23 | 24 | template 25 | __device__ __host__ Eigen::Matrix PointEdgeDistanceGrad(const Eigen::Vector &p, const Eigen::Vector &e0, const Eigen::Vector &e1) 26 | { 27 | Eigen::Vector e = e1 - e0; 28 | T ratio = e.dot(p - e0) / e.dot(e); 29 | if (ratio < 0) 30 | { 31 | Eigen::Matrix g_PP = PointPointDistanceGrad(p, e0); 32 | Eigen::Matrix gradient; 33 | gradient << g_PP.template segment<2>(0), g_PP.template segment<2>(2), Eigen::Matrix::Zero(); 34 | return gradient; 35 | } 36 | else if (ratio > 1) 37 | { 38 | Eigen::Matrix g_PP = PointPointDistanceGrad(p, e1); 39 | Eigen::Matrix gradient; 40 | gradient << g_PP.template segment<2>(0), Eigen::Matrix::Zero(), g_PP.template segment<2>(2); 41 | return gradient; 42 | } 43 | else 44 | { 45 | Eigen::Matrix grad; 46 | PointLineDistanceGrad(grad, p, e0, e1); 47 | return grad; 48 | } 49 | } 50 | 51 | template 52 | __device__ __host__ Eigen::Matrix PointEdgeDistanceHess(const Eigen::Vector &p, const Eigen::Vector &e0, const Eigen::Vector &e1) 53 | { 54 | Eigen::Vector e = e1 - e0; 55 | T ratio = e.dot(p - e0) / e.dot(e); 56 | if (ratio < 0) 57 | { 58 | Eigen::Matrix H_PP = PointPointDistanceHess(p, e0); 59 | Eigen::Matrix H; 60 | H.setZero(); 61 | H.template block<2, 2>(0, 0) = H_PP.template block<2, 2>(0, 0); 62 | H.template block<2, 2>(0, 2) = H_PP.template block<2, 2>(0, 2); 63 | H.template block<2, 2>(2, 0) = H_PP.template block<2, 2>(2, 0); 64 | H.template block<2, 2>(2, 2) = H_PP.template block<2, 2>(2, 2); 65 | return H; 66 | } 67 | else if (ratio > 1) 68 | { 69 | Eigen::Matrix H_PP = PointPointDistanceHess(p, e1); 70 | Eigen::Matrix H; 71 | H.setZero(); 72 | H.template block<2, 2>(0, 0) = H_PP.template block<2, 2>(0, 0); 73 | H.template block<2, 2>(0, 4) = H_PP.template block<2, 2>(0, 2); 74 | H.template block<2, 2>(4, 0) = H_PP.template block<2, 2>(2, 0); 75 | H.template block<2, 2>(4, 4) = H_PP.template block<2, 2>(2, 2); 76 | return H; 77 | } 78 | else 79 | { 80 | Eigen::Matrix hess; 81 | PointLineDistanceHess(hess, p, e0, e1); 82 | return hess; 83 | } 84 | } 85 | 86 | template __device__ __host__ float PointEdgeDistanceVal(const Eigen::Vector2f &p, const Eigen::Vector2f &e0, const Eigen::Vector2f &e1); 87 | template __device__ __host__ Eigen::Matrix PointEdgeDistanceGrad(const Eigen::Vector2f &p, const Eigen::Vector2f &e0, const Eigen::Vector2f &e1); 88 | template __device__ __host__ Eigen::Matrix PointEdgeDistanceHess(const Eigen::Vector2f &p, const Eigen::Vector2f &e0, const Eigen::Vector2f &e1); 89 | 90 | template __device__ __host__ double PointEdgeDistanceVal(const Eigen::Vector2d &p, const Eigen::Vector2d &e0, const Eigen::Vector2d &e1); 91 | template __device__ __host__ Eigen::Matrix PointEdgeDistanceGrad(const Eigen::Vector2d &p, const Eigen::Vector2d &e0, const Eigen::Vector2d &e1); 92 | template __device__ __host__ Eigen::Matrix PointEdgeDistanceHess(const Eigen::Vector2d &p, const Eigen::Vector2d &e0, const Eigen::Vector2d &e1); 93 | 94 | template 95 | __device__ __host__ void PointEdgeDistanceTangent(const Eigen::Vector& p, const Eigen::Vector& e0, const Eigen::Vector& e1, Eigen::Matrix& n, T& r) { 96 | Eigen::Vector e = e1 - e0; 97 | r = e.dot(p - e0) / e.dot(e); 98 | if (r < 0) { 99 | n = p - e0; 100 | } 101 | else if (r > 1) { 102 | n = p - e1; 103 | } 104 | else { 105 | n = p - ((1-r)*e0+r*e1); 106 | } 107 | n = n.normalized(); 108 | } 109 | 110 | template __device__ __host__ void PointEdgeDistanceTangent(const Eigen::Vector2f& p, const Eigen::Vector2f& e0, const Eigen::Vector2f& e1, Eigen::Vector2f& n, float& r); 111 | template __device__ __host__ void PointEdgeDistanceTangent(const Eigen::Vector2d& p, const Eigen::Vector2d& e0, const Eigen::Vector2d& e1, Eigen::Vector2d& n, double& r); 112 | -------------------------------------------------------------------------------- /simulators/8_self_friction/src/distance/PointPointDistance.cu: -------------------------------------------------------------------------------- 1 | #include "distance.h" 2 | 3 | template 4 | __device__ __host__ T PointPointDistanceVal(const Eigen::Vector &p0, const Eigen::Vector &p1) 5 | { 6 | Eigen::Vector e = p0 - p1; 7 | return e.dot(e); 8 | } 9 | 10 | template 11 | __device__ __host__ Eigen::Matrix PointPointDistanceGrad(const Eigen::Vector &p0, const Eigen::Vector &p1) 12 | { 13 | Eigen::Vector e = p0 - p1; 14 | Eigen::Matrix gradient; 15 | gradient << 2 * e(0), 2 * e(1), -2 * e(0), -2 * e(1); 16 | return gradient; 17 | } 18 | 19 | template 20 | __device__ __host__ Eigen::Matrix PointPointDistanceHess(const Eigen::Vector &p0, const Eigen::Vector &p1) 21 | { 22 | Eigen::Matrix H = Eigen::Matrix::Zero(); 23 | H(0, 0) = H(1, 1) = H(2, 2) = H(3, 3) = 2; 24 | H(0, 2) = H(1, 3) = H(2, 0) = H(3, 1) = -2; 25 | return H; 26 | } 27 | 28 | template __device__ __host__ float PointPointDistanceVal(const Eigen::Vector2f &p0, const Eigen::Vector2f &p1); 29 | template __device__ __host__ Eigen::Matrix PointPointDistanceGrad(const Eigen::Vector2f &p0, const Eigen::Vector2f &p1); 30 | template __device__ __host__ Eigen::Matrix PointPointDistanceHess(const Eigen::Vector2f &p0, const Eigen::Vector2f &p1); 31 | 32 | template __device__ __host__ double PointPointDistanceVal(const Eigen::Vector2d &p0, const Eigen::Vector2d &p1); 33 | template __device__ __host__ Eigen::Matrix PointPointDistanceGrad(const Eigen::Vector2d &p0, const Eigen::Vector2d &p1); 34 | template __device__ __host__ Eigen::Matrix PointPointDistanceHess(const Eigen::Vector2d &p0, const Eigen::Vector2d &p1); -------------------------------------------------------------------------------- /simulators/8_self_friction/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "simulator.h" 2 | #include "Eigen/Dense" 3 | #include 4 | int main() 5 | { 6 | double nu = 0.4, E = 1e5; 7 | double Mu = E / (2 * (1 + nu)), Lam = E * nu / ((1 + nu) * (1 - 2 * nu)); 8 | double rho = 1000, 9 | k = 4e4, initial_stretch = 1, n_seg = 6, h = 0.01, side_len = 0.45, tol = 0.01, mu = 0.4; 10 | SelfFrictionSimulator simulator(rho, side_len, initial_stretch, k, h, tol, mu, Mu, Lam, n_seg); 11 | simulator.run(); 12 | } -------------------------------------------------------------------------------- /simulators/8_self_friction/src/square_mesh.cpp: -------------------------------------------------------------------------------- 1 | #include "square_mesh.h" 2 | #include 3 | template 4 | void generate(T side_length, int n_seg, std::vector &x, std::vector &e) 5 | { 6 | int dim = n_seg + 1; 7 | int num_nodes = dim * dim; 8 | x.resize(num_nodes * 2); 9 | 10 | T step = side_length / n_seg; 11 | 12 | // Populate the coordinates 13 | for (int i = 0; i < dim; ++i) 14 | { 15 | for (int j = 0; j < dim; ++j) 16 | { 17 | x[(i * dim + j) * 2] = -side_length / 2 + i * step; 18 | x[(i * dim + j) * 2 + 1] = -side_length / 2 + j * step; 19 | } 20 | } 21 | 22 | // Clear and reserve space for edges 23 | e.clear(); 24 | e.reserve(2 * n_seg * n_seg * 3); 25 | 26 | // Triangulate the grid 27 | for (int i = 0; i < n_seg; ++i) 28 | { 29 | for (int j = 0; j < n_seg; ++j) 30 | { 31 | if ((i % 2) ^ (j % 2)) 32 | { 33 | e.push_back(i * dim + j); 34 | e.push_back((i + 1) * dim + j); 35 | e.push_back(i * dim + j + 1); 36 | 37 | e.push_back((i + 1) * dim + j); 38 | e.push_back((i + 1) * dim + j + 1); 39 | e.push_back(i * dim + j + 1); 40 | } 41 | else 42 | { 43 | e.push_back(i * dim + j); 44 | e.push_back((i + 1) * dim + j); 45 | e.push_back((i + 1) * dim + j + 1); 46 | 47 | e.push_back(i * dim + j); 48 | e.push_back((i + 1) * dim + j + 1); 49 | e.push_back(i * dim + j + 1); 50 | } 51 | } 52 | } 53 | } 54 | 55 | template void generate(float side_length, int n_seg, std::vector &x, std::vector &e); 56 | template void generate(double side_length, int n_seg, std::vector &x, std::vector &e); 57 | template void generate(long double side_length, int n_seg, std::vector &x, std::vector &e); 58 | 59 | void find_boundary(const std::vector &e, std::vector &bp, std::vector &be) 60 | { 61 | // index all half-edges for fast query 62 | std::set> edge_set; 63 | for (size_t i = 0; i < e.size() / 3; i++) 64 | { 65 | for (int j = 0; j < 3; ++j) 66 | { 67 | edge_set.insert({e[i * 3 + j], e[i * 3 + (j + 1) % 3]}); 68 | } 69 | } 70 | 71 | // find boundary points and edges 72 | std::set bp_set; 73 | for (const auto &eI : edge_set) 74 | { 75 | if (edge_set.find({eI.second, eI.first}) == edge_set.end()) 76 | { 77 | // if the inverse edge of a half-edge does not exist, 78 | // then it is a boundary edge 79 | be.push_back(eI.first); 80 | be.push_back(eI.second); 81 | bp_set.insert(eI.first); 82 | bp_set.insert(eI.second); 83 | } 84 | } 85 | 86 | // Convert set to vector 87 | bp.assign(bp_set.begin(), bp_set.end()); 88 | } 89 | -------------------------------------------------------------------------------- /simulators/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(1_mass_spring) 2 | add_subdirectory(2_dirichlet) 3 | add_subdirectory(3_contact) 4 | add_subdirectory(4_friction) 5 | add_subdirectory(5_mov_dirichlet) 6 | add_subdirectory(6_inv_free) 7 | add_subdirectory(7_self_contact) 8 | add_subdirectory(8_self_friction) --------------------------------------------------------------------------------