/*! Returns maximum norm if p == 0 */ template<class Grid_T> double get_diff_lp_norm( const std::vector<uint64_t>& cells, const Grid_T& grid, const double p, const double cell_volume, const size_t dimension ) { double local_norm = 0, global_norm = 0; for (const auto& cell: cells) { const auto* const cell_data = grid[cell]; if (cell_data == NULL) { std::cerr << __FILE__ << ":" << __LINE__ << ": No data for cell " << cell << std::endl; abort(); } const auto center = grid.geometry.get_center(cell); if (p == 0) { local_norm = std::max( local_norm, std::fabs((*cell_data)[Divergence()] - div_of_function(center[dimension])) ); } else { local_norm += std::pow( std::fabs((*cell_data)[Divergence()] - div_of_function(center[dimension])), p ); } } local_norm *= cell_volume; if (p == 0) { MPI_Comm comm = grid.get_communicator(); MPI_Allreduce(&local_norm, &global_norm, 1, MPI_DOUBLE, MPI_MAX, comm); MPI_Comm_free(&comm); return global_norm; } else { MPI_Comm comm = grid.get_communicator(); MPI_Allreduce(&local_norm, &global_norm, 1, MPI_DOUBLE, MPI_SUM, comm); MPI_Comm_free(&comm); return std::pow(global_norm, 1.0 / p); } }
void Fluid::Project( int maxIterations, const View2f& velocities, View2f* velocitiesProjected) const { // Part1: Compute divergence of velocity field. auto divergence = Image<float, 1>::Create(_velocities->Rect(), _velocities->Width(), 1, 1); auto pressure = Image<float, 1>::Create(divergence->View(), kLeaveUninitialized); Divergence(_velocities->View(), &divergence->View()); ComputePressureField(maxIterations, divergence->View(), &pressure->View()); divergence.reset(); // Part2: Make the velocity field divergence-free by substracting pressure gradients. SubstractGradient(_velocities->View(), pressure->View(), velocitiesProjected); }
/** Gradient Domain HDR tone mapping operator @param Y Image luminance values @param alpha Parameter alpha of the paper (suggested value is 0.1) @param beta Parameter beta of the paper (suggested value is between 0.8 and 0.9) @return returns the tone mapped luminance */ static FIBITMAP* tmoFattal02(FIBITMAP *Y, float alpha, float beta) { const unsigned MIN_PYRAMID_SIZE = 32; // minimun size (width or height) of the coarsest level of the pyramid FIBITMAP *H = NULL; FIBITMAP **pyramid = NULL; FIBITMAP **gradients = NULL; FIBITMAP *phy = NULL; FIBITMAP *divG = NULL; FIBITMAP *U = NULL; float *avgGrad = NULL; int k; int nlevels = 0; try { // get the normalized luminance FIBITMAP *H = LogLuminance(Y); if(!H) throw(1); // get the number of levels for the pyramid const unsigned width = FreeImage_GetWidth(H); const unsigned height = FreeImage_GetHeight(H); unsigned minsize = MIN(width, height); while(minsize >= MIN_PYRAMID_SIZE) { nlevels++; minsize /= 2; } // create the Gaussian pyramid pyramid = (FIBITMAP**)malloc(nlevels * sizeof(FIBITMAP*)); if(!pyramid) throw(1); memset(pyramid, 0, nlevels * sizeof(FIBITMAP*)); if(!GaussianPyramid(H, pyramid, nlevels)) throw(1); // calculate gradient magnitude and its average value on each pyramid level gradients = (FIBITMAP**)malloc(nlevels * sizeof(FIBITMAP*)); if(!gradients) throw(1); memset(gradients, 0, nlevels * sizeof(FIBITMAP*)); avgGrad = (float*)malloc(nlevels * sizeof(float)); if(!avgGrad) throw(1); if(!GradientPyramid(pyramid, nlevels, gradients, avgGrad)) throw(1); // free the Gaussian pyramid for(k = 0; k < nlevels; k++) { if(pyramid[k]) FreeImage_Unload(pyramid[k]); } free(pyramid); pyramid = NULL; // compute the gradient attenuation function PHI(x, y) phy = PhiMatrix(gradients, avgGrad, nlevels, alpha, beta); if(!phy) throw(1); // free the gradient pyramid for(k = 0; k < nlevels; k++) { if(gradients[k]) FreeImage_Unload(gradients[k]); } free(gradients); gradients = NULL; free(avgGrad); avgGrad = NULL; // compute gradients in x and y directions, attenuate them with the attenuation matrix, // then compute the divergence div G from the attenuated gradient. divG = Divergence(H, phy); if(!divG) throw(1); // H & phy no longer needed FreeImage_Unload(H); H = NULL; FreeImage_Unload(phy); phy = NULL; // solve the PDE (Poisson equation) using a multigrid solver and 3 cycles FIBITMAP *U = FreeImage_MultigridPoissonSolver(divG, 3); if(!U) throw(1); FreeImage_Unload(divG); // perform exponentiation and recover the log compressed image ExpLuminance(U); return U; } catch(int) { if(H) FreeImage_Unload(H); if(pyramid) { for(int i = 0; i < nlevels; i++) { if(pyramid[i]) FreeImage_Unload(pyramid[i]); } free(pyramid); } if(gradients) { for(int i = 0; i < nlevels; i++) { if(gradients[i]) FreeImage_Unload(gradients[i]); } free(gradients); } if(avgGrad) free(avgGrad); if(phy) FreeImage_Unload(phy); if(divG) FreeImage_Unload(divG); if(U) FreeImage_Unload(U); return NULL; } }
float divDGradU(intVectorType point ,densityDataType *densityData, int scanningRange) { momentOfInertiaType Inertia; floatMatrixType BT, B, Diag, Help, Diffusion; float a, structure; //evaluateDirectionAndStructure(&a, &structure ,&Inertia, *densityData, point, scanningRange); /* (Inertia).v1.x=0.0; (Inertia).v1.y=1.0; (Inertia).v2.x=1.0; (Inertia).v2.y=0.0; */ //BTransposed float magV1=FLOATVECNORM((Inertia).v1)+EPS; float magV2=FLOATVECNORM((Inertia).v2)+EPS; /* printf("magV1=%f\n",magV1); printf("magV2=%f\n",magV2); */ BT.a11=(Inertia).v1.x/magV1; BT.a12=(Inertia).v1.y/magV1; BT.a21=(Inertia).v2.x/magV2; BT.a22=(Inertia).v2.y/magV2; //Diagonal Diag.a11=1.0; Diag.a12=0.0; Diag.a21=0.0; Diag.a22=1.0; //B B.a11=(Inertia).v1.x/magV1; B.a12=(Inertia).v2.x/magV2; B.a21=(Inertia).v1.y/magV1; B.a22=(Inertia).v2.y/magV2; /* printf("BT:\n"); SHOWMATRIX(BT); printf("Diag:\n"); SHOWMATRIX(Diag); */ //Create Diffusion Matrix MultiplyMatrix(&Help, &Diag, &BT); /* printf("DiagBT:\n"); SHOWMATRIX(Help); */ /* printf("B:\n"); SHOWMATRIX(B); */ MultiplyMatrix(&Diffusion, &B, &Help); //printf("Diffusion\n"); //SHOWMATRIX(Diffusion); return Divergence(point.x , point.y, &Diag , densityData); //return Divergence(point.x , point.y, &Diffusion , densityData); };
int main(int argc, char* argv[]) { if (MPI_Init(&argc, &argv) != MPI_SUCCESS) { std::cerr << "Couldn't initialize MPI." << std::endl; abort(); } MPI_Comm comm = MPI_COMM_WORLD; int rank = 0, comm_size = 0; if (MPI_Comm_rank(comm, &rank) != MPI_SUCCESS) { std::cerr << "Couldn't obtain MPI rank." << std::endl; abort(); } if (MPI_Comm_size(comm, &comm_size) != MPI_SUCCESS) { std::cerr << "Couldn't obtain size of MPI communicator." << std::endl; abort(); } // intialize Zoltan float zoltan_version; if (Zoltan_Initialize(argc, argv, &zoltan_version) != ZOLTAN_OK) { std::cerr << "Zoltan_Initialize failed." << std::endl; abort(); } double old_norm_x = std::numeric_limits<double>::max(), old_norm_y = std::numeric_limits<double>::max(), old_norm_z = std::numeric_limits<double>::max(); size_t old_nr_of_cells = 0; for (size_t nr_of_cells = 8; nr_of_cells <= 2048; nr_of_cells *= 2) { dccrg::Dccrg<Cell, dccrg::Cartesian_Geometry> grid_x, grid_y, grid_z; const std::array<uint64_t, 3> grid_size_x{{nr_of_cells + 2, 1, 1}}, grid_size_y{{1, nr_of_cells + 2, 1}}, grid_size_z{{1, 1, nr_of_cells + 2}}; if (not grid_x.initialize(grid_size_x,comm,"RANDOM",0,0,false,false,false)) { std::cerr << __FILE__ << ":" << __LINE__ << std::endl; abort(); } if (not grid_y.initialize(grid_size_y,comm,"RANDOM",0,0,false,false,false)) { std::cerr << __FILE__ << ":" << __LINE__ << std::endl; abort(); } if (not grid_z.initialize(grid_size_z,comm,"RANDOM",0,0,false,false,false)) { std::cerr << __FILE__ << ":" << __LINE__ << std::endl; abort(); } const std::array<double, 3> cell_length_x{{2 * M_PI / (grid_size_x[0] - 2), 1, 1}}, cell_length_y{{1, 2 * M_PI / (grid_size_y[0] - 2), 1}}, cell_length_z{{1, 1, 2 * M_PI / (grid_size_z[0] - 2)}}, grid_start_x{{-cell_length_x[0], 0, 0}}, grid_start_y{{0, -cell_length_y[1], 0}}, grid_start_z{{0, 0, -cell_length_z[2]}}; const double cell_volume = cell_length_x[0] * cell_length_x[1] * cell_length_x[2]; dccrg::Cartesian_Geometry::Parameters geom_params_x,geom_params_y,geom_params_z; geom_params_x.start = grid_start_x; geom_params_x.level_0_cell_length = cell_length_x; geom_params_y.start = grid_start_y; geom_params_y.level_0_cell_length = cell_length_y; geom_params_z.start = grid_start_z; geom_params_z.level_0_cell_length = cell_length_z; if (not grid_x.set_geometry(geom_params_x)) { std::cerr << __FILE__ << ":" << __LINE__ << std::endl; abort(); } if (not grid_y.set_geometry(geom_params_y)) { std::cerr << __FILE__ << ":" << __LINE__ << std::endl; abort(); } if (not grid_z.set_geometry(geom_params_z)) { std::cerr << __FILE__ << ":" << __LINE__ << std::endl; abort(); } const auto all_cells = grid_x.get_cells(); std::vector<uint64_t> solve_cells, boundary_cells; for (const auto& cell: all_cells) { auto *const cell_data_x = grid_x[cell], *const cell_data_y = grid_y[cell], *const cell_data_z = grid_z[cell]; if (cell_data_x == NULL or cell_data_y == NULL or cell_data_z == NULL) { std::cerr << __FILE__ << ":" << __LINE__ << std::endl; abort(); } const auto index = grid_x.mapping.get_indices(cell); if (index[0] > 0 and index[0] < grid_size_x[0] - 1) { solve_cells.push_back(cell); } else { boundary_cells.push_back(cell); } const auto x = grid_x.geometry.get_center(cell)[0]; auto &vec_x = (*cell_data_x)[Vector_Field()], &vec_y = (*cell_data_y)[Vector_Field()], &vec_z = (*cell_data_z)[Vector_Field()]; vec_x[0] = vec_y[1] = vec_z[2] = function(x); vec_x[1] = vec_x[2] = vec_y[0] = vec_y[2] = vec_z[0] = vec_z[1] = 0; } grid_x.update_copies_of_remote_neighbors(); grid_y.update_copies_of_remote_neighbors(); grid_z.update_copies_of_remote_neighbors(); // use copy boundaries const uint64_t neg_bdy_cell = 1, pos_bdy_cell = nr_of_cells + 2; if (grid_x.is_local(neg_bdy_cell)) { const auto *const neighbor_data_x = grid_x[neg_bdy_cell + 1], *const neighbor_data_y = grid_y[neg_bdy_cell + 1], *const neighbor_data_z = grid_z[neg_bdy_cell + 1]; auto *const cell_data_x = grid_x[neg_bdy_cell], *const cell_data_y = grid_y[neg_bdy_cell], *const cell_data_z = grid_z[neg_bdy_cell]; if ( cell_data_x == NULL or neighbor_data_x == NULL or cell_data_y == NULL or neighbor_data_y == NULL or cell_data_z == NULL or neighbor_data_z == NULL ) { std::cerr << __FILE__ << ":" << __LINE__ << std::endl; abort(); } (*cell_data_x)[Vector_Field()] = (*neighbor_data_x)[Vector_Field()]; (*cell_data_y)[Vector_Field()] = (*neighbor_data_y)[Vector_Field()]; (*cell_data_z)[Vector_Field()] = (*neighbor_data_z)[Vector_Field()]; } if (grid_x.is_local(pos_bdy_cell)) { const auto *const neighbor_data_x = grid_x[pos_bdy_cell - 1], *const neighbor_data_y = grid_y[pos_bdy_cell - 1], *const neighbor_data_z = grid_z[pos_bdy_cell - 1]; auto *const cell_data_x = grid_x[pos_bdy_cell], *const cell_data_y = grid_y[pos_bdy_cell], *const cell_data_z = grid_z[pos_bdy_cell]; if ( cell_data_x == NULL or neighbor_data_x == NULL or cell_data_y == NULL or neighbor_data_y == NULL or cell_data_z == NULL or neighbor_data_z == NULL ) { std::cerr << __FILE__ << ":" << __LINE__ << std::endl; abort(); } (*cell_data_x)[Vector_Field()] = (*neighbor_data_x)[Vector_Field()]; (*cell_data_y)[Vector_Field()] = (*neighbor_data_y)[Vector_Field()]; (*cell_data_z)[Vector_Field()] = (*neighbor_data_z)[Vector_Field()]; } auto Vector_Getter = [](Cell& cell_data) -> Vector_Field::data_type& { return cell_data[Vector_Field()]; }; auto Divergence_Getter = [](Cell& cell_data) -> Divergence::data_type& { return cell_data[Divergence()]; }; auto Gradient_Getter = [](Cell& cell_data) -> Gradient::data_type& { return cell_data[Gradient()]; }; pamhd::divergence::remove( solve_cells, boundary_cells, {}, grid_x, Vector_Getter, Divergence_Getter, Gradient_Getter, 2000, 0, 1e-15, 2, 100, false ); pamhd::divergence::remove( solve_cells, boundary_cells, {}, grid_y, Vector_Getter, Divergence_Getter, Gradient_Getter, 2000, 0, 1e-15, 2, 100, false ); pamhd::divergence::remove( solve_cells, boundary_cells, {}, grid_z, Vector_Getter, Divergence_Getter, Gradient_Getter, 2000, 0, 1e-15, 2, 100, false ); const double p_of_norm = 2, norm_x = get_diff_lp_norm(solve_cells, grid_x, p_of_norm, cell_volume, 0), norm_y = get_diff_lp_norm(solve_cells, grid_y, p_of_norm, cell_volume, 1), norm_z = get_diff_lp_norm(solve_cells, grid_z, p_of_norm, cell_volume, 2); if (norm_x > old_norm_x) { if (grid_x.get_rank() == 0) { std::cerr << __FILE__ << ":" << __LINE__ << ": X norm with " << nr_of_cells << " cells " << norm_x << " is larger than with " << nr_of_cells / 2 << " cells " << old_norm_x << std::endl; } abort(); } if (norm_y > old_norm_y) { if (grid_y.get_rank() == 0) { std::cerr << __FILE__ << ":" << __LINE__ << ": Y norm with " << nr_of_cells << " cells " << norm_y << " is larger than with " << nr_of_cells / 2 << " cells " << old_norm_y << std::endl; } abort(); } if (norm_y > old_norm_z) { if (grid_z.get_rank() == 0) { std::cerr << __FILE__ << ":" << __LINE__ << ": Z norm with " << nr_of_cells << " cells " << norm_z << " is larger than with " << nr_of_cells / 2 << " cells " << old_norm_z << std::endl; } abort(); } if (old_nr_of_cells > 0) { const double order_of_accuracy_x = -log(norm_x / old_norm_x) / log(double(nr_of_cells) / old_nr_of_cells), order_of_accuracy_y = -log(norm_y / old_norm_y) / log(double(nr_of_cells) / old_nr_of_cells), order_of_accuracy_z = -log(norm_z / old_norm_z) / log(double(nr_of_cells) / old_nr_of_cells); if (order_of_accuracy_x < 1.5) { if (grid_x.get_rank() == 0) { std::cerr << __FILE__ << ":" << __LINE__ << ": X order of accuracy from " << old_nr_of_cells << " to " << nr_of_cells << " is too low: " << order_of_accuracy_x << std::endl; } abort(); } if (order_of_accuracy_y < 1.5) { if (grid_y.get_rank() == 0) { std::cerr << __FILE__ << ":" << __LINE__ << ": Y order of accuracy from " << old_nr_of_cells << " to " << nr_of_cells << " is too low: " << order_of_accuracy_y << std::endl; } abort(); } if (order_of_accuracy_z < 1.5) { if (grid_z.get_rank() == 0) { std::cerr << __FILE__ << ":" << __LINE__ << ": Z order of accuracy from " << old_nr_of_cells << " to " << nr_of_cells << " is too low: " << order_of_accuracy_z << std::endl; } abort(); } } old_nr_of_cells = nr_of_cells; old_norm_x = norm_x; old_norm_y = norm_y; old_norm_z = norm_z; } MPI_Finalize(); return EXIT_SUCCESS; }