ExecStatus IntBase<VY>::prune_lower(Space& home, int* dis, int n_dis) { assert(n_dis > 0); // At least one more value will be needed GECODE_ME_CHECK(y.gq(home,vs.size() + 1)); Region r(home); // Only one additional value is allowed if (y.max() == vs.size() + 1) { // Compute possible values ViewRanges<IntView>* r_dis = r.alloc<ViewRanges<IntView> >(n_dis); for (int i=n_dis; i--; ) r_dis[i] = ViewRanges<IntView>(x[dis[i]]); Iter::Ranges::NaryInter iv(r, r_dis, n_dis); // Is there a common value at all? if (!iv()) return ES_FAILED; ValSet::Ranges vsr(vs); Iter::Ranges::NaryUnion pv(r,iv,vsr); // Enforce common values for (int i=x.size(); i--; ) { pv.reset(); GECODE_ME_CHECK(x[i].inter_r(home, pv, false)); } return ES_OK; } // Compute independent set for lower bound // ovl is a bit-matrix defining whether two views overlap SymBitMatrix ovl(r,x.size()); // deg[i] is the degree of x[i] int* deg = r.alloc<int>(x.size()); // ovl_i[i] is an array of indices j such that x[j] overlaps with x[i] int** ovl_i = r.alloc<int*>(x.size()); // n_ovl_i[i] defines how many integers are stored for ovl_i[i] int* n_ovl_i = r.alloc<int>(x.size()); { #ifndef NDEBUG // Initialize all to null pointers so that things crash ;-) for (int i=x.size(); i--; ) ovl_i[i] = NULL; #endif // For each i there can be at most n_dis-1 entries in ovl_i[i] int* m = r.alloc<int>(n_dis*(n_dis-1)); for (int i=n_dis; i--; ) { deg[dis[i]] = 0; ovl_i[dis[i]] = m; m += n_dis-1; } } // Initialize overlap matrix by analyzing the view ranges { // Compute how many events are needed // One event for the end marker int n_re = 1; // Two events for each range for (int i=n_dis; i--; ) for (ViewRanges<IntView> rx(x[dis[i]]); rx(); ++rx) n_re += 2; // Allocate and initialize events RangeEvent* re = r.alloc<RangeEvent>(n_re); int j=0; for (int i=n_dis; i--; ) for (ViewRanges<IntView> rx(x[dis[i]]); rx(); ++rx) { // Event when a range starts re[j].ret=RET_FST; re[j].val=rx.min(); re[j].view=dis[i]; j++; // Event when a range ends re[j].ret=RET_LST; re[j].val=rx.max(); re[j].view=dis[i]; j++; } // Make this the last event re[j].ret=RET_END; re[j].val=Int::Limits::infinity; assert(j+1 == n_re); // Sort and process events Support::quicksort(re,n_re); // Current views with a range being active Support::BitSet<Region> cur(r,static_cast<unsigned int>(x.size())); // Process all events for (int i=0; true; i++) switch (re[i].ret) { case RET_FST: // Process all overlapping views for (Iter::Values::BitSet<Support::BitSet<Region> > j(cur); j(); ++j) { int di = re[i].view, dj = j.val(); if (!ovl.get(di,dj)) { ovl.set(di,dj); ovl_i[di][deg[di]++] = dj; ovl_i[dj][deg[dj]++] = di; } } cur.set(static_cast<unsigned int>(re[i].view)); break; case RET_LST: cur.clear(static_cast<unsigned int>(re[i].view)); break; case RET_END: goto done; default: GECODE_NEVER; } done: r.free<RangeEvent>(re,n_re); } // While deg changes, n_ovl_i remains unchanged and is needed, so copy it for (int i=n_dis; i--; ) { assert(deg[dis[i]] < n_dis); n_ovl_i[dis[i]] = deg[dis[i]]; } // Views in the independent set int* ind = r.alloc<int>(n_dis); int n_ind = 0; while (n_dis > 0) { int i_min = n_dis-1; int d_min = deg[dis[i_min]]; unsigned int s_min = x[dis[i_min]].size(); // Find view with smallest (degree,size) for (int i=n_dis-1; i--; ) if ((d_min > deg[dis[i]]) || ((d_min == deg[dis[i]]) && (s_min > x[dis[i]].size()))) { i_min = i; d_min = deg[dis[i]]; s_min = x[dis[i]].size(); } // i_min refers to view with smallest (degree,size) ind[n_ind++] = dis[i_min]; dis[i_min] = dis[--n_dis]; // Filter out non disjoint views for (int i=n_dis; i--; ) if (ovl.get(dis[i],ind[n_ind-1])) { // Update degree information for (int j=n_ovl_i[dis[i]]; j--; ) deg[ovl_i[dis[i]][j]]--; // Eliminate view dis[i] = dis[--n_dis]; } } // Enforce lower bound GECODE_ME_CHECK(y.gq(home,vs.size() + n_ind)); // Prune, if possible if (vs.size() + n_ind == y.max()) { // Only values from the indepent set a can be taken ViewRanges<IntView>* r_ind = r.alloc<ViewRanges<IntView> >(n_ind); for (int i=n_ind; i--; ) r_ind[i] = ViewRanges<IntView>(x[ind[i]]); Iter::Ranges::NaryUnion v_ind(r, r_ind, n_ind); ValSet::Ranges vsr(vs); v_ind |= vsr; for (int i=x.size(); i--; ) { v_ind.reset(); GECODE_ME_CHECK(x[i].inter_r(home,v_ind,false)); } } return ES_OK; }
void FluidSim::solve_viscosity(float dt) { int ni = liquid_phi.ni; int nj = liquid_phi.nj; //static obstacles for simplicity - for moving objects, //use a spatially varying 2d array, and modify the linear system appropriately float u_obj = 0; float v_obj = 0; Array2c u_state(ni+1,nj,(const char&)0); Array2c v_state(ni,nj+1,(const char&)0); const int SOLID = 1; const int FLUID = 0; printf("Determining states\n"); //just determine if the face position is inside the wall! That's it. for(int j = 0; j < nj; ++j) { for(int i = 0; i < ni+1; ++i) { if(i - 1 < 0 || i >= ni || (nodal_solid_phi(i,j+1) + nodal_solid_phi(i,j))/2 <= 0) u_state(i,j) = SOLID; else u_state(i,j) = FLUID; } } for(int j = 0; j < nj+1; ++j) { for(int i = 0; i < ni; ++i) { if(j - 1 < 0 || j >= nj || (nodal_solid_phi(i+1,j) + nodal_solid_phi(i,j))/2 <= 0) v_state(i,j) = SOLID; else v_state(i,j) = FLUID; } } printf("Building matrix\n"); int elts = (ni+1)*nj + ni*(nj+1); if(vrhs.size() != elts) { vrhs.resize(elts); velocities.resize(elts); vmatrix.resize(elts); } vmatrix.zero(); float factor = dt/sqr(dx); for(int j = 1; j < nj-1; ++j) for(int i = 1; i < ni-1; ++i) { if(u_state(i,j) == FLUID ) { int index = u_ind(i,j); vrhs[index] = u_vol(i,j) * u(i,j); vmatrix.set_element(index,index,u_vol(i,j)); //uxx terms float visc_right = viscosity(i,j); float visc_left = viscosity(i-1,j); float vol_right = c_vol(i,j); float vol_left = c_vol(i-1,j); //u_x_right vmatrix.add_to_element(index,index, 2*factor*visc_right*vol_right); if(u_state(i+1,j) == FLUID) vmatrix.add_to_element(index,u_ind(i+1,j), -2*factor*visc_right*vol_right); else if(u_state(i+1,j) == SOLID) vrhs[index] -= -2*factor*visc_right*vol_right*u_obj; //u_x_left vmatrix.add_to_element(index,index, 2*factor*visc_left*vol_left); if(u_state(i-1,j) == FLUID) vmatrix.add_to_element(index,u_ind(i-1,j), -2*factor*visc_left*vol_left); else if(u_state(i-1,j) == SOLID) vrhs[index] -= -2*factor*visc_left*vol_left*u_obj; //uyy terms float visc_top = 0.25f*(viscosity(i-1,j+1) + viscosity(i-1,j) + viscosity(i,j+1) + viscosity(i,j)); float visc_bottom = 0.25f*(viscosity(i-1,j) + viscosity(i-1,j-1) + viscosity(i,j) + viscosity(i,j-1)); float vol_top = n_vol(i,j+1); float vol_bottom = n_vol(i,j); //u_y_top vmatrix.add_to_element(index,index, +factor*visc_top*vol_top); if(u_state(i,j+1) == FLUID) vmatrix.add_to_element(index,u_ind(i,j+1), -factor*visc_top*vol_top); else if(u_state(i,j+1) == SOLID) vrhs[index] -= -u_obj*factor*visc_top*vol_top; //u_y_bottom vmatrix.add_to_element(index,index, +factor*visc_bottom*vol_bottom); if(u_state(i,j-1) == FLUID) vmatrix.add_to_element(index,u_ind(i,j-1), -factor*visc_bottom*vol_bottom); else if(u_state(i,j-1) == SOLID) vrhs[index] -= -u_obj*factor*visc_bottom*vol_bottom; //vxy terms //v_x_top if(v_state(i,j+1) == FLUID) vmatrix.add_to_element(index,v_ind(i,j+1), -factor*visc_top*vol_top); else if(v_state(i,j+1) == SOLID) vrhs[index] -= -v_obj*factor*visc_top*vol_top; if(v_state(i-1,j+1) == FLUID) vmatrix.add_to_element(index,v_ind(i-1,j+1), factor*visc_top*vol_top); else if(v_state(i-1,j+1) == SOLID) vrhs[index] -= v_obj*factor*visc_top*vol_top; //v_x_bottom if(v_state(i,j) == FLUID) vmatrix.add_to_element(index,v_ind(i,j), +factor*visc_bottom*vol_bottom); else if(v_state(i,j) == SOLID) vrhs[index] -= v_obj*factor*visc_bottom*vol_bottom; if(v_state(i-1,j) == FLUID) vmatrix.add_to_element(index,v_ind(i-1,j), -factor*visc_bottom*vol_bottom); else if(v_state(i-1,j) == SOLID) vrhs[index] -= -v_obj*factor*visc_bottom*vol_bottom; } } for(int j = 1; j < nj; ++j) for(int i = 1; i < ni-1; ++i) { if(v_state(i,j) == FLUID) { int index = v_ind(i,j); vrhs[index] = v_vol(i,j)*v(i,j); vmatrix.set_element(index, index, v_vol(i,j)); //vyy float visc_top = viscosity(i,j); float visc_bottom = viscosity(i,j-1); float vol_top = c_vol(i,j); float vol_bottom = c_vol(i,j-1); //vy_top vmatrix.add_to_element(index,index, +2*factor*visc_top*vol_top); if(v_state(i,j+1) == FLUID) vmatrix.add_to_element(index,v_ind(i,j+1), -2*factor*visc_top*vol_top); else if (v_state(i,j+1) == SOLID) vrhs[index] -= -2*factor*visc_top*vol_top*v_obj; //vy_bottom vmatrix.add_to_element(index,index, +2*factor*visc_bottom*vol_bottom); if(v_state(i,j-1) == FLUID) vmatrix.add_to_element(index,v_ind(i,j-1), -2*factor*visc_bottom*vol_bottom); else if(v_state(i,j-1) == SOLID) vrhs[index] -= -2*factor*visc_bottom*vol_bottom*v_obj; //vxx terms float visc_right = 0.25f*(viscosity(i,j-1) + viscosity(i+1,j-1) + viscosity(i,j) + viscosity(i+1,j)); float visc_left = 0.25f*(viscosity(i,j-1) + viscosity(i-1,j-1) + viscosity(i,j) + viscosity(i-1,j)); float vol_right = n_vol(i+1,j); float vol_left = n_vol(i,j); //v_x_right vmatrix.add_to_element(index,index, +factor*visc_right*vol_right); if(v_state(i+1,j) == FLUID) vmatrix.add_to_element(index,v_ind(i+1,j), -factor*visc_right*vol_right); else if(v_state(i+1,j) == SOLID) vrhs[index] -= -v_obj*factor*visc_right*vol_right; //v_x_left vmatrix.add_to_element(index,index, +factor*visc_left*vol_left); if(v_state(i-1,j) == FLUID) vmatrix.add_to_element(index,v_ind(i-1,j), -factor*visc_left*vol_left); else if(v_state(i-1,j) == SOLID) vrhs[index] -= -v_obj*factor*visc_left*vol_left; //uyx //u_y_right if(u_state(i+1,j) == FLUID) vmatrix.add_to_element(index,u_ind(i+1,j), -factor*visc_right*vol_right); else if(u_state(i+1,j) == SOLID) vrhs[index] -= -u_obj*factor*visc_right*vol_right; if(u_state(i+1,j-1) == FLUID) vmatrix.add_to_element(index,u_ind(i+1,j-1), factor*visc_right*vol_right); else if(u_state(i+1,j-1) == SOLID) vrhs[index] -= u_obj*factor*visc_right*vol_right; //u_y_left if(u_state(i,j) == FLUID) vmatrix.add_to_element(index,u_ind(i,j), factor*visc_left*vol_left); else if(u_state(i,j) == SOLID) vrhs[index] -= u_obj*factor*visc_left*vol_left; if(u_state(i,j-1) == FLUID) vmatrix.add_to_element(index,u_ind(i,j-1), -factor*visc_left*vol_left); else if(u_state(i,j-1) == SOLID) vrhs[index] -= -u_obj*factor*visc_left*vol_left; } } double res_out; int iter_out; solver.solve(vmatrix, vrhs, velocities, res_out, iter_out); for(int j = 0; j < nj; ++j) for(int i = 0; i < ni+1; ++i) if(u_state(i,j) == FLUID) u(i,j) = (float)velocities[u_ind(i,j)]; else if(u_state(i,j) == SOLID) u(i,j) = u_obj; for(int j = 0; j < nj+1; ++j) for(int i = 0; i < ni; ++i) if(v_state(i,j) == FLUID) v(i,j) = (float)velocities[v_ind(i,j)]; else if(v_state(i,j) == SOLID) v(i,j) = v_obj; }