diff --git a/.vscode/settings.json b/.vscode/settings.json index 1435a069..79b53ab4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -24,6 +24,11 @@ "pool.h": "c", "mainfunctions.h": "c", "solver_consts.h": "c", - "public.h": "c" + "public.h": "c", + "islandsolver.h": "c", + "stb_ds.h": "c", + "test.h": "c", + "stdlib.h": "c", + "chunk_test_utils.h": "c" } } \ No newline at end of file diff --git a/src/main/c/includes/fluid/chunk.h b/src/main/c/includes/fluid/chunk.h index 63aa0c6b..2ed02690 100644 --- a/src/main/c/includes/fluid/chunk.h +++ b/src/main/c/includes/fluid/chunk.h @@ -28,6 +28,22 @@ typedef struct { float * w0[27]; int chunkMask; jobject chunkJRaw; + + /** + * The world x coordinate of this chunk + */ + int x; + + /** + * The world y coordinate of this chunk + */ + int y; + + /** + * The world z coordinate of this chunk + */ + int z; + } Chunk; /** @@ -40,25 +56,45 @@ typedef struct { */ #define SPARSE_ARRAY_CHUNK_DIM 7 +/** + * The number of chunks to place next to one another + */ +#define SPARSE_ARRAY_CHUNK_RADIUS 3 + /** * The total number of chunks in the chunk tracking array */ -#define SPARSE_ARRAY_TOTAL_CHUNKS SPARSE_ARRAY_CHUNK_DIM * SPARSE_ARRAY_CHUNK_DIM * SPARSE_ARRAY_CHUNK_DIM +#define SPARSE_ARRAY_TOTAL_CHUNKS (SPARSE_ARRAY_CHUNK_DIM * SPARSE_ARRAY_CHUNK_DIM * SPARSE_ARRAY_CHUNK_DIM) /** * The extra values at the edges of the sparse array (to allow pulling data from borders) */ #define SPARSE_ARRAY_BORDER_SIZE 2 +/** + * The size of the real data in the sparse array (not including bounds) + */ +#define SPARSE_ARRAY_REAL_DATA_SIZE (SPARSE_ARRAY_CHUNK_DIM * MAIN_ARRAY_DIM) + /** * The size of the dimension of the memory of the sparse array */ -#define SPARSE_ARRAY_RAW_DIM ((SPARSE_ARRAY_CHUNK_DIM * MAIN_ARRAY_DIM) + SPARSE_ARRAY_BORDER_SIZE) +#define SPARSE_ARRAY_RAW_DIM (SPARSE_ARRAY_REAL_DATA_SIZE + SPARSE_ARRAY_BORDER_SIZE) /** * The size of a sparse array in number of elements */ -#define SPARSE_ARRAY_FULL_SIZE SPARSE_ARRAY_RAW_DIM * SPARSE_ARRAY_RAW_DIM * SPARSE_ARRAY_RAW_DIM +#define SPARSE_ARRAY_FULL_SIZE (SPARSE_ARRAY_RAW_DIM * SPARSE_ARRAY_RAW_DIM * SPARSE_ARRAY_RAW_DIM) + +/** + * The unit of spacial distance + */ +#define SPATIAL_UNIT 1 + +/** + * The size of the sparse array in spatial units + */ +#define SPARSE_ARRAY_SPATIAL_SIZE (SPARSE_ARRAY_RAW_DIM * SPATIAL_UNIT) /** * A set of sparse matricies for simulating fluids @@ -138,4 +174,17 @@ LIBRARY_API void fluid_sparse_array_remove_chunk(SparseChunkArray * array, Chunk */ LIBRARY_API int fluid_sparse_array_get_index(SparseChunkArray * array, int x, int y, int z); +/** + * Cleans the sparse array + */ +LIBRARY_API void fluid_sparse_array_clean(SparseChunkArray * array); + +/** + * Gets the number of chunks in the sparse array + */ +LIBRARY_API int fluid_sparse_array_get_chunk_count(SparseChunkArray * array); + +int GCI(int x, int y, int z); +int GVI(int x, int y, int z); + #endif \ No newline at end of file diff --git a/src/main/c/includes/fluid/islandsolver.h b/src/main/c/includes/fluid/islandsolver.h new file mode 100644 index 00000000..8cbbb7da --- /dev/null +++ b/src/main/c/includes/fluid/islandsolver.h @@ -0,0 +1,79 @@ + + +//Must be included for public functions to be imported/exported on windows +#include "public.h" + +#ifndef ISLANDSOLVER_H +#define ISLANDSOLVER_H + +#include "chunk.h" + +/** + * A set of sparse matricies for simulating fluids + */ +typedef struct { + + /** + * The chunks that still need to be solved + */ + Chunk ** remaining; + + /** + * The chunks that have already been solved for + */ + Chunk ** solved; + + /** + * The sparse array + */ + SparseChunkArray * sparseArray; + + /** + * The number of chunks in the currently solved island + */ + int currentChunks; + +} FluidIslandSolver; + +/** + * Creates a fluid island solver + */ +LIBRARY_API FluidIslandSolver * fluid_island_solver_create(); + +/** + * Frees a fluid island solver + */ +LIBRARY_API void fluid_island_solver_free(FluidIslandSolver * solver); + +/** + * Adds a chunk to the fluid island solver + */ +LIBRARY_API void fluid_island_solver_add_chunk(FluidIslandSolver * solver, Chunk * chunk); + +/** + * Adds a chunk to the fluid island solver + */ +LIBRARY_API void fluid_island_solver_remove_chunk(FluidIslandSolver * solver, Chunk * chunk); + +/** + * Solves for the next available island + */ +LIBRARY_API void fluid_island_solver_solve_island(FluidIslandSolver * solver); + +/** + * Gets the number of chunks in the current island + */ +LIBRARY_API int fluid_island_solver_get_chunk_count(FluidIslandSolver * solver); + +/** + * Gets the sparse array in the solver + */ +LIBRARY_API SparseChunkArray * fluid_island_solver_get_sparse_array(FluidIslandSolver * solver); + +/** + * Gets the number of chunks that still need to be solved for + */ +LIBRARY_API int fluid_island_solver_get_remaining(FluidIslandSolver * solver); + + +#endif \ No newline at end of file diff --git a/src/main/c/includes/fluid/sparsesimulator.h b/src/main/c/includes/fluid/sparsesimulator.h new file mode 100644 index 00000000..11c43e82 --- /dev/null +++ b/src/main/c/includes/fluid/sparsesimulator.h @@ -0,0 +1,74 @@ +#ifndef SPARSESIMULATOR_H +#define SPARSESIMULATOR_H + +//Must be included for public functions to be imported/exported on windows +#include "public.h" + +#include "chunk.h" + +/** + * Simulates a sparse array + */ +LIBRARY_API int fluid_sparse_array_simulate(SparseChunkArray * array, float dt); + +/** + * Adds values from a source array to a current frame array (eg more density to the main density array) + * @param x The array to store into + * @param s The source array to pull from + * @param dt The delta time of the simulation +*/ +void fluid_sparse_array_add_source(float * x, float * s, float dt); + +/** + * Diffuses an array + * @param b The axis to diffuse along + * @param x The array to store the diffuse values + * @param x0 The array that contains the first order derivatives + * @param diff The diffuse constant + * @param dt The delta time of the simulation + */ +LIBRARY_API void fluid_sparse_array_diffuse(int b, float * x, float * x0, float diff, float dt); + +/** + * Advects an array + */ +LIBRARY_API void fluid_sparse_array_advect(int N, int b, float * d, float * d0, float * u, float * v, float * w, float dt); + +/** + * Projects an array + */ +LIBRARY_API void fluid_sparse_array_project(int N, float * u, float * v, float * w, float * p, float * div); + +/** + * Sets the bounds of the simulation + * @param b The axis to set bounds along + * @param target The array to set the bounds of +*/ +LIBRARY_API void fluid_sparse_array_set_bnd(int b, float * target); + +/** + * Performs the density step + * @param x The density array + * @param x0 The delta-density array + * @param u The x velocity array + * @param v The y velocity array + * @param w THe z velocity array + * @param diff The diffuse constant + * @param dt The delta time for the simulation + */ +LIBRARY_API void fluid_sparse_array_dens_step(float * x, float * x0, float * u, float * v, float * w, float diff, float dt); + +/** + * Performs the velocity step + */ +LIBRARY_API void fluid_sparse_array_vel_step(int N, float * u, float * v, float * w, float * u0, float * v0, float * w0, float visc, float dt); + +/** + * Solves a linear system of equations in a vectorized manner + * @param b The axis to set the bounds along + * @param x The array that will contain the solved equations + * @param x0 The array containing the first order derivatives +*/ +LIBRARY_API void fluid_sparse_array_lin_solve(int b, float * x, float * x0); + +#endif \ No newline at end of file diff --git a/src/main/c/src/CMakeLists.txt b/src/main/c/src/CMakeLists.txt index ac7e6755..66538c03 100644 --- a/src/main/c/src/CMakeLists.txt +++ b/src/main/c/src/CMakeLists.txt @@ -1,6 +1,6 @@ # Find sources -file(GLOB_RECURSE SOURCES "*.c") +file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS "*.c") # include jni set(JAVA_AWT_LIBRARY NotNeeded) diff --git a/src/main/c/src/fluid/chunk.c b/src/main/c/src/fluid/chunk.c index 6f6b1ae8..fa62f63d 100644 --- a/src/main/c/src/fluid/chunk.c +++ b/src/main/c/src/fluid/chunk.c @@ -7,8 +7,6 @@ -int GCI(int x, int y, int z); -int GVI(int x, int y, int z); int solveOffset(int chunkPos); /** @@ -156,9 +154,10 @@ LIBRARY_API void fluid_sparse_array_remove_chunk(SparseChunkArray * array, Chunk int minPos = (SPARSE_ARRAY_BORDER_SIZE / 2); int i, j, k; - for(int m = 0; m < MAIN_ARRAY_DIM; m++){ - for(int n = 0; n < MAIN_ARRAY_DIM; n++){ - for(int o = 0; o < MAIN_ARRAY_DIM; o++){ + //we add +1 to the dimension to copy the neighbors into the chunk + for(int m = 0; m < MAIN_ARRAY_DIM + 1; m++){ + for(int n = 0; n < MAIN_ARRAY_DIM + 1; n++){ + for(int o = 0; o < MAIN_ARRAY_DIM + 1; o++){ i = m + 1; j = n + 1; k = o + 1; @@ -223,6 +222,46 @@ LIBRARY_API int fluid_sparse_array_get_index(SparseChunkArray * array, int x, in return GVI(x,y,z); } +/** + * Cleans the sparse array + */ +LIBRARY_API void fluid_sparse_array_clean(SparseChunkArray * array){ + for(int x = 0; x < SPARSE_ARRAY_RAW_DIM; x++){ + for(int y = 0; y < SPARSE_ARRAY_RAW_DIM; y++){ + for(int z = 0; z < SPARSE_ARRAY_RAW_DIM; z++){ + array->d[GVI(x,y,z)] = 0; + array->d0[GVI(x,y,z)] = 0; + array->u[GVI(x,y,z)] = 0; + array->v[GVI(x,y,z)] = 0; + array->w[GVI(x,y,z)] = 0; + array->u0[GVI(x,y,z)] = 0; + array->v0[GVI(x,y,z)] = 0; + array->w0[GVI(x,y,z)] = 0; + } + } + } + for(int x = 0; x < SPARSE_ARRAY_CHUNK_DIM; x++){ + for(int y = 0; y < SPARSE_ARRAY_CHUNK_DIM; y++){ + for(int z = 0; z < SPARSE_ARRAY_CHUNK_DIM; z++){ + array->chunks[GCI(x,y,z)] = NULL; + } + } + } +} + +/** + * Gets the number of chunks in the sparse array + */ +LIBRARY_API int fluid_sparse_array_get_chunk_count(SparseChunkArray * array){ + int rVal = 0; + for(int i = 0; i < SPARSE_ARRAY_TOTAL_CHUNKS; i++){ + if(array->chunks[i] != NULL){ + rVal++; + } + } + return rVal; +} + /** * Gets the index of the chunk at a given position within the sparse array */ diff --git a/src/main/c/src/fluid/islandsolver.c b/src/main/c/src/fluid/islandsolver.c new file mode 100644 index 00000000..4e2f88ba --- /dev/null +++ b/src/main/c/src/fluid/islandsolver.c @@ -0,0 +1,141 @@ +#include +#include + +#include "../../lib/stb/stb_ds.h" + +#include "fluid/islandsolver.h" +#include "fluid/chunk.h" + + + + + + + +/** + * Creates a fluid island solver + */ +LIBRARY_API FluidIslandSolver * fluid_island_solver_create(){ + FluidIslandSolver * rVal = (FluidIslandSolver *)malloc(sizeof(FluidIslandSolver)); + + rVal->sparseArray = fluid_sparse_array_create(); + rVal->remaining = NULL; + rVal->solved = NULL; + rVal->currentChunks = 0; + + return rVal; +} + +/** + * Frees a fluid island solver + */ +LIBRARY_API void fluid_island_solver_free(FluidIslandSolver * solver){ + fluid_sparse_array_free(solver->sparseArray); + free(solver); +} + +/** + * Adds a chunk to the fluid island solver + */ +LIBRARY_API void fluid_island_solver_add_chunk(FluidIslandSolver * solver, Chunk * chunk){ + stbds_arrput(solver->remaining,chunk); +} + +/** + * Adds a chunk to the fluid island solver + */ +LIBRARY_API void fluid_island_solver_remove_chunk(FluidIslandSolver * solver, Chunk * chunk){ + for(int i = 0; i < stbds_arrlen(solver->remaining); i++){ + if(solver->remaining[i] == chunk){ + stbds_arrdel(solver->remaining,i); + i--; + } + } + for(int i = 0; i < stbds_arrlen(solver->solved); i++){ + if(solver->solved[i] == chunk){ + stbds_arrdel(solver->solved,i); + i--; + } + } +} + +/** + * Solves for the next available island + */ +LIBRARY_API void fluid_island_solver_solve_island(FluidIslandSolver * solver){ + if(fluid_island_solver_get_remaining(solver) < 1){ + printf("Tried to solve a solver with 0 remaining! \n"); + fflush(stdout); + return; + } + + //clear the existing values + fluid_sparse_array_clean(solver->sparseArray); + + //fill in sparse array based on the first found chunk + Chunk * target = stbds_arrpop(solver->remaining); + fluid_sparse_array_add_chunk( + solver->sparseArray, + target, + SPARSE_ARRAY_CHUNK_RADIUS, + SPARSE_ARRAY_CHUNK_RADIUS, + SPARSE_ARRAY_CHUNK_RADIUS + ); + + //add neighbors of the target + for(int i = 0; i < stbds_arrlen(solver->remaining); i++){ + Chunk * current = solver->remaining[i]; + // printf("%d %d %d %d %d\n", + // abs(current->x - target->x) <= SPARSE_ARRAY_CHUNK_RADIUS, + // abs(current->y - target->y) <= SPARSE_ARRAY_CHUNK_RADIUS, + // abs(current->z - target->z) <= SPARSE_ARRAY_CHUNK_RADIUS, + // target->x, + // current->x + // ); + if( + abs(current->x - target->x) <= SPARSE_ARRAY_CHUNK_RADIUS && + abs(current->y - target->y) <= SPARSE_ARRAY_CHUNK_RADIUS && + abs(current->z - target->z) <= SPARSE_ARRAY_CHUNK_RADIUS + ){ + //remove this chunk from the remaining array + stbds_arrdel(solver->remaining,i); + i--; + //add to sparse array + int xPos = SPARSE_ARRAY_CHUNK_RADIUS + (current->x - target->x); + int yPos = SPARSE_ARRAY_CHUNK_RADIUS + (current->y - target->y); + int zPos = SPARSE_ARRAY_CHUNK_RADIUS + (current->z - target->z); + if( + xPos < 0 || xPos >= SPARSE_ARRAY_CHUNK_DIM || + yPos < 0 || yPos >= SPARSE_ARRAY_CHUNK_DIM || + zPos < 0 || zPos >= SPARSE_ARRAY_CHUNK_DIM + ){ + printf("Invalid insertion position! %d %d %d \n",xPos,yPos,zPos); + fflush(stdout); + } + fluid_sparse_array_add_chunk(solver->sparseArray,current,xPos,yPos,zPos); + } + } +} + +/** + * Gets the number of chunks in the current island + */ +LIBRARY_API int fluid_island_solver_get_chunk_count(FluidIslandSolver * solver){ + return fluid_sparse_array_get_chunk_count(solver->sparseArray); +} + +/** + * Gets the sparse array in the solver + */ +LIBRARY_API SparseChunkArray * fluid_island_solver_get_sparse_array(FluidIslandSolver * solver){ + return solver->sparseArray; +} + +/** + * Gets the number of chunks that still need to be solved for + */ +LIBRARY_API int fluid_island_solver_get_remaining(FluidIslandSolver * solver){ + return stbds_arrlen(solver->remaining); +} + + diff --git a/src/main/c/src/fluid/sparsesimulator.c b/src/main/c/src/fluid/sparsesimulator.c new file mode 100644 index 00000000..cf7916ec --- /dev/null +++ b/src/main/c/src/fluid/sparsesimulator.c @@ -0,0 +1,192 @@ +#include +#include +#include + +#include "../../lib/stb/stb_ds.h" + +#include "fluid/chunk.h" +#include "fluid/islandsolver.h" +#include "fluid/sparsesimulator.h" +#include "fluid/utilities.h" + +#define LINEARSOLVERTIMES 10 + +/** + * Simulates a sparse array + */ +LIBRARY_API int fluid_sparse_array_simulate(SparseChunkArray * array, float dt){ + +} + + + + +/** + * Adds values from a source array to a current frame array (eg more density to the main density array) + * @param x The array to store into + * @param s The source array to pull from + * @param dt The delta time of the simulation +*/ +LIBRARY_API void fluid_sparse_array_add_source(float * x, float * s, float dt){ + int i; + int size=SPARSE_ARRAY_FULL_SIZE; + for(i=0; i SPARSE_ARRAY_RAW_DIM - (SPARSE_ARRAY_BORDER_SIZE / 2)){ + for(i = i - vectorSize; i < (SPARSE_ARRAY_RAW_DIM - (SPARSE_ARRAY_BORDER_SIZE / 2)); i++){ + /* + want to solve the second derivative of the grid + x0 stores the first derivative + start with x being 0 in all locations + then take the difference along x0 and store it in x + this is approximating the derivative + + equation looks something like + + 2nd deriv = x0 + + + */ + //phi is the scalar potential + //want to solve the laplacian + //laplacian is derivative of phi over the gid spacing squared along each dimension + //the derivative of phi is just phi(x+1) - 2 * phi(x) + phi(x-1) along each axis "x" + //we are grabbing phi from the x array + x[GVI(i,j,k)] = (x0[GVI(i,j,k)] + a*(x[GVI(i-1,j,k)]+x[GVI(i+1,j,k)]+x[GVI(i,j-1,k)]+x[GVI(i,j+1,k)]+x[GVI(i,j,k-1)]+x[GVI(i,j,k+1)]))/c; + } + } + } + } + fluid_sparse_array_set_bnd(b, x); + } +} + +/** + * Sets the bounds of the simulation + * @param b The axis to set bounds along + * @param target The array to set the bounds of +*/ +LIBRARY_API void fluid_sparse_array_set_bnd(int b, float * target){ + for(int x=1; x < SPARSE_ARRAY_RAW_DIM-1; x++){ + for(int y = 1; y < SPARSE_ARRAY_RAW_DIM-1; y++){ + //((x)+(DIM)*(y) + (DIM)*(DIM)*(z)) + target[0 + SPARSE_ARRAY_RAW_DIM * x + SPARSE_ARRAY_RAW_DIM * SPARSE_ARRAY_RAW_DIM * y] = + b==1 ? + -target[1 + SPARSE_ARRAY_RAW_DIM * x + SPARSE_ARRAY_RAW_DIM * SPARSE_ARRAY_RAW_DIM * y] + : + target[1 + SPARSE_ARRAY_RAW_DIM * x + SPARSE_ARRAY_RAW_DIM * SPARSE_ARRAY_RAW_DIM * y] + ; + target[IX(SPARSE_ARRAY_RAW_DIM-1,x,y)] = b==1 ? -target[IX(SPARSE_ARRAY_RAW_DIM-2,x,y)] : target[IX(SPARSE_ARRAY_RAW_DIM-2,x,y)]; + target[IX(x,0,y)] = b==2 ? -target[IX(x,1,y)] : target[IX(x,1,y)]; + target[IX(x,SPARSE_ARRAY_RAW_DIM-1,y)] = b==2 ? -target[IX(x,SPARSE_ARRAY_RAW_DIM-2,y)] : target[IX(x,SPARSE_ARRAY_RAW_DIM-2,y)]; + target[IX(x,y,0)] = b==3 ? -target[IX(x,y,1)] : target[IX(x,y,1)]; + target[IX(x,y,SPARSE_ARRAY_RAW_DIM-1)] = b==3 ? -target[IX(x,y,SPARSE_ARRAY_RAW_DIM-2)] : target[IX(x,y,SPARSE_ARRAY_RAW_DIM-2)]; + } + } + for(int x = 1; x < SPARSE_ARRAY_RAW_DIM-1; x++){ + target[IX(x,0,0)] = (float)(0.5f * (target[IX(x,1,0)] + target[IX(x,0,1)])); + target[IX(x,SPARSE_ARRAY_RAW_DIM-1,0)] = (float)(0.5f * (target[IX(x,SPARSE_ARRAY_RAW_DIM-2,0)] + target[IX(x,SPARSE_ARRAY_RAW_DIM-1,1)])); + target[IX(x,0,SPARSE_ARRAY_RAW_DIM-1)] = (float)(0.5f * (target[IX(x,1,SPARSE_ARRAY_RAW_DIM-1)] + target[IX(x,0,SPARSE_ARRAY_RAW_DIM-2)])); + target[IX(x,SPARSE_ARRAY_RAW_DIM-1,SPARSE_ARRAY_RAW_DIM-1)] = (float)(0.5f * (target[IX(x,SPARSE_ARRAY_RAW_DIM-2,SPARSE_ARRAY_RAW_DIM-1)] + target[IX(x,SPARSE_ARRAY_RAW_DIM-1,SPARSE_ARRAY_RAW_DIM-2)])); + + target[IX(0,x,0)] = (float)(0.5f * (target[IX(1,x,0)] + target[IX(0,x,1)])); + target[IX(SPARSE_ARRAY_RAW_DIM-1,x,0)] = (float)(0.5f * (target[IX(SPARSE_ARRAY_RAW_DIM-2,x,0)] + target[IX(SPARSE_ARRAY_RAW_DIM-1,x,1)])); + target[IX(0,x,SPARSE_ARRAY_RAW_DIM-1)] = (float)(0.5f * (target[IX(1,x,SPARSE_ARRAY_RAW_DIM-1)] + target[IX(0,x,SPARSE_ARRAY_RAW_DIM-2)])); + target[IX(SPARSE_ARRAY_RAW_DIM-1,x,SPARSE_ARRAY_RAW_DIM-1)] = (float)(0.5f * (target[IX(SPARSE_ARRAY_RAW_DIM-2,x,SPARSE_ARRAY_RAW_DIM-1)] + target[IX(SPARSE_ARRAY_RAW_DIM-1,x,SPARSE_ARRAY_RAW_DIM-2)])); + + + target[IX(0,0,x)] = (float)(0.5f * (target[IX(1,0,x)] + target[IX(0,1,x)])); + target[IX(SPARSE_ARRAY_RAW_DIM-1,0,x)] = (float)(0.5f * (target[IX(SPARSE_ARRAY_RAW_DIM-2,0,x)] + target[IX(SPARSE_ARRAY_RAW_DIM-1,1,x)])); + target[IX(0,SPARSE_ARRAY_RAW_DIM-1,x)] = (float)(0.5f * (target[IX(1,SPARSE_ARRAY_RAW_DIM-1,x)] + target[IX(0,SPARSE_ARRAY_RAW_DIM-2,x)])); + target[IX(SPARSE_ARRAY_RAW_DIM-1,SPARSE_ARRAY_RAW_DIM-1,x)] = (float)(0.5f * (target[IX(SPARSE_ARRAY_RAW_DIM-2,SPARSE_ARRAY_RAW_DIM-1,x)] + target[IX(SPARSE_ARRAY_RAW_DIM-1,SPARSE_ARRAY_RAW_DIM-2,x)])); + + } + target[IX(0,0,0)] = (float)((target[IX(1,0,0)]+target[IX(0,1,0)]+target[IX(0,0,1)])/3.0); + target[IX(SPARSE_ARRAY_RAW_DIM-1,0,0)] = (float)((target[IX(SPARSE_ARRAY_RAW_DIM-2,0,0)]+target[IX(SPARSE_ARRAY_RAW_DIM-1,1,0)]+target[IX(SPARSE_ARRAY_RAW_DIM-1,0,1)])/3.0); + target[IX(0,SPARSE_ARRAY_RAW_DIM-1,0)] = (float)((target[IX(1,SPARSE_ARRAY_RAW_DIM-1,0)]+target[IX(0,SPARSE_ARRAY_RAW_DIM-2,0)]+target[IX(0,SPARSE_ARRAY_RAW_DIM-1,1)])/3.0); + target[IX(0,0,SPARSE_ARRAY_RAW_DIM-1)] = (float)((target[IX(0,0,SPARSE_ARRAY_RAW_DIM-2)]+target[IX(1,0,SPARSE_ARRAY_RAW_DIM-1)]+target[IX(0,1,SPARSE_ARRAY_RAW_DIM-1)])/3.0); + target[IX(SPARSE_ARRAY_RAW_DIM-1,SPARSE_ARRAY_RAW_DIM-1,0)] = (float)((target[IX(SPARSE_ARRAY_RAW_DIM-2,SPARSE_ARRAY_RAW_DIM-1,0)]+target[IX(SPARSE_ARRAY_RAW_DIM-1,SPARSE_ARRAY_RAW_DIM-2,0)]+target[IX(SPARSE_ARRAY_RAW_DIM-1,SPARSE_ARRAY_RAW_DIM-1,1)])/3.0); + target[IX(0,SPARSE_ARRAY_RAW_DIM-1,SPARSE_ARRAY_RAW_DIM-1)] = (float)((target[IX(1,SPARSE_ARRAY_RAW_DIM-1,SPARSE_ARRAY_RAW_DIM-1)]+target[IX(0,SPARSE_ARRAY_RAW_DIM-2,SPARSE_ARRAY_RAW_DIM-1)]+target[IX(0,SPARSE_ARRAY_RAW_DIM-1,SPARSE_ARRAY_RAW_DIM-2)])/3.0); + target[IX(SPARSE_ARRAY_RAW_DIM-1,0,SPARSE_ARRAY_RAW_DIM-1)] = (float)((target[IX(SPARSE_ARRAY_RAW_DIM-1,0,SPARSE_ARRAY_RAW_DIM-2)]+target[IX(SPARSE_ARRAY_RAW_DIM-2,0,SPARSE_ARRAY_RAW_DIM-1)]+target[IX(SPARSE_ARRAY_RAW_DIM-1,1,SPARSE_ARRAY_RAW_DIM-1)])/3.0); + target[IX(SPARSE_ARRAY_RAW_DIM-1,SPARSE_ARRAY_RAW_DIM-1,SPARSE_ARRAY_RAW_DIM-1)] = (float)((target[IX(SPARSE_ARRAY_RAW_DIM-1,SPARSE_ARRAY_RAW_DIM-1,SPARSE_ARRAY_RAW_DIM-2)]+target[IX(SPARSE_ARRAY_RAW_DIM-1,SPARSE_ARRAY_RAW_DIM-2,SPARSE_ARRAY_RAW_DIM-1)]+target[IX(SPARSE_ARRAY_RAW_DIM-1,SPARSE_ARRAY_RAW_DIM-1,SPARSE_ARRAY_RAW_DIM-2)])/3.0); +} \ No newline at end of file diff --git a/test/c/CMakeLists.txt b/test/c/CMakeLists.txt index d58bc8ab..dd0855be 100644 --- a/test/c/CMakeLists.txt +++ b/test/c/CMakeLists.txt @@ -9,7 +9,7 @@ else() endif() # Grab test files -file(GLOB_RECURSE TEST_FILES "*.c") +file(GLOB_RECURSE TEST_FILES CONFIGURE_DEPENDS "*.c") set(TEST_DRIVER test_driver.c) # include and enable testing diff --git a/test/c/fluid/chunk_test_utils.h b/test/c/fluid/chunk_test_utils.h new file mode 100644 index 00000000..4ce34877 --- /dev/null +++ b/test/c/fluid/chunk_test_utils.h @@ -0,0 +1,68 @@ + +#ifndef CHUNK_TEST_UTILS_H +#define CHUNK_TEST_UTILS_H + +#include "fluid/chunk.h" + + +/** + * Array id of the d array for chunk_set_val + */ +#define ARR_ID_D 0 + +/** + * Array id of the d0 array for chunk_set_val + */ +#define ARR_ID_D0 1 + +/** + * Array id of the u array for chunk_set_val + */ +#define ARR_ID_U 2 + +/** + * Array id of the v array for chunk_set_val + */ +#define ARR_ID_V 3 + +/** + * Array id of the w array for chunk_set_val + */ +#define ARR_ID_W 4 + +/** + * Array id of the u0 array for chunk_set_val + */ +#define ARR_ID_U0 5 + +/** + * Array id of the v0 array for chunk_set_val + */ +#define ARR_ID_V0 6 + +/** + * Array id of the w0 array for chunk_set_val + */ +#define ARR_ID_W0 7 + + + +/** + * Creates a chunk at a world position + */ +Chunk * chunk_create(int x, int y, int z); + +/** + * Frees a chunk + */ +void chunk_free(Chunk * chunk); + +/** + * Sets a chunk's value + * @param chunk The chunk + * @param i The value to set the array to + * @param arr THe array to set + */ +void chunk_set_val(Chunk * chunk, int i, int arr); + +#endif \ No newline at end of file diff --git a/test/c/fluid/chunk_tests.c b/test/c/fluid/chunk_tests.c index 6ef1f826..669fb0f3 100644 --- a/test/c/fluid/chunk_tests.c +++ b/test/c/fluid/chunk_tests.c @@ -65,6 +65,9 @@ int fluid_chunk_tests(int argc, char **argv){ rVal += assertEquals(sparseArray->d[fluid_sparse_array_get_index(sparseArray,16,16,16)],chunk1->d[CENTER_LOC][IX(15,15,15)],"index 16,16,16 in the sparse array should be 15,15,15 of the chunk stored at 0,0,0 -- %d %d\n"); rVal += assertEquals(sparseArray->d[fluid_sparse_array_get_index(sparseArray,17,1,1)],chunk2->d[CENTER_LOC][IX(1,1,1)],"index 17,1,1 in the sparse array should be 1,1,1 of the chunk stored at 1,0,0 -- %d %d\n"); + //validate fluid_sparse_array_get_chunk_count + rVal += assertEquals(fluid_sparse_array_get_chunk_count(sparseArray),2,"Sparse array not counting chunks correctly -- %d %d \n"); + //set some value in sparse array for future tests sparseArray->d[fluid_sparse_array_get_index(sparseArray,17,1,1)] = 6; @@ -81,6 +84,10 @@ int fluid_chunk_tests(int argc, char **argv){ fluid_sparse_array_remove_chunk(sparseArray,chunk1,0,0,0); rVal += assertNotEquals(chunk1->d[CENTER_LOC][IX(1,1,1)],6,"chunk should have received the value from the sparse array -- %d %d \n"); + //clean the array and make sure it's clean + fluid_sparse_array_clean(sparseArray); + rVal += assertEquals(sparseArray->d[fluid_sparse_array_get_index(sparseArray,1,1,1)],0,"Array should have been cleaned -- %d %d \n"); + //free a sparse array fluid_sparse_array_free(sparseArray); diff --git a/test/c/fluid/islandsolver_tests.c b/test/c/fluid/islandsolver_tests.c new file mode 100644 index 00000000..dae321ae --- /dev/null +++ b/test/c/fluid/islandsolver_tests.c @@ -0,0 +1,142 @@ +#include +#include + +#include "fluid/chunk.h" +#include "fluid/chunkmask.h" +#include "fluid/utilities.h" +#include "fluid/islandsolver.h" +#include "../test.h" +#include "chunk_test_utils.h" + + + +/** + * Creates a chunk at a world position + */ +Chunk * chunk_create(int x, int y, int z){ + Chunk * chunk1 = (Chunk *)malloc(sizeof(Chunk)); + chunk1->d[CENTER_LOC] = (float *)malloc(DIM * DIM * DIM * sizeof(float)); + chunk1->d0[CENTER_LOC] = (float *)malloc(DIM * DIM * DIM * sizeof(float)); + chunk1->u[CENTER_LOC] = (float *)malloc(DIM * DIM * DIM * sizeof(float)); + chunk1->v[CENTER_LOC] = (float *)malloc(DIM * DIM * DIM * sizeof(float)); + chunk1->w[CENTER_LOC] = (float *)malloc(DIM * DIM * DIM * sizeof(float)); + chunk1->u0[CENTER_LOC] = (float *)malloc(DIM * DIM * DIM * sizeof(float)); + chunk1->v0[CENTER_LOC] = (float *)malloc(DIM * DIM * DIM * sizeof(float)); + chunk1->w0[CENTER_LOC] = (float *)malloc(DIM * DIM * DIM * sizeof(float)); + chunk1->x = x; + chunk1->y = y; + chunk1->z = z; + return chunk1; +} + +/** + * Frees a chunk + */ +void chunk_free(Chunk * chunk){ + free(chunk->d[CENTER_LOC]); + free(chunk->d0[CENTER_LOC]); + free(chunk->u[CENTER_LOC]); + free(chunk->v[CENTER_LOC]); + free(chunk->w[CENTER_LOC]); + free(chunk->u0[CENTER_LOC]); + free(chunk->v0[CENTER_LOC]); + free(chunk->w0[CENTER_LOC]); + free(chunk); +} + +/** + * Sets a chunk's value + * @param chunk The chunk + * @param i The value to set the array to + * @param arr THe array to set + */ +void chunk_set_val(Chunk * chunk, int i, int arr){ + for(int x = 0; x < DIM; x++){ + for(int y = 0; y < DIM; y++){ + for(int z = 0; z < DIM; z++){ + switch(arr){ + case ARR_ID_D: { + chunk->d[CENTER_LOC][x * DIM * DIM + y * DIM + z] = i; + } break; + case ARR_ID_D0: { + chunk->d0[CENTER_LOC][x * DIM * DIM + y * DIM + z] = i; + } break; + case ARR_ID_U: { + chunk->u[CENTER_LOC][x * DIM * DIM + y * DIM + z] = i; + } break; + case ARR_ID_V: { + chunk->v[CENTER_LOC][x * DIM * DIM + y * DIM + z] = i; + } break; + case ARR_ID_W: { + chunk->w[CENTER_LOC][x * DIM * DIM + y * DIM + z] = i; + } break; + case ARR_ID_U0: { + chunk->u0[CENTER_LOC][x * DIM * DIM + y * DIM + z] = i; + } break; + case ARR_ID_V0: { + chunk->v0[CENTER_LOC][x * DIM * DIM + y * DIM + z] = i; + } break; + case ARR_ID_W0: { + chunk->w0[CENTER_LOC][x * DIM * DIM + y * DIM + z] = i; + } break; + } + } + } + } +} + + +int fluid_islandsolver_tests(int argc, char **argv){ + int rVal = 0; + //allocate a sparse array + FluidIslandSolver * islandSolver = fluid_island_solver_create(); + if(islandSolver == NULL){ + printf("Failed to allocate islandSolver!\n"); + return 1; + } + + //create chunks to add to the sparse array + Chunk * chunk1 = chunk_create(0,0,0); + Chunk * chunk2 = chunk_create(1,0,0); + Chunk * chunk3 = chunk_create(7,0,0); + + //test adding chunks + fluid_island_solver_add_chunk(islandSolver,chunk1); + fluid_island_solver_add_chunk(islandSolver,chunk2); + rVal += assertEqualsPtr((void *)islandSolver->remaining[0],(void *)chunk1,"Failed to insert chunk1 \n"); + rVal += assertEqualsPtr((void *)islandSolver->remaining[1],(void *)chunk2,"Failed to insert chunk1 \n"); + rVal += assertNotEqualsPtr((void *)islandSolver->remaining[1],(void *)chunk1,"Failed to insert chunk1 \n"); + rVal += assertNotEqualsPtr((void *)islandSolver->remaining[0],(void *)chunk2,"Failed to insert chunk1 \n"); + + //test removing + fluid_island_solver_remove_chunk(islandSolver,chunk1); + rVal += assertEquals(fluid_island_solver_get_remaining(islandSolver),1,"remaining array should NOT be empty -- %d %d \n"); + fluid_island_solver_remove_chunk(islandSolver,chunk2); + rVal += assertEquals(fluid_island_solver_get_remaining(islandSolver),0,"remaining array should be empty -- %d %d \n"); + + //solve an island + fluid_island_solver_add_chunk(islandSolver,chunk1); + fluid_island_solver_add_chunk(islandSolver,chunk2); + fluid_island_solver_add_chunk(islandSolver,chunk3); + //this should solve for the lone chunk 3 island + fluid_island_solver_solve_island(islandSolver); + rVal += assertEquals(fluid_sparse_array_get_chunk_count(islandSolver->sparseArray),1,"sparse array should contain one element %d %d \n"); + //this should solve for the conjoined chunk1-chunk2 island + fluid_island_solver_solve_island(islandSolver); + rVal += assertEquals(fluid_sparse_array_get_chunk_count(islandSolver->sparseArray),2,"sparse array should contain two elements %d %d \n"); + rVal += assertEquals(fluid_island_solver_get_remaining(islandSolver),0,"there should be no remaining chunks %d %d \n"); + + //should be able to grab the sparse array from here still + rVal += assertEqualsPtr(fluid_island_solver_get_sparse_array(islandSolver),islandSolver->sparseArray,"should be able to fetch the sparse array from the solver \n"); + + + + //free the test chunks + chunk_free(chunk1); + chunk_free(chunk2); + chunk_free(chunk3); + //free a sparse array + fluid_island_solver_free(islandSolver); + + return rVal; +} diff --git a/test/c/fluid/sparsesimulator_tests.c b/test/c/fluid/sparsesimulator_tests.c new file mode 100644 index 00000000..0651bf02 --- /dev/null +++ b/test/c/fluid/sparsesimulator_tests.c @@ -0,0 +1,137 @@ +#include +#include + +#include "fluid/chunk.h" +#include "fluid/chunkmask.h" +#include "fluid/utilities.h" +#include "fluid/islandsolver.h" +#include "fluid/sparsesimulator.h" +#include "../test.h" +#include "chunk_test_utils.h" + +#define TEST_DT 0.1 +#define TEST_DIFF_CONST 0.0001 + + + + + + + + + + + +int test_fluid_sparse_array_add_source(){ + int rVal = 0; + //allocate a sparse array + FluidIslandSolver * islandSolver = fluid_island_solver_create(); + if(islandSolver == NULL){ + printf("Failed to allocate islandSolver!\n"); + return 1; + } + + SparseChunkArray * sparseArray = islandSolver->sparseArray; + + //create chunks to add to the sparse array + Chunk * chunk1 = chunk_create(0,0,0); + + int testVal = 1; + + //add to island solver + fluid_island_solver_add_chunk(islandSolver,chunk1); + chunk_set_val(chunk1,testVal,ARR_ID_D0); + + //solve and simulate + fluid_island_solver_solve_island(islandSolver); + + //add source test + fluid_sparse_array_add_source(sparseArray->d,sparseArray->d0, TEST_DT); + //indices are weird because this chunk will be at the center of the sparse array + int voxelIndex = MAIN_ARRAY_DIM + MAIN_ARRAY_DIM + MAIN_ARRAY_DIM + (SPARSE_ARRAY_BORDER_SIZE / 2); + int index = fluid_sparse_array_get_index(sparseArray,voxelIndex,voxelIndex,voxelIndex); + printf("voxelIndex: %d \n",voxelIndex); + rVal += assertEqualsFloat(sparseArray->d[index],testVal * TEST_DT,"add source did not properly add the source to the array! %f %f \n"); + + + + //free the test chunks + chunk_free(chunk1); + //free a sparse array + fluid_island_solver_free(islandSolver); + + return rVal; +} + + + + + + + + + + + + + +int test_fluid_sparse_array_dens_step(){ + int rVal = 0; + //allocate a sparse array + FluidIslandSolver * islandSolver = fluid_island_solver_create(); + if(islandSolver == NULL){ + printf("Failed to allocate islandSolver!\n"); + return 1; + } + + SparseChunkArray * sparseArray = islandSolver->sparseArray; + + //create chunks to add to the sparse array + Chunk * chunk1 = chunk_create(0,0,0); + + int testVal = 1; + + //add to island solver + fluid_island_solver_add_chunk(islandSolver,chunk1); + chunk_set_val(chunk1,testVal,ARR_ID_D0); + + //solve and simulate + fluid_island_solver_solve_island(islandSolver); + + //add source test + fluid_sparse_array_dens_step(sparseArray->d, sparseArray->d0, sparseArray->u, sparseArray->v, sparseArray->w, TEST_DIFF_CONST, TEST_DT); + + + + //free the test chunks + chunk_free(chunk1); + //free a sparse array + fluid_island_solver_free(islandSolver); + + return rVal; +} + + + + + + + + + + + + + + + + + +int fluid_sparsesimulator_tests(int argc, char **argv){ + int rVal = 0; + + rVal += test_fluid_sparse_array_add_source(); + rVal += test_fluid_sparse_array_dens_step(); + + return rVal; +} diff --git a/test/c/test.c b/test/c/test.c index 56d6bbb4..1b9667d3 100644 --- a/test/c/test.c +++ b/test/c/test.c @@ -7,6 +7,25 @@ int assertEquals(int a, int b, char * msg){ int rVal = (a != b); if(rVal){ printf(msg, a, b); + fflush(stdout); + } + return rVal; +} + +int assertEqualsPtr(void * a, void * b, char * msg){ + int rVal = (a != b); + if(rVal){ + printf(msg, a, b); + fflush(stdout); + } + return rVal; +} + +int assertEqualsFloat(float a, float b, char * msg){ + int rVal = (a != b); + if(rVal){ + printf(msg, a, b); + fflush(stdout); } return rVal; } @@ -15,6 +34,25 @@ int assertNotEquals(int a, int b, char * msg){ int rVal = (a == b); if(rVal){ printf(msg, a, b); + fflush(stdout); + } + return rVal; +} + +int assertNotEqualsPtr(void * a, void * b, char * msg){ + int rVal = (a == b); + if(rVal){ + printf(msg, a, b); + fflush(stdout); + } + return rVal; +} + +int assertNotEqualsFloat(float a, float b, char * msg){ + int rVal = (a == b); + if(rVal){ + printf(msg, a, b); + fflush(stdout); } return rVal; } diff --git a/test/c/test.h b/test/c/test.h index 4714b815..c2f47541 100644 --- a/test/c/test.h +++ b/test/c/test.h @@ -5,4 +5,10 @@ int assertEquals(int a, int b, char * msg); int assertNotEquals(int a, int b, char * msg); +int assertEqualsPtr(void * a, void * b, char * msg); +int assertNotEqualsPtr(void * a, void * b, char * msg); + +int assertEqualsFloat(float a, float b, char * msg); +int assertNotEqualsFloat(float a, float b, char * msg); + #endif \ No newline at end of file