/* open fill's output stream and get all info from there; delete fillStream */ AMI_STREAM<sweepItem>* fillstr2sweepstr(AMI_STREAM<waterWindowBaseType>* fillStream) { Rtimer rt; AMI_STREAM<sweepItem> *sweepstr; rt_start(rt); if (stats) stats->comment("creating sweep stream from fill output stream"); assert(fillStream->stream_len() == nrows * ncols); /* create the sweep stream */ sweepstr = new AMI_STREAM<sweepItem>(); waterWindowBaseType2sweepItem(fillStream, nrows, ncols, nodataType::ELEVATION_NODATA, sweepstr); delete fillStream; if (opt->verbose) { fprintf(stderr, "sweep stream size: %.2fMB", (double)sweepstr->stream_len()*sizeof(sweepItem)/(1<<20)); fprintf(stderr, " (%d items, item size=%d B\n ", (int)sweepstr->stream_len(), sizeof(sweepItem));; } if (stats) stats->recordLength("sweep stream", sweepstr); /* sort sweep stream by (increasing) priority */ if (opt->verbose) { fprintf(stderr, "sorting sweep stream (%.2fMB) in priority order\n", (double)sweepstr->stream_len()*sizeof(sweepItem)/(1<<20)); } if (stats) stats->comment("sorting sweep stream"); sort(&sweepstr, PrioCmpSweepItem()); rt_stop(rt); if (stats) { stats->recordTime("create sweep stream", rt); stats->recordLength("(sorted) sweep stream", sweepstr); } return sweepstr; }
AMI_STREAM<elevation_type> * classifyNodata(AMI_STREAM<elevation_type> *elstr) { Rtimer rt; rt_start(rt); if (stats) stats->comment("finding nodata", opt->verbose); detectEdgeNodata md(nrows, ncols, nodataType::ELEVATION_NODATA); md.generateNodata(*elstr); if (stats) *stats << "nodata stream length = " << md.getNodata()->stream_len() << endl; { char * foo; md.getNodata()->name(&foo); if (stats) *stats << "nodata stream name: " << foo << endl; } rt_stop(rt); if (stats) stats->recordTime("classifyNodata::generate nodata", rt); rt_start(rt); if (stats) stats->comment("relabeling nodata", opt->verbose); md.relabelNodata(); /* re-assign labels (combine connected plateaus) */ rt_stop(rt); if (stats) stats->recordTime("classifyNodata::relabeling", rt); rt_start(rt); if (stats) stats->comment("merging relabeled grid", opt->verbose); AMI_STREAM<elevation_type> *mergeStr; mergeStr = md.merge(); rt_stop(rt); if (stats) stats->recordTime("classifyNodata::merge", rt); mergeStr->seek(0); return mergeStr; }
/* collapse labels; remove nodata regions */ void detectEdgeNodata::relabelNodata() { AMI_err ae; nodataType *pt; /* sort by label */ if (stats) NODATA_DEBUG *stats << "sort nodataStream (by nodata label): "; AMI_STREAM<nodataType> *sortedInStream; sortedInStream = sort(nodataStream, labelCmpNodataType()); delete nodataStream; nodataStream = new AMI_STREAM<nodataType>(); while((ae = sortedInStream->read_item(&pt)) == AMI_ERROR_NO_ERROR) { cclabel_type root = colTree.findNextRoot(pt->label); assert(root <= pt->label); pt->label = root; ae = nodataStream->write_item(*pt); assert(ae == AMI_ERROR_NO_ERROR); } delete sortedInStream; }
void flow_waterWindower::processWindow(dimension_type i, dimension_type j, waterWindowBaseType *a, waterWindowBaseType *b, waterWindowBaseType *c) { elevation_type el1[3], el2[3], el3[3]; toporank_type ac1[3], ac2[3], ac3[3]; if (is_nodata(b[1].el)) { /*sweep_str does not include nodata */ return; } /*#ifdef COMPRESSED_WINDOWS sweepItem win = sweepItem(i, j, a, b, c); #else */ for (int k=0; k<3; k++) { el1[k] = a[k].el; ac1[k] = -a[k].depth; /*WEIRD */ el2[k] = b[k].el; ac2[k] = -b[k].depth; /*WEIRD*/ el3[k] = c[k].el; ac3[k] = -c[k].depth; /*WEIRD*/ } /* genericWindow<elevation_type> e_win(el); genericWindow<toporank_type> a_win(ac); sweepItem win = sweepItem(i, j, b[1].dir, e_win, a_win); */ sweepItem win = sweepItem(i, j, b[1].dir, el1, el2, el3, ac1, ac2, ac3); /* #endif */ AMI_err ae = sweep_str->write_item(win); assert(ae == AMI_ERROR_NO_ERROR); }
void ccforest<T>::findAllRoots(int depth) { if(foundAllRoots) return; foundAllRoots = 1; Rtimer rt; rt_start(rt); if(depth > 5) { cerr << "WARNING: excessive recursion in ccforest (ignored)" << endl; } int explicitRootCount = 0; assert(!superTree); superTree = new ccforest<T>(); if (stats) DEBUG_CCFOREST *stats << "sort edgeStream (by cclabel)): "; keyCmpKeyvalueType<T> fo; sort(&edgeStream, fo); /* XXX -changed this to use a cmp obj */ /* time forward processing */ EMPQueueAdaptive<cckeyvalue,T> *pq = new EMPQueueAdaptive<cckeyvalue,T>(); /* parent queue */ size_t streamLength = edgeStream->stream_len(); T prevSrc = T(-1); T parent = T(-1); ccedge prevEdge; for(unsigned int i=0; i<streamLength; i++) { ccedge *e; AMI_err ae = edgeStream->read_item(&e); assert(ae == AMI_ERROR_NO_ERROR); #if(0) if (stats) { DEBUG_CCFOREST *stats << "------------------------------" << endl; DEBUG_CCFOREST *stats << "processing edge " << *e << endl; } DEBUG_CCFOREST pq->print(); #endif if(*e == prevEdge) { if (stats) DEBUG_CCFOREST *stats << "\tduplicate " << *e << " removed\n"; continue; /* already have this done */ } prevEdge = *e; if (stats) DEBUG_CCFOREST *stats << "processing edge " << *e << endl; /* find root (assign parent) */ if(e->src() != prevSrc) { prevSrc = e->src(); cckeyvalue kv; /* check if we have a key we don't use. */ while(pq->min(kv) && (kv.getPriority() < e->src())) { pq->extract_min(kv); assert(kv.src() >= kv.dst()); removeDuplicates(kv.src(), kv.dst(), *pq); ae = rootStream->write_item(kv); /* save root */ assert(ae == AMI_ERROR_NO_ERROR); } /* try to find our root */ if(pq->min(kv) && ((e->src() == kv.getPriority()))) { pq->extract_min(kv); parent = kv.getValue(); removeDuplicates(e->src(), parent, *pq); } else { parent = e->src(); /* we are root */ explicitRootCount++; /* technically, we could skip this part. the lookup function automatically assumes that values without parents are roots */ } /* save result */ cckeyvalue kroot(e->src(), parent); assert(kroot.src() >= kroot.dst()); ae = rootStream->write_item(kroot); assert(ae == AMI_ERROR_NO_ERROR); } #ifndef NDEBUG cckeyvalue kv2; assert(pq->is_empty() || (pq->min(kv2) && kv2.getPriority() > e->src())); #endif /* insert */ cckeyvalue kv(e->dst(), parent); assert(kv.src() >= kv.dst()); pq->insert(kv); /* cout << "identified: " << kroot << endl; */ } /* drain the priority queue */ if (stats) DEBUG_CCFOREST *stats << "draining priority queue" << endl; while (!pq->is_empty()) { cckeyvalue kv; pq->extract_min(kv); assert(kv.src() >= kv.dst()); if (stats) DEBUG_CCFOREST *stats << "processing edge " << kv << endl; removeDuplicates(kv.src(), kv.dst(), *pq); AMI_err ae = rootStream->write_item(kv); assert(ae == AMI_ERROR_NO_ERROR); } delete pq; /* note that rootStream is naturally ordered by src */ if(superTree->size()) { if (stats) { DEBUG_CCFOREST *stats << "resolving cycles..." << endl; /* printStream(rootStream); */ DEBUG_CCFOREST *stats << "sort rootStream: "; } AMI_STREAM<cckeyvalue> *sortedRootStream; dstCmpKeyvalueType<T> dstfo; sortedRootStream = sort(rootStream, dstfo); /* XXX replaced this to use a cmp object -- laura AMI_STREAM<cckeyvalue>*sortedRootStream=new AMI_STREAM<cckeyvalue>(); AMI_err ae = AMI_sort(rootStream, sortedRootStream, valueCmp); assert(ae == AMI_ERROR_NO_ERROR); */ delete rootStream; cckeyvalue *kv; T parent; AMI_err ae; AMI_STREAM<cckeyvalue>* relabeledRootStream = new AMI_STREAM<cckeyvalue>(); ae = sortedRootStream->seek(0); superTree->findAllRoots(depth+1); while((ae = sortedRootStream->read_item(&kv)) == AMI_ERROR_NO_ERROR) { parent = superTree->findNextRoot(kv->dst()); ae = relabeledRootStream->write_item(cckeyvalue(kv->src(), parent)); assert(ae == AMI_ERROR_NO_ERROR); } delete sortedRootStream; if (stats) DEBUG_CCFOREST *stats << "sort relabeledRootStream: "; rootStream = sort(relabeledRootStream, fo); /* laura: changed this rootStream = new AMI_STREAM<cckeyvalue>(); ae = AMI_sort(relabeledRootStream, rootStream); assert(ae == AMI_ERROR_NO_ERROR); */ delete relabeledRootStream; if (stats) DEBUG_CCFOREST *stats << "resolving cycles... done." << endl; } rootStream->seek(0); if (stats){ DEBUG_CCFOREST *stats << "Rootstream length=" << rootStream->stream_len() << endl; DEBUG_CCFOREST printStream(*stats, rootStream); DEBUG_CCFOREST *stats << "Explicit root count=" << explicitRootCount << endl; } rt_stop(rt); if (stats) stats->recordTime("ccforest::findAllRoots", (long int)rt_seconds(rt)); }
/* deletes fillStream */ void computeFlowAccumulation(AMI_STREAM<waterWindowBaseType>* fillStream, AMI_STREAM<sweepOutput> *& outstr) { Rtimer rt, rtTotal; AMI_STREAM<sweepItem> *sweepstr; rt_start(rtTotal); assert(fillStream && outstr == NULL); if (stats) { stats->comment("------------------------------"); stats->comment("COMPUTING FLOW ACCUMULATION"); } { /* timestamp stats file and print memory */ time_t t = time(NULL); char buf[BUFSIZ]; if(t == (time_t)-1) { perror("time"); exit(1); } #ifdef __MINGW32__ strcpy(buf, ctime(&t)); #else ctime_r(&t, buf); buf[24] = '\0'; #endif if (stats) { stats->timestamp(buf); *stats << endl; } size_t mm_size = (opt->mem << 20); /* (in bytes) */ formatNumber(buf, mm_size); if (stats) *stats << "memory size: " << buf << " bytes\n"; } /* create sweepstream using info from fillStream */ sweepstr = fillstr2sweepstr(fillStream); /* fillStream is deleted inside fillstr2sweepstr */ /* sweep and dump outputs into outStream; trustdir=1 */ outstr = sweep(sweepstr, opt->d8cut, 1); assert(outstr->stream_len() == sweepstr->stream_len()); delete sweepstr; /* sort output stream into a grid */ rt_start(rt); if (stats) { stats->comment( "sorting sweep output stream"); stats->recordLength("output stream", outstr); } sort(&outstr, ijCmpSweepOutput()); rt_stop(rt); if (stats) { stats->recordLength("output stream", outstr); stats->recordTime("sorting output stream", rt); } rt_stop(rtTotal); if (stats) stats->recordTime("compute flow accumulation", rtTotal); #ifdef SAVE_ASCII printStream2Grid(outstr, nrows, ncols, "flowaccumulation.asc", printAccumulationAscii()); printStream2Grid(outstr, nrows, ncols, "tci.asc", printTciAscii()); #endif return; }
/* ---------------------------------------------------------------------- */ int main(int argc, char *argv[]) { struct GModule *module; Rtimer rtTotal; char buf[BUFSIZ]; /* initialize GIS library */ G_gisinit(argv[0]); module = G_define_module(); #ifdef ELEV_SHORT module->description = _("Flow computation for massive grids (integer version)."); #endif #ifdef ELEV_FLOAT module->description = _("Flow computation for massive grids (float version)."); #endif G_add_keyword(_("raster")); G_add_keyword(_("hydrology")); /* read user options; fill in global <opt> */ opt = (userOptions*)malloc(sizeof(userOptions)); assert(opt); region = (struct Cell_head*)malloc(sizeof(struct Cell_head)); assert(region); parse_args(argc, argv); /* get the current region and dimensions */ G_get_set_window(region); check_args(); int nr = Rast_window_rows(); int nc = Rast_window_cols(); if ((nr > dimension_type_max) || (nc > dimension_type_max)) { G_fatal_error(_("[nrows=%d, ncols=%d] dimension_type overflow -- " "change dimension_type and recompile"), nr, nc); } else { nrows = (dimension_type)nr; ncols = (dimension_type)nc; } G_verbose_message( _("Region size is %d x %d"), nrows, ncols); /* check STREAM path (the place where intermediate STREAMs are placed) */ sprintf(buf, "%s=%s",STREAM_TMPDIR, opt->streamdir); /* don't pass an automatic variable; putenv() isn't guaranteed to make a copy */ putenv(G_store(buf)); if (getenv(STREAM_TMPDIR) == NULL) { fprintf(stderr, "%s:", STREAM_TMPDIR); G_fatal_error("not set"); } else { fprintf(stderr, "STREAM temporary files in %s ", getenv(STREAM_TMPDIR)); fprintf(stderr, "(THESE INTERMEDIATE STREAMS WILL NOT BE DELETED IN CASE OF ABNORMAL TERMINATION OF THE PROGRAM. TO SAVE SPACE PLEASE DELETE THESE FILES MANUALLY!)\n"); } /* open the stats file */ stats = new statsRecorder(opt->stats); record_args(argc, argv); { char buf[BUFSIZ]; long grid_size = nrows * ncols; *stats << "region size = " << formatNumber(buf, grid_size) << " elts " << "(" << nrows << " rows x " << ncols << " cols)\n"; stats->flush(); } /* set up STREAM memory manager */ size_t mm_size = (size_t) opt->mem << 20; /* opt->mem is in MB */ MM_manager.set_memory_limit(mm_size); if (opt->verbose) { MM_manager.warn_memory_limit(); } else { MM_manager.ignore_memory_limit(); } MM_manager.print_limit_mode(); /* initialize nodata */ nodataType::init(); *stats << "internal nodata value: " << nodataType::ELEVATION_NODATA << endl; /* start timing -- after parse_args, which are interactive */ rt_start(rtTotal); #ifndef JUMP2FLOW /* read elevation into a stream */ AMI_STREAM<elevation_type> *elstr=NULL; long nodata_count; elstr = cell2stream<elevation_type>(opt->elev_grid, elevation_type_max, &nodata_count); /* print the largest interm file that will be generated */ printMaxSortSize(nodata_count); /* -------------------------------------------------- */ /* compute flow direction and filled elevation (and watersheds) */ AMI_STREAM<direction_type> *dirstr=NULL; AMI_STREAM<elevation_type> *filledstr=NULL; AMI_STREAM<waterWindowBaseType> *flowStream=NULL; AMI_STREAM<labelElevType> *labeledWater = NULL; flowStream=computeFlowDirections(elstr, filledstr, dirstr, labeledWater); delete elstr; /* write streams to GRASS raster maps */ stream2_CELL(dirstr, nrows, ncols, opt->dir_grid); delete dirstr; #ifdef ELEV_SHORT stream2_CELL(filledstr, nrows, ncols, opt->filled_grid); #else stream2_CELL(filledstr, nrows, ncols, opt->filled_grid,true); #endif delete filledstr; stream2_CELL(labeledWater, nrows, ncols, labelElevTypePrintLabel(), opt->watershed_grid); setSinkWatershedColorTable(opt->watershed_grid); delete labeledWater; #else AMI_STREAM<waterWindowBaseType> *flowStream; char path[GPATH_MAX]; sprintf(path, "%s/flowStream", streamdir->answer); flowStream = new AMI_STREAM<waterWindowBaseType>(path); fprintf(stderr, "flowStream opened: len=%d\n", flowStream->stream_len()); fprintf(stderr, "jumping to flow accumulation computation\n"); #endif /* -------------------------------------------------- */ /* compute flow accumulation (and tci) */ AMI_STREAM<sweepOutput> *outstr=NULL; computeFlowAccumulation(flowStream, outstr); /* delete flowStream -- deleted inside */ /* write output stream to GRASS raster maps */ #ifdef OUTPUT_TCI stream2_FCELL(outstr, nrows, ncols, printAccumulation(), printTci(), opt->flowaccu_grid, opt->tci_grid); #else stream2_FCELL(outstr, nrows, ncols, printAccumulation(), opt->flowaccu_grid); #endif setFlowAccuColorTable(opt->flowaccu_grid); delete outstr; rt_stop(rtTotal); stats->recordTime("Total running time: ", rtTotal); stats->timestamp("end"); G_done_msg(" "); /* free the globals */ free(region); free(opt); delete stats; return 0; }
void detectEdgeNodata::processWindow(dimension_type row, dimension_type col, elevation_type &point, elevation_type *a, elevation_type *b, elevation_type *c) { AMI_err ae; static nodataType prevCell; /* cell on left (gets initialized) */ assert(row>=0); assert(col>=0); /* create window and write out */ ElevationWindow win(a, b, c); fillPit(win); /* fill pit in window */ ae = elevStream->write_item(win.get()); assert(ae == AMI_ERROR_NO_ERROR); /* only interested in nodata in this pass */ if(win.get() != nodata) { prevCell.label = LABEL_UNDEF; return; } if(col == 0) prevCell.label = LABEL_UNDEF; /* no left cell */ /* now check for continuing plateaus */ nodataType *ptarr = getNodataForward(row-1, col-1, nr, nc); /* make sure we use boundary label if appropriate */ cclabel_type crtlabel; crtlabel = (IS_BOUNDARY(row,col,nr, nc) ? LABEL_BOUNDARY : LABEL_UNDEF); for(int i=0; i<4; i++) { if(win.get(i) != win.get()) continue; /* only interesting if same elev */ /* determine label for cell */ cclabel_type label = LABEL_UNDEF; if(i<3) { if(ptarr[i].valid) label = ptarr[i].label; } else { if(prevCell.valid) label = prevCell.label; } /* check for collisions */ if(label != LABEL_UNDEF) { if (crtlabel == LABEL_UNDEF) { crtlabel = label; } else if(crtlabel != label) { /* collision!! */ /* pick smaller label, but prefer nodata */ if(crtlabel==LABEL_BOUNDARY || crtlabel<label) { colTree.insert(crtlabel, label); } else { colTree.insert(label, crtlabel); crtlabel = label; } } } } /* assign label if required */ if(crtlabel == LABEL_UNDEF) { crtlabel = labelFactory::getNewLabel(); } /* write this plateau point to the plateau stream */ nodataType pt; prevCell = pt = nodataType(row, col, crtlabel); nodataQueue->enqueue(pt); /* NODATA_DEBUG *stats << "inserting " << pt << endl; */ nodataStream->write_item(pt); /* save to file for later use */ }