/*+ VIDE -- Void IDentification and Examination -- ./c_tools/zobov2/jozov2/jozov2_watershed.cpp Copyright (C) 2010-2014 Guilhem Lavaux Copyright (C) 2011-2014 P. M. Sutter This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ #ifdef OPENMP #include #endif #include #include #include #include #include #include #include "jozov2.hpp" #include "zobov.hpp" using namespace std; using boost::format; struct ZoneDensityPair { int h; double density; double core; bool operator<(const ZoneDensityPair& p2) const { return (density > p2.density) || (density==p2.density && core > p2.core); } }; typedef priority_queue ZoneQueue; static void build_process_queue(ZoneQueue& q, ZONE *z, PARTICLE *p, char *inyet, int h) { ZoneDensityPair zdp; ZONE& z_h = z[h]; bool interior = true; assert(inyet[h] == 1); for (int za = 0; za < z_h.nadj; za++) { zdp.h = z_h.adj[za]; zdp.density = z_h.slv[za]; zdp.core = p[z[zdp.h].core].dens; if (inyet[zdp.h] == 0) { q.push(zdp); interior = false; } } if (interior) inyet[h] = 2; } void doWatershed(PARTICLE *p, pid_t np, ZONE *z, int numZones, float maxvol, float voltol) { /* Text output file */ #pragma omp parallel { char *inyet, *inyet2; int *zonelist, *zonelist2; int nhl; int prev_ii = -1; inyet = new char[numZones]; inyet2 = new char[numZones]; zonelist = new int[numZones]; zonelist2 = new int[numZones]; fill(inyet, inyet + numZones, 0); fill(inyet2, inyet2 + numZones, 0); nhl = 0; #pragma omp for schedule(dynamic,1) for (int h = 0; h < numZones; h++) { int nhlcount = 0; float previous_lowvol = BIGFLT, lowvol, z_cur_core_dens; bool beaten; priority_queue to_process; int link0; int save_nhl; pid_t save_npjoin; for (int hl = 0; hl < nhl; hl++) inyet[zonelist[hl]] = 0; zonelist[0] = h; inyet[h] = 1; save_nhl = nhl = 1; save_npjoin = z[h].npjoin = z[h].np; z_cur_core_dens = p[z[h].core].dens; build_process_queue(to_process, z, p, inyet, h); do { /* Find the lowest-volume (highest-density) adjacency */ beaten = false; if (to_process.empty()) { beaten = true; z[h].leak = maxvol; save_npjoin = z[h].npjoin; save_nhl = nhl; continue; } do { lowvol = to_process.top().density; link0 = to_process.top().h; to_process.pop(); } while ((inyet[link0] != 0) && (!to_process.empty())); if (to_process.empty()) { save_npjoin = z[h].npjoin; save_nhl = nhl; beaten = true; z[h].leak = maxvol; continue; } /* See if there's a beater */ if (previous_lowvol != lowvol) { save_npjoin = z[h].npjoin; save_nhl = nhl; previous_lowvol = lowvol; } if (lowvol > voltol) { beaten = true; z[h].leak = lowvol; continue; } if (p[z[link0].core].dens < z_cur_core_dens) { beaten = true; z[h].leak = lowvol; continue; } /* Add everything linked to the link(s) */ int nhl2 = 0; zonelist2[0] = link0; inyet2[link0] = 1; nhl2=1; bool added = true; while (added && !beaten) { added = false; for (int hl = 0; (hl < nhl2) && (!beaten); hl++) { int h2 = zonelist2[hl]; if (inyet2[h2] == 1) { bool interior = true; /* Guilty until proven innocent */ for (int za = 0; za < z[h2].nadj; za ++) { int link2 = z[h2].adj[za]; if ((inyet[link2]+inyet2[link2]) == 0) { interior = false; if (z[h2].slv[za] <= lowvol) { if (p[z[link2].core].dens < z_cur_core_dens) { beaten = true; break; } zonelist2[nhl2] = link2; inyet2[link2] = 1; nhl2++; added = true; } } } if (interior) inyet2[h2] = 2; } } } /* See if there's a beater */ if (beaten) { z[h].leak = lowvol; } else { for (int h2 = 0; h2 < nhl2; h2++) { int new_h = zonelist2[h2]; zonelist[nhl] = new_h; assert(inyet[new_h] == 0); z[h].npjoin += z[new_h].np; inyet[new_h] = 1; if (inyet2[new_h] != 2) build_process_queue(to_process, z, p, inyet, new_h); nhl++; } } for (int hl = 0; hl < nhl2; hl++) inyet2[zonelist2[hl]] = 0; if (nhl/10000 > nhlcount) { if (nhlcount == 0) (cout << format("Zone %d: %d") % h % nhl).flush(); else (cout << format(" %d [%d]") % nhl % to_process.size()).flush(); nhlcount = nhl/10000; } } while((lowvol < BIGFLT) && (!beaten)); if (!beaten) { save_npjoin = z[h].npjoin; save_nhl = nhl; } z[h].denscontrast = z[h].leak/p[z[h].core].dens; if (z[h].denscontrast < 1.) z[h].denscontrast = 1.; /* Don't sort; want the core zone to be first */ if (nhlcount > 0) { /* Outputs the number of zones in large voids */ printf(" h%d:%d\n",h,nhl); FF; } /* Calculate volume */ z[h].npjoin = save_npjoin; z[h].voljoin = 0.; z[h].zonelist = new int[save_nhl]; z[h].numzones = save_nhl; for (int q = 0; q < save_nhl; q++) { z[h].voljoin += z[zonelist[q]].vol; z[h].zonelist[q] = zonelist[q]; } z[h].nhl = save_nhl; } delete[] zonelist; delete[] zonelist2; delete[] inyet; delete[] inyet2; } double maxdenscontrast = 0; #pragma omp parallel shared(maxdenscontrast) { double maxdenscontrast_local = 0; #pragma omp for schedule(static) for (int h = 0; h < numZones; h++) { /* find biggest denscontrast */ if (z[h].denscontrast > maxdenscontrast_local) { maxdenscontrast_local = (double)z[h].denscontrast; } } #pragma omp critical { if (maxdenscontrast_local > maxdenscontrast) maxdenscontrast = maxdenscontrast_local; } } cout << format("Maxdenscontrast = %f.") % maxdenscontrast << endl; }