fluid work
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2024-12-05 16:22:32 -05:00
parent da4e46daaf
commit e6e469bec1
15 changed files with 988 additions and 11 deletions

View File

@ -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"
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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
*/

View File

@ -0,0 +1,141 @@
#include <stdio.h>
#include <stdlib.h>
#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);
}

View File

@ -0,0 +1,192 @@
#include <stdio.h>
#include <stdlib.h>
#include <immintrin.h>
#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<size; i++){
x[i] += dt*s[i];
}
}
/**
* Diffuses a given array by a diffusion constant
*/
LIBRARY_API void fluid_sparse_array_diffuse(int b, float * x, float * x0, float diff, float dt){
float a=dt*diff*SPARSE_ARRAY_SPATIAL_SIZE*SPARSE_ARRAY_SPATIAL_SIZE*SPARSE_ARRAY_SPATIAL_SIZE;
fluid_sparse_array_lin_solve(b, x, x0);
}
/**
* Advects a given array based on the force vectors in the simulation
*/
LIBRARY_API void fluid_sparse_array_advect(int N, int b, float * d, float * d0, float * u, float * v, float * w, float dt){
}
/**
* 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){
fluid_sparse_array_add_source(x, x0, dt);
SWAP(x0, x);
fluid_sparse_array_diffuse(0, x, x0, diff, dt);
// SWAP(x0, x);
// fluid_sparse_array_advect(N, 0, x, x0, u, v, w, dt);
}
/**
* The main velocity step function
*/
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){
}
/**
* Projects a given array based on force vectors
*/
LIBRARY_API void fluid_sparse_array_project(int N, float * u, float * v, float * w, float * p, float * div){
}
/**
* 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
* @param a
*/
LIBRARY_API void fluid_sparse_array_lin_solve(int b, float * x, float * x0){
int i, j, k, l, m;
int a = 0;
int c = 0;
__m256 aScalar = _mm256_set1_ps(0);
__m256 cScalar = _mm256_set1_ps(0);
int vectorSize = 8;
// iterate the solver
for(l = 0; l < LINEARSOLVERTIMES; l++){
// update for each cell
for(k = (SPARSE_ARRAY_BORDER_SIZE / 2); k < SPARSE_ARRAY_RAW_DIM - (SPARSE_ARRAY_BORDER_SIZE / 2); k++){
for(j = (SPARSE_ARRAY_BORDER_SIZE / 2); j < SPARSE_ARRAY_RAW_DIM - (SPARSE_ARRAY_BORDER_SIZE / 2); j++){
int n = 0;
//solve as much as possible vectorized
for(i = (SPARSE_ARRAY_BORDER_SIZE / 2); i < SPARSE_ARRAY_RAW_DIM - (SPARSE_ARRAY_BORDER_SIZE / 2); i = i + vectorSize){
__m256 vector = _mm256_loadu_ps(&x[GVI(i-1,j,k)]);
vector = _mm256_add_ps(vector,_mm256_loadu_ps(&x[GVI(i+1,j,k)]));
vector = _mm256_add_ps(vector,_mm256_loadu_ps(&x[GVI(i,j-1,k)]));
vector = _mm256_add_ps(vector,_mm256_loadu_ps(&x[GVI(i,j+1,k)]));
vector = _mm256_add_ps(vector,_mm256_loadu_ps(&x[GVI(i,j,k-1)]));
vector = _mm256_add_ps(vector,_mm256_loadu_ps(&x[GVI(i,j,k+1)]));
vector = _mm256_mul_ps(vector,aScalar);
vector = _mm256_add_ps(vector,_mm256_loadu_ps(&x0[GVI(i,j,k)]));
vector = _mm256_div_ps(vector,cScalar);
_mm256_storeu_ps(&x[GVI(i,j,k)],vector);
}
//If there is any leftover, perform manual solving
if(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);
}

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -0,0 +1,142 @@
#include <stdio.h>
#include <stdlib.h>
#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;
}

View File

@ -0,0 +1,137 @@
#include <stdio.h>
#include <stdlib.h>
#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;
}

View File

@ -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;
}

View File

@ -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