sgsPy
structurally guided sampling
Loading...
Searching...
No Matches
strat.h
Go to the documentation of this file.
1/******************************************************************************
2 *
3 * Project: sgs
4 * Purpose: C++ implementation of stratified sampling
5 * Author: Joseph Meyer
6 * Date: September, 2025
7 *
8 ******************************************************************************/
9
14
15#include <iostream>
16#include <random>
17
18#include "utils/access.h"
19#include "utils/existing.h"
20#include "utils/helper.h"
21#include "utils/raster.h"
22#include "utils/vector.h"
23
24#include <xoshiro.h>
25
26namespace sgs {
27namespace strat {
28
40std::vector<int64_t>
42 int64_t numSamples,
43 std::string allocation,
44 std::vector<int64_t> strataCounts,
45 std::vector<double> weights,
46 int64_t numPixels)
47{
48 std::vector<int64_t> retval;
49 int64_t remainder = numSamples;
50 int64_t numStrata = strataCounts.size();
51 if (allocation == "prop") {
52 //allocate the samples per stratum according to stratum size
53 int64_t pixelsPerSample = numPixels / numSamples;
54
55 //add 1 if pixelsPerSample was truncated down, to avoid adding too many samples
56 pixelsPerSample += static_cast<int64_t>(pixelsPerSample * numSamples < numPixels);
57
58 for (int64_t i = 0; i < numStrata; i++) {
59 int64_t count = strataCounts[i] / pixelsPerSample;
60 retval.push_back(count);
61 remainder -= count;
62 }
63 }
64 else if (allocation == "equal") {
65 //determine the count of samples per strata
66 int64_t strataSampleCount = numSamples / numStrata;
67
68 for (int64_t i = 0; i < numStrata; i++) {
69 retval.push_back(strataSampleCount);
70 remainder -= strataSampleCount;
71 }
72 }
73 else if (allocation == "manual" || allocation == "optim") {
74 //allocate samples accordign to weights.
75 //Optim allocation calculates these weights whereas when using manual the weights are given by the user
76 for (int64_t i = 0; i < numStrata; i++) {
77 int64_t count = static_cast<int64_t>(static_cast<double>(numSamples) * weights[i]);
78 retval.push_back(count);
79 remainder -= count;
80 }
81 }
82 else {
83 throw std::runtime_error("allocation method must be one of 'prop', 'equal', 'manual', or 'optim'.");
84 }
85
86 //redistribute remainder pixels among strata, and check strata sizes
87 for (int64_t i = numStrata; i > 0; i--) {
88 int64_t extra = remainder / i;
89 retval[i - 1] += extra;
90 remainder -= extra;
91
92 if (retval[i - 1] > strataCounts[i - 1]) {
93 std::cout << "warning: strata " << i - 1 << " does not have enough pixels for the full " << retval[i - 1] << " samples it should recieve. There will be less than " << numSamples << " final samples." << std::endl;
94 retval[i - 1] = strataCounts[i - 1];
95 }
96 }
97
98 return retval;
99}
100
111 std::vector<helper::Variance> variances;
112 bool used = false;
113
123 OptimAllocationDataManager(raster::GDALRasterWrapper *p_raster, int bandNum, std::string allocation) {
124 if (!p_raster || allocation != "optim") {
125 return;
126 }
127
128 this->band.p_band = p_raster->getRasterBand(bandNum);
129 this->band.type = p_raster->getRasterBandType(bandNum);
130 this->band.size = p_raster->getRasterBandTypeSize(bandNum);
131 this->band.p_buffer = nullptr; //allocated later
132 this->band.nan = this->band.p_band->GetNoDataValue();
133 this->band.p_band->GetBlockSize(&this->band.xBlockSize, &this->band.yBlockSize);
134 this->used = true;
135 }
136
142 if (this->used) {
143 VSIFree(this->band.p_buffer);
144 }
145 }
146
156 inline void
157 init(int numStrata, int xBlockSize, int yBlockSize) {
158 this->variances.resize(numStrata);
159 this->band.p_buffer = VSIMalloc3(xBlockSize, yBlockSize, band.size);
160 }
161
173 inline void
174 readNewBlock(int xBlockSize, int yBlockSize, int xBlock, int yBlock, int xValid, int yValid) {
175 helper::rasterBandIO(this->band, this->band.p_buffer, xBlockSize, yBlockSize, xBlock, yBlock, xValid, yValid, true, false);
176 }
177
186 inline void
187 update(int index, int strata) {
188 double val = helper::getPixelValueDependingOnType<double>(this->band.type, this->band.p_buffer, index);
189 variances[strata].update(val);
190 }
191
204 inline std::vector<double>
206 std::vector<double> retval(variances.size());
207
208 double total = 0;
209 for (size_t i = 0; i < variances.size(); i++) {
210 double stdev = variances[i].getStdev();
211 double count = static_cast<double>(variances[i].getCount());
212 double product = count == 0 ? 0 : stdev * count; //if count == 0 stdev will be nan, this stops the nan from spreading
213 retval[i] = product;
214 total += product;
215 }
216
217 for (size_t i = 0; i < variances.size(); i++) {
218 retval[i] = retval[i] / total;
219 }
220
221 return retval;
222 }
223};
224
243private:
244 std::vector<int64_t> strataCounts;
245
246 std::vector<int64_t> indexCountPerStrata;
247 std::vector<std::vector<helper::Index>> indexesPerStrata;
248
249 std::vector<int64_t> firstXIndexCountPerStrata;
250 std::vector<std::vector<helper::Index>> firstXIndexesPerStrata;
251
252 int64_t numStrata;
253 int64_t x;
254
255public:
263 IndexStorageVectors(int64_t numStrata, int64_t x) {
264 this->numStrata = numStrata;
265 this->x = x;
266
267 this->strataCounts.resize(numStrata);
268
269 this->indexCountPerStrata.resize(numStrata, 0);
270 this->indexesPerStrata.resize(numStrata);
271
272 this->firstXIndexCountPerStrata.resize(numStrata, 0);
273 this->firstXIndexesPerStrata.resize(numStrata);
274 for (int64_t i = 0; i < numStrata; i++) {
275 this->firstXIndexesPerStrata[i].resize(x);
276 }
277 }
278
284 inline void
285 updateStrataCounts(int strata) {
286 this->strataCounts[strata]++;
287 }
288
296 inline void
297 updateIndexesVector(int strata, helper::Index& index) {
298 this->indexesPerStrata[strata].push_back(index);
299 this->indexCountPerStrata[strata]++;
300 }
301
309 inline void
311 int64_t i = firstXIndexCountPerStrata[strata];
312 if (i < this->x) {
313 firstXIndexesPerStrata[strata][i] = index;
314 firstXIndexCountPerStrata[strata]++;
315 }
316 else if (i == this->x) {
317 std::vector<helper::Index>().swap(firstXIndexesPerStrata[strata]);
318 firstXIndexCountPerStrata[strata]++;
319 }
320 }
321
340 inline std::vector<std::vector<helper::Index> *>
341 getStrataIndexVectors(std::vector<int64_t> existing, std::vector<int64_t> strataSampleCounts, xso::xoshiro_4x64_plus& rng) {
342 std::vector<std::vector<helper::Index> *> retval(numStrata);
343
344 for (int64_t i = 0; i < numStrata; i++) {
345 int64_t existingSamples = existing[i];
346 int64_t desiredSamples = strataSampleCounts[i];
347 int64_t remainingSamples = desiredSamples - existingSamples;
348
349 int64_t probIndexesCount = indexCountPerStrata[i];
350 int64_t firstXIndexesCount = firstXIndexCountPerStrata[i];
351
352 if (probIndexesCount >= remainingSamples || firstXIndexesCount > x) {
353 auto begin = this->indexesPerStrata[i].begin();
354 auto end = this->indexesPerStrata[i].end();
355 std::shuffle(begin, end, rng);
356 retval[i] = &this->indexesPerStrata[i];
357 }
358 else {
359 this->firstXIndexesPerStrata[i].resize(firstXIndexesCount);
360 auto begin = this->firstXIndexesPerStrata[i].begin();
361 auto end = this->firstXIndexesPerStrata[i].end();
362 std::shuffle(begin, end, rng);
363 retval[i] = &this->firstXIndexesPerStrata[i];
364 }
365 }
366
367 return retval;
368 }
369
375 inline std::vector<int64_t>
377 return this->strataCounts;
378 }
379
385 inline int64_t
387 int64_t retval = 0;
388
389 for (const int64_t& count : this->strataCounts) {
390 retval += count;
391 }
392
393 return retval;
394 }
395};
396
438template <typename T>
439std::vector<int64_t>
441 int numSamples,
442 int numStrata,
446 IndexStorageVectors& indices,
447 std::vector<std::vector<OGRPoint>>& existingSamples,
448 uint64_t multiplier,
449 xso::xoshiro_4x64_plus& rng,
450 std::string allocation,
452 std::vector<double> weights,
453 int width,
454 int height)
455{
456 T nanInt = static_cast<T>(band.nan);
457 int xBlockSize = band.xBlockSize;
458 int yBlockSize = band.yBlockSize;
459
460 int xBlocks = (width + xBlockSize - 1) / xBlockSize;
461 int yBlocks = (height + yBlockSize - 1) / yBlockSize;
462
463 band.p_buffer = VSIMalloc3(xBlockSize, yBlockSize, band.size);
464 T *p_buffer = reinterpret_cast<T *>(band.p_buffer);
465 int8_t *p_access = nullptr;
466 if (access.used) {
467 access.band.p_buffer = VSIMalloc3(xBlockSize, yBlockSize, access.band.size);
468 p_access = reinterpret_cast<int8_t *>(access.band.p_buffer);
469 }
470
471 helper::RandValController rand(band.xBlockSize, band.yBlockSize, multiplier, &rng);
472
473 if (optim.used) {
474 optim.init(numStrata, xBlockSize, yBlockSize);
475 }
476
477 for (int yBlock = 0; yBlock < yBlocks; yBlock++) {
478 for (int xBlock = 0; xBlock < xBlocks; xBlock++) {
479 int xValid, yValid;
480
481 //read block
482 band.p_band->GetActualBlockSize(xBlock, yBlock, &xValid, &yValid);
483 helper::rasterBandIO(band, band.p_buffer, xBlockSize, yBlockSize, xBlock, yBlock, xValid, yValid, true, false);
484
485 //read access block
486 if (access.used) {
487 helper::rasterBandIO(access.band, access.band.p_buffer, xBlockSize, yBlockSize, xBlock, yBlock, xValid, yValid, true, false);
488 }
489
490 //read mraster block for optim
491 if (optim.used) {
492 optim.readNewBlock(xBlockSize, yBlockSize, xBlock, yBlock, xValid, yValid);
493 }
494
495 //calculate rand vals
496 rand.calculateRandValues();
497
498 //iterate through block and update vectors
499 for (int y = 0; y < yValid; y++) {
500 int blockIndex = y * xBlockSize;
501 for (int x = 0; x < xValid; x++) {
502 T val = p_buffer[blockIndex];
503 helper::Index index = {x + xBlock * xBlockSize, y + yBlock * yBlockSize};
504
505 bool isNan = val == nanInt;
506 bool accessible = !access.used || p_access[blockIndex] != 1;
507 bool alreadySampled = existing.used && existing.containsIndex(index.x, index.y);
508
509 //check nan
510 if (isNan) {
511 blockIndex++;
512 continue;
513 }
514
515 if (val >= numStrata) {
516 throw std::runtime_error("the num_strata indicated for the strat raster band is less than or equal to one of the value sin that band.");
517 }
518
519 if (val < 0) {
520 std::string errmsg = "a negative value of " + std::to_string(val) + " was found in the strat raster, and has not been marked as a nodata value.";
521 throw std::runtime_error(errmsg);
522 }
523
524 //update optim allocation variance calculations
525 if (optim.used) {
526 optim.update(blockIndex, val);
527 }
528
529 //udpate strata counts
530 indices.updateStrataCounts(val);
531
532 //update existing sampled strata
533 if (alreadySampled) {
534 existingSamples[val].push_back(existing.getPoint(index.x, index.y));
535 }
536
537 //add val to stored indices
538 if (accessible && !alreadySampled) {
539 indices.updateFirstXIndexesVector(val, index);
540
541 if (rand.next()) {
542 indices.updateIndexesVector(val, index);
543 }
544 }
545
546 //increment block index
547 blockIndex++;
548 }
549 }
550 }
551 }
552
553 VSIFree(band.p_buffer);
554 if (access.used) {
555 VSIFree(access.band.p_buffer);
556 }
557
558 if (optim.used) {
559 weights = optim.getAllocationPercentages();
560 }
561
562 std::vector<int64_t> strataSampleCounts = calculateAllocation(
563 numSamples,
564 allocation,
565 indices.getStrataCounts(),
566 weights,
567 indices.getNumDataPixels()
568 );
569
570 return strataSampleCounts;
571}
572
605 int wrow, wcol;
606 int width;
607 int vpad, hpad;
608 std::vector<bool> m;
609 std::vector<bool> valid;
610
620 FocalWindow(int wrow, int wcol, int width) {
621 this->wrow = wrow;
622 this->vpad = wrow / 2;
623 this->wcol = wcol;
624 this->hpad = wcol / 2;
625 this->width = width;
626 this->m.resize(wrow * width, false);
627 this->valid.resize(wrow * width, false);
628 }
629
638 inline void
639 reset(int row) {
640 int start = (row % wrow) * this->width;
641 int end = start + this->width;
642 for (int i = start; i < end; i++) {
643 m[i] = false;
644 valid[i] = false;
645 }
646 }
647
670 inline bool
671 check(int x, int y) {
672 y = y % wrow;
673 switch (wrow) {
674 case 3:
675 return this->m[x] &&
676 this->m[x + width] &&
677 this->m[x + width * 2] &&
678 this->valid[x + y * width];
679 case 5:
680 return this->m[x] &&
681 this->m[x + width] &&
682 this->m[x + width * 2] &&
683 this->m[x + width * 3] &&
684 this->m[x + width * 4] &&
685 this->valid[x + y * width];
686 case 7:
687 return this->m[x] &&
688 this->m[x + width] &&
689 this->m[x + width * 2] &&
690 this->m[x + width * 3] &&
691 this->m[x + width * 4] &&
692 this->m[x + width * 5] &&
693 this->m[x + width * 6] &&
694 this->valid[x + y * width];
695 default:
696 throw std::runtime_error("wrow must be one of 3, 5, 7.");
697 }
698 }
699};
700
773template <typename T>
774std::vector<int64_t>
776 int numSamples,
777 int numStrata,
781 IndexStorageVectors& indices,
782 IndexStorageVectors& queinnecIndices,
783 FocalWindow& fw,
784 std::vector<std::vector<OGRPoint>>& existingSamples,
785 uint64_t multiplier,
786 uint64_t queinnecMultiplier,
787 xso::xoshiro_4x64_plus& rng,
788 std::string allocation,
790 std::vector<double> weights,
791 int width,
792 int height)
793{
794 T nanInt = static_cast<T>(band.nan);
795
796 //adjust blocks to be a large chunk of scanlines
797 int xBlockSize = band.xBlockSize;
798 int yBlockSize = band.yBlockSize;
799 if (xBlockSize != width) {
800 xBlockSize = width;
801 }
802 else {
803 yBlockSize = std::min(128, height);
804 }
805
806 //allocate required memory
807 band.p_buffer = VSIMalloc3(xBlockSize, yBlockSize + fw.vpad * 2, band.size);
808 T *p_buffer = reinterpret_cast<T *>(band.p_buffer);
809 int8_t *p_access = nullptr;
810 if (access.used) {
811 access.band.p_buffer = VSIMalloc3(xBlockSize, yBlockSize, access.band.size);
812 p_access = reinterpret_cast<int8_t *>(access.band.p_buffer);
813 }
814
815 helper::RandValController rand(xBlockSize, yBlockSize, multiplier, &rng);
816 helper::RandValController queinnecRand(xBlockSize, yBlockSize, queinnecMultiplier, &rng);
817
818 if (optim.used) {
819 optim.init(numStrata, xBlockSize, yBlockSize);
820 }
821
822 //get number of blocks
823 int yBlocks = (height + yBlockSize - 1) / yBlockSize;
824
825 int fwyi = 0;
826 for (int yBlock = 0; yBlock < yBlocks; yBlock++) {
827 //read block
828 int xOff = 0;
829 int yOff = yBlock * yBlockSize;
830 int xValid = width;
831 int yValid = std::min(yBlockSize, height - yBlock * yBlockSize);
832
833 //read block
834 if (yBlock == 0) {
835 CPLErr err = band.p_band->RasterIO(GF_Read, xOff, yOff, xValid, yValid, band.p_buffer, xValid, yValid, band.type, 0, 0);
836 if (err) {
837 throw std::runtime_error("error reading block from raster.");
838 }
839 }
840 else {
841 int stratYOff = yOff - fw.vpad * 2;
842 int stratYValid = yValid + fw.vpad * 2;
843 CPLErr err = band.p_band->RasterIO(GF_Read, xOff, stratYOff, xValid, stratYValid, band.p_buffer, xValid, stratYValid, band.type, 0, 0);
844 if (err) {
845 throw std::runtime_error("error reading block from raster.");
846 }
847 }
848
849 //read access block
850 if (access.used) {
851 CPLErr err = access.band.p_band->RasterIO(GF_Read, xOff, yOff, xValid, yValid, access.band.p_buffer, xValid, yValid, GDT_Int8, 0, 0);
852 if (err) {
853 throw std::runtime_error("error reading block from raster.");
854 }
855 }
856
857 //read mraster block for optim
858 if (optim.used) {
859 CPLErr err = optim.band.p_band->RasterIO(GF_Read, xOff, yOff, xValid, yValid, optim.band.p_buffer, xValid, yValid, optim.band.type, 0, 0);
860 if (err) {
861 throw std::runtime_error("error reading block from raster.");
862 }
863 }
864
865 //calculate rand vals
866 rand.calculateRandValues();
867 queinnecRand.calculateRandValues();
868
869 //calculate the within-block index. In the case where there is a padding at the top of the block,
870 //adjust for that.
871 int newBlockStart = (yBlock == 0) ? 0 : width * fw.vpad * 2;
872
873 //iterate through block and update vectors
874 for (int y = 0; y < yValid; y++) {
875 //reset upcomming row in focal window matrix
876 fw.reset(yBlock * yBlockSize + y);
877
878 //the indexes from 0 to the horizontal pad cannot be a queinnec index
879 //because they are too close to the edges of the raster
880 for (int x = 0; x < fw.hpad; x++) {
881 T val = p_buffer[newBlockStart + y * width + x];
882 helper::Index index = {x, y + yBlock * yBlockSize};
883
884 bool isNan = val == nanInt;
885 bool accessible = !access.used || p_access[y * width + x] != 1;
886 bool alreadySampled = existing.used && existing.containsIndex(index.x, index.y);
887
888 //check nan
889 if (isNan) {
890 continue;
891 }
892
893 //update optim allocation variance calculations
894 if (optim.used) {
895 optim.update(y * width + x, val);
896 }
897
898 //update strata counts
899 indices.updateStrataCounts(val);
900
901 //update existing samled strata
902 if (alreadySampled) {
903 existingSamples[val].push_back(existing.getPoint(index.x, index.y));
904 }
905
906 //add val to stored indices
907 if (accessible && !alreadySampled) {
908 indices.updateFirstXIndexesVector(val, index);
909
910 if (rand.next()) {
911 indices.updateIndexesVector(val, index);
912 }
913 }
914 }
915
916 for (int x = fw.hpad; x < width - fw.hpad; x++) {
917 T val = p_buffer[newBlockStart + y * width + x];
918 helper::Index index = {x, y + yBlock * yBlockSize};
919
920 bool isNan = val == nanInt;
921 bool accessible = !access.used || p_access[y * width + x] != 1;
922 bool alreadySampled = existing.used && existing.containsIndex(index.x, index.y);
923
924 //check nan
925 if (isNan) {
926 continue;
927 }
928
929 //update optim allocation variance calculations
930 if (optim.used) {
931 optim.update(y * width + x, val);
932 }
933
934 //update strata counts
935 indices.updateStrataCounts(val);
936
937 //update exisitng sampled strata
938 if (alreadySampled) {
939 existingSamples[val].push_back(existing.getPoint(index.x, index.y));
940 };
941
942 //set focal window matrix value by checking horizontal indices within focal window
943 int start = newBlockStart + y * width + x - fw.hpad;
944 switch (fw.wcol) {
945 case 3:
946 fw.m[fwyi + x] = p_buffer[start] == p_buffer[start + 1] &&
947 p_buffer[start] == p_buffer[start + 2];
948 break;
949 case 5:
950 fw.m[fwyi + x] = p_buffer[start] == p_buffer[start + 1] &&
951 p_buffer[start] == p_buffer[start + 2] &&
952 p_buffer[start] == p_buffer[start + 3] &&
953 p_buffer[start] == p_buffer[start + 4];
954 break;
955 case 7:
956 fw.m[fwyi + x] = p_buffer[start] == p_buffer[start + 1] &&
957 p_buffer[start] == p_buffer[start + 2] &&
958 p_buffer[start] == p_buffer[start + 3] &&
959 p_buffer[start] == p_buffer[start + 4] &&
960 p_buffer[start] == p_buffer[start + 5] &&
961 p_buffer[start] == p_buffer[start + 6];
962 break;
963 default:
964 throw std::runtime_error("wcol must be one of 3, 5, 6.");
965 }
966
967 //add val to stored indices and update focal window validity
968 if (accessible && !alreadySampled) {
969 indices.updateFirstXIndexesVector(val, index);
970
971 if (rand.next()) {
972 indices.updateIndexesVector(val, index);
973 }
974
975 fw.valid[fwyi + x] = true;
976 }
977
978 //add index to queinnec indices if surrounding focal window is all the same
979 helper::Index fwIndex = {x, index.y - fw.vpad};
980 if (fw.check(fwIndex.x, fwIndex.y)) {
981 bool add = false;
982 int start = newBlockStart + y * width + x - 2 * width * fw.vpad;
983 switch (fw.wrow) {
984 case 3:
985 add = p_buffer[start] == p_buffer[start + width * 1] &&
986 p_buffer[start] == p_buffer[start + width * 2];
987 break;
988 case 5:
989 add = p_buffer[start] == p_buffer[start + width * 1] &&
990 p_buffer[start] == p_buffer[start + width * 2] &&
991 p_buffer[start] == p_buffer[start + width * 3] &&
992 p_buffer[start] == p_buffer[start + width * 4];
993 break;
994 case 7:
995 add = p_buffer[start] == p_buffer[start + width * 1] &&
996 p_buffer[start] == p_buffer[start + width * 2] &&
997 p_buffer[start] == p_buffer[start + width * 3] &&
998 p_buffer[start] == p_buffer[start + width * 4] &&
999 p_buffer[start] == p_buffer[start + width * 5] &&
1000 p_buffer[start] == p_buffer[start + width * 6];
1001 break;
1002 }
1003
1004 if (add) {
1005 //(we know if we've made it here that val is the same for both the fw add and the current index)
1006 queinnecIndices.updateFirstXIndexesVector(val, fwIndex);
1007
1008 if (queinnecRand.next()) {
1009 queinnecIndices.updateIndexesVector(val, fwIndex);
1010 }
1011 }
1012 }
1013 }
1014
1015 //the indexes from width - horizontal pad to width cannot be a queinnec index
1016 //because they are too close to the edges of the raster
1017 for (int x = width - fw.hpad; x < width; x++) {
1018 T val = p_buffer[newBlockStart + y * width + x];
1019 helper::Index index = {x, y + yBlock * yBlockSize};
1020
1021 bool isNan = val == nanInt;
1022 bool accessible = !access.used || p_access[y * width + x] != 1;
1023 bool alreadySampled = existing.used && existing.containsIndex(index.x, index.y);
1024
1025 //check nan
1026 if (isNan) {
1027 continue;
1028 }
1029
1030 //update optim allocation variance calculations
1031 if (optim.used) {
1032 optim.update(y * width + x, val);
1033 }
1034
1035 //update strata counts
1036 indices.updateStrataCounts(val);
1037
1038 //update existing sampled strata
1039 if (alreadySampled) {
1040 existingSamples[val].push_back(existing.getPoint(index.x, index.y));
1041 }
1042
1043 //add val to stored indices
1044 if (accessible && !alreadySampled) {
1045 indices.updateFirstXIndexesVector(val, index);
1046
1047 if (rand.next()) {
1048 indices.updateIndexesVector(val, index);
1049 }
1050 }
1051 }
1052
1053 fwyi += width;
1054 if (fwyi == width * fw.wrow) {
1055 fwyi = 0;
1056 }
1057 }
1058 }
1059
1060 VSIFree(band.p_buffer);
1061 if (access.used) {
1062 VSIFree(access.band.p_buffer);
1063 }
1064
1065 if (optim.used) {
1066 weights = optim.getAllocationPercentages();
1067 }
1068 std::vector<int64_t> strataSampleCounts = calculateAllocation(
1069 numSamples,
1070 allocation,
1071 indices.getStrataCounts(),
1072 weights,
1073 indices.getNumDataPixels()
1074 );
1075
1076 return strataSampleCounts;
1077}
1078
1158std::tuple<std::vector<std::vector<double>>, vector::GDALVectorWrapper *, size_t>
1160 raster::GDALRasterWrapper *p_raster,
1161 int bandNum,
1162 int64_t numSamples,
1163 int64_t numStrata,
1164 std::string allocation,
1165 std::vector<double> weights,
1166 raster::GDALRasterWrapper *p_mraster,
1167 int mrastBandNum,
1168 std::string method,
1169 int wrow,
1170 int wcol,
1171 double mindist,
1172 vector::GDALVectorWrapper *p_existing,
1173 bool force,
1174 vector::GDALVectorWrapper *p_access,
1175 std::string layerName,
1176 double buffInner,
1177 double buffOuter,
1178 std::vector<std::pair<std::string, int>> mapStratMapping,
1179 bool plot,
1180 std::string filename,
1181 std::string tempFolder)
1182{
1183 GDALAllRegister();
1184
1185 double mindist_sq = mindist * mindist;
1186 bool useMindist = mindist != 0;
1187 int width = p_raster->getWidth();
1188 int height = p_raster->getHeight();
1189 double *GT = p_raster->getGeotransform();
1190 bool mapped = mapStratMapping.size() != 0;
1191
1192 std::mutex bandMutex;
1193 std::mutex rngMutex;
1194 std::mutex accessMutex;
1195
1196 //step 1: get raster band
1198
1199 band.p_band = p_raster->getRasterBand(bandNum);
1200 band.type = p_raster->getRasterBandType(bandNum);
1201 band.size = p_raster->getRasterBandTypeSize(bandNum);
1202 band.p_buffer = nullptr;
1203 band.nan = band.p_band->GetNoDataValue();
1204 band.p_mutex = &bandMutex;
1205 band.p_band->GetBlockSize(&band.xBlockSize, &band.yBlockSize);
1206
1208
1209 //create output dataset before doing anything which will take a long time in case of failure.
1210 GDALDriver *p_driver = GetGDALDriverManager()->GetDriverByName("MEM");
1211 if (!p_driver) {
1212 throw std::runtime_error("unable to create output sample dataset driver.");
1213 }
1214 GDALDataset *p_samples = p_driver->Create("", 0, 0, 0, GDT_Unknown, nullptr);
1215 if (!p_samples) {
1216 throw std::runtime_error("unable to create output dataset with driver.");
1217 }
1218
1219 vector::GDALVectorWrapper *p_wrapper = new vector::GDALVectorWrapper(p_samples, std::string(p_raster->getDataset()->GetProjectionRef()));
1220 OGRLayer *p_layer = p_samples->CreateLayer("samples", p_wrapper->getSRS(), wkbPoint, nullptr);
1221 if (!p_layer) {
1222 throw std::runtime_error("unable to create output dataset layer.");
1223 }
1224
1225 if (!mapped) {
1226 OGRFieldDefn strataField(band.p_band->GetDescription(), OFTInteger);
1227 OGRErr err = p_layer->CreateField(&strataField);
1228 if (err) {
1229 throw std::runtime_error("cannot create field for strata name.");
1230 }
1231 }
1232 else {
1233 for (size_t i = 0; i < mapStratMapping.size(); i++) {
1234 OGRFieldDefn strataField(mapStratMapping[i].first.c_str(), OFTInteger);
1235 OGRErr err = p_layer->CreateField(&strataField);
1236 if (err) {
1237 throw std::runtime_error("cannot create create field for strata name.");
1238 }
1239 }
1240 }
1241
1243 p_access,
1244 p_raster,
1245 layerName,
1246 buffInner,
1247 buffOuter,
1248 true,
1249 tempFolder,
1250 band.xBlockSize,
1251 band.yBlockSize
1252 );
1253
1254 std::vector<double> xCoords, yCoords;
1255 std::vector<std::vector<OGRPoint>> existingSamples(numStrata);
1257 p_existing,
1258 p_raster,
1259 GT,
1260 width,
1261 p_layer,
1262 false,
1263 xCoords,
1264 yCoords,
1265 false
1266 );
1267
1268 //fast random number generator using xoshiro256++
1269 //https://vigna.di.unimi.it/ftp/papers/ScrambledLinear.pdf
1270 xso::xoshiro_4x64_plus rng;
1271 uint64_t multiplier = helper::getProbabilityMultiplier(
1272 width,
1273 height,
1274 p_raster->getPixelWidth(),
1275 p_raster->getPixelHeight(),
1276 8,
1277 numSamples,
1278 useMindist,
1279 access.area
1280 );
1281 uint64_t queinnecMultiplier = helper::getProbabilityMultiplier(
1282 width,
1283 height,
1284 p_raster->getPixelWidth(),
1285 p_raster->getPixelHeight(),
1286 64,
1287 numSamples,
1288 useMindist,
1289 access.area
1290 );
1291
1292 //normal indices used with both methods, queinnec indices used only with queinnec method
1293 IndexStorageVectors indices(numStrata, 10000);
1294 IndexStorageVectors queinnecIndices(numStrata, 10000);
1295
1296 FocalWindow fw(wrow, wcol, width);
1297
1298 OptimAllocationDataManager optim(p_mraster, mrastBandNum, allocation);
1299
1300 std::vector<int64_t> strataSampleCounts;
1301 if (method == "random") {
1302 switch (band.type) {
1303 case GDT_Int8:
1304 strataSampleCounts = processBlocksStratRandom<int8_t>(numSamples, numStrata, band, access,
1305 existing, indices, existingSamples,
1306 multiplier, rng, allocation, optim,
1307 weights, width, height);
1308 break;
1309 case GDT_Int16:
1310 strataSampleCounts = processBlocksStratRandom<int16_t>(numSamples, numStrata, band, access,
1311 existing, indices, existingSamples,
1312 multiplier, rng, allocation, optim,
1313 weights, width, height);
1314 break;
1315 default:
1316 strataSampleCounts = processBlocksStratRandom<int32_t>(numSamples, numStrata, band, access,
1317 existing, indices, existingSamples,
1318 multiplier, rng, allocation, optim,
1319 weights, width, height);
1320 break;
1321 }
1322 }
1323 else { //method == queinnec
1324 switch (band.type) {
1325 case GDT_Int8:
1326 strataSampleCounts = processBlocksStratQueinnec<int8_t>(numSamples, numStrata, band, access, existing,
1327 indices, queinnecIndices, fw, existingSamples,
1328 multiplier, queinnecMultiplier, rng, allocation,
1329 optim, weights, width, height);
1330 break;
1331 case GDT_Int16:
1332 strataSampleCounts = processBlocksStratQueinnec<int16_t>(numSamples, numStrata, band, access, existing,
1333 indices, queinnecIndices, fw, existingSamples,
1334 multiplier, queinnecMultiplier, rng, allocation,
1335 optim, weights, width, height);
1336 break;
1337 default:
1338 strataSampleCounts = processBlocksStratQueinnec<int32_t>(numSamples, numStrata, band, access, existing,
1339 indices, queinnecIndices, fw, existingSamples,
1340 multiplier, queinnecMultiplier, rng, allocation,
1341 optim, weights, width, height);
1342 break;
1343 }
1344 }
1345
1346 std::vector<std::vector<helper::Index> *> strataIndexVectors;
1347 std::vector<size_t> nextIndexes(numStrata, 0);
1348
1349 std::vector<bool> completedStrata(numStrata, false);
1350 std::vector<bool> completedStrataQueinnec(numStrata, false);
1351 std::vector<int64_t> samplesAddedPerStrata(numStrata, 0);
1352 int64_t numCompletedStrata = 0;
1353 int64_t numCompletedStrataQueinnec = 0;
1354 int64_t curStrata = 0;
1355 int64_t addedSamples = 0;
1356
1357 //the following looks complicated. The reason for all of the fields, vectors, and pointers
1358 //is to lower the ammount of times Fields and vectors are copied or created. Fields are
1359 //used to contain metadata on each sample, for example whether that sample is part of
1360 //an existing sample plot network, or the strata from which that field originated.
1361 //
1362 //PROBLEMS:
1363 //One option, would be to create a new Field or a vector of Fields EVERY iteration when a point
1364 //is added. Obviously, this incurs a large overhead.
1365 //
1366 //Another option would be to do without the pointers and have a set vector of fields or a set
1367 //vector of field vectors. However, whenever a vector is indexed it returns a copy of the element.
1368 //So, rather than creating a new Field or vector of fields, it would copy an existing field or
1369 //vector of fields EVERY iteration when a point is added. Obviously, this also incurs a large
1370 //overhead.
1371 //
1372 //SOLUTION:
1373 //in order to get around these problems, ONLY the exact fields which will be used are ever
1374 //created, which includes the 'fieldExistingTrue', 'fieldExistingFalse', and 'strataFields'
1375 //variables.
1376 //
1377 //THEN, since we may need to add multiple fields for each point, in addition to those fields
1378 //we also create every combination of fields that would ever be required in the form of
1379 //std::vector<Field *> (so the field is not copied). This is the 'fieldVectors' vector which
1380 //has the type std::vector<std::vector<Field *>>.
1381 //
1382 //Essentially: 'fieldExistingTrue', 'fieldExistingFalse', and 'strataFields' store the ONLY
1383 //copies of the fields (and are accessed via pointers.) 'fieldVectors' stores all the COMBINATIONS
1384 //of (pointers to) fields that might be relevant to a pixel (and are accessed via pointers.)
1385 //
1386 //Finally, to make the COMBINATIONS of fields easily indexible without copying, there are
1387 //additional vectors storing POINTERS to combinations within 'fieldVectors'. These are
1388 //'fieldVectorPointersExistingTrue', 'fieldVectorPointersExistingFalse', and 'fieldVectorPointersNoExisting',
1389 //and have the type std::vector<std::vector<Field *> *> in order to point to a particular
1390 //entry in the 'fieldVectors' vector.
1391 helper::Field fieldExistingTrue("existing", 1);
1392 helper::Field fieldExistingFalse("existing", 0);
1393 std::vector<helper::Field> strataFields(mapped ? 0 : numStrata);
1394 std::vector<std::vector<helper::Field>> mappedStrataFields(mapped ? mapStratMapping.size() : 0);
1395 if (!mapped) {
1396 strataFields.resize(numStrata);
1397 for (int i = 0; i < numStrata; i++) {
1398 strataFields[i].fname = std::string(band.p_band->GetDescription());
1399 strataFields[i].fval = i;
1400 }
1401 }
1402 else { //mapped
1403 for (size_t i = 0; i < mapStratMapping.size(); i++) {
1404 mappedStrataFields[i].resize(mapStratMapping[i].second);
1405 for (int strat = 0; strat < mapStratMapping[i].second; strat++) {
1406 mappedStrataFields[i][strat].fname = mapStratMapping[i].first;
1407 mappedStrataFields[i][strat].fval = strat;
1408 }
1409 }
1410 }
1411
1412 int fieldVectorCount = existing.used ? numStrata * 2 : numStrata;
1413 std::vector<std::vector<helper::Field *>> fieldVectors(fieldVectorCount);
1414
1415 int fvi = 0; //field vectors index
1416 std::vector<std::vector<helper::Field *> *> fieldVectorPointersExistingTrue(existing.used ? numStrata : 0);
1417 std::vector<std::vector<helper::Field *> *> fieldVectorPointersExistingFalse(existing.used ? numStrata : 0);
1418 std::vector<std::vector<helper::Field *> *> fieldVectorPointersNoExisting(existing.used ? 0 : numStrata);
1419
1420 if (existing.used && !mapped) {
1421 for (int strata = 0; strata < numStrata; strata++) {
1422 //resize entries for both existing==true and existing==false
1423 fieldVectors[fvi].resize(2);
1424 fieldVectors[fvi + 1].resize(2);
1425
1426 //update field vector pointers for strata and existing
1427 fieldVectors[fvi][0] = &fieldExistingTrue;
1428 fieldVectors[fvi + 1][0] = &fieldExistingFalse;
1429 fieldVectors[fvi][1] = strataFields.data() + strata;
1430 fieldVectors[fvi + 1][1] = strataFields.data() + strata;
1431
1432 //update pointers to field vectors
1433 fieldVectorPointersExistingTrue[strata] = fieldVectors.data() + fvi;
1434 fieldVectorPointersExistingFalse[strata] = fieldVectors.data() + fvi + 1;
1435
1436 //increment field vector index
1437 fvi += 2;
1438 }
1439 }
1440 else if (existing.used && mapped) {
1441 for (int i = 0; i < numStrata; i++) {
1442 int strata = i;
1443
1444 //resize entries for both existing==true and existing==false
1445 fieldVectors[fvi].resize(mapStratMapping.size() + 1);
1446 fieldVectors[fvi + 1].resize(mapStratMapping.size() + 1);
1447
1448 //update field vector pointers for strata and existing
1449 for (size_t j = 0; j < mapStratMapping.size(); j++) {
1450 int bandStrata = strata % mapStratMapping[j].second;
1451 fieldVectors[fvi][j] = mappedStrataFields[j].data() + bandStrata;
1452 fieldVectors[fvi + 1][j] = mappedStrataFields[j].data() + bandStrata;
1453 strata = strata / mapStratMapping[j].second;
1454 }
1455 fieldVectors[fvi][mapStratMapping.size()] = &fieldExistingTrue;
1456 fieldVectors[fvi + 1][mapStratMapping.size()] = &fieldExistingFalse;
1457
1458 //update pointers to field vectors
1459 fieldVectorPointersExistingTrue[i] = fieldVectors.data() + fvi;
1460 fieldVectorPointersExistingFalse[i] = fieldVectors.data() + fvi + 1;
1461
1462 //increment field vector index
1463 fvi += 2;
1464 }
1465 }
1466 else if (!existing.used && !mapped) {
1467 for (int strata = 0; strata < numStrata; strata++) {
1468 fieldVectors[fvi].resize(1);
1469 fieldVectors[fvi][0] = strataFields.data() + strata;
1470 fieldVectorPointersNoExisting[strata] = fieldVectors.data() + fvi;
1471
1472 fvi++;
1473 }
1474 }
1475 else {
1476 for (int i = 0; i < numStrata; i++) {
1477 int strata = i;
1478
1479 fieldVectors[fvi].resize(mapStratMapping.size());
1480 for (size_t j = 0; j < mapStratMapping.size(); j++) {
1481 int bandStrata = strata % mapStratMapping[j].second;
1482 fieldVectors[fvi][j] = mappedStrataFields[j].data() + bandStrata;
1483 strata = strata / mapStratMapping[j].second;
1484 }
1485 fieldVectorPointersNoExisting[i] = fieldVectors.data() + fvi;
1486 fvi++;
1487 }
1488 }
1489
1490 //add existing sample plots
1491 helper::NeighborMap neighbor_map;
1492 if (existing.used) {
1493 if (force) {
1494 //if force is used, add all samples no matter what
1495 for (int i = 0; i < numStrata; i++) {
1496 std::vector<OGRPoint> samples = existingSamples[i];
1497 for (const OGRPoint& point : samples) {
1498 helper::addPoint(&point, p_layer, fieldVectorPointersExistingTrue[i]);
1499
1500 addedSamples++;
1501 samplesAddedPerStrata[i]++;
1502
1503 if (plot) {
1504 xCoords.push_back(point.getX());
1505 yCoords.push_back(point.getY());
1506 }
1507 }
1508
1509 if (samplesAddedPerStrata[i] >= strataSampleCounts[i]) {
1510 numCompletedStrata++;
1511 numCompletedStrataQueinnec++;
1512 completedStrata[i] = true;
1513 completedStrataQueinnec[i] = true;
1514 }
1515 }
1516 }
1517 else { //force == false
1518 for (size_t i = 0; i < numStrata; i++) {
1519 std::vector<OGRPoint> samples = existingSamples[i];
1520 std::shuffle(samples.begin(), samples.end(), rng);
1521
1522 size_t j = 0;
1523 while (samplesAddedPerStrata[i] < strataSampleCounts[i] && j < samples.size()) {
1524 OGRPoint point = samples[j];
1525 double x = point.getX();
1526 double y = point.getY();
1527 bool valid = true;
1528
1529 if (useMindist) {
1530 valid = helper::is_valid_sample(x, y, neighbor_map, mindist, mindist_sq);
1531 }
1532
1533 if (valid) {
1534 helper::addPoint(&point, p_layer, fieldVectorPointersExistingTrue[i]);
1535
1536 addedSamples++;
1537 samplesAddedPerStrata[i]++;
1538
1539 if (plot) {
1540 xCoords.push_back(point.getX());
1541 yCoords.push_back(point.getY());
1542 }
1543 }
1544
1545 j++;
1546 }
1547
1548 if (samplesAddedPerStrata[i] == strataSampleCounts[i]) {
1549 numCompletedStrata++;
1550 numCompletedStrataQueinnec++;
1551 completedStrata[i] = true;
1552 completedStrataQueinnec[i] = true;
1553 }
1554 }
1555 }
1556 }
1557
1558 if (method == "Queinnec") {
1559 strataIndexVectors = queinnecIndices.getStrataIndexVectors(samplesAddedPerStrata, strataSampleCounts, rng);
1560
1561 int64_t curStrata = 0;
1562 while (numCompletedStrataQueinnec < numStrata && addedSamples < numSamples) {
1563 if (curStrata == numStrata) {
1564 curStrata = 0;
1565 }
1566 if (completedStrataQueinnec[curStrata]) {
1567 curStrata++;
1568 continue;
1569 }
1570
1571 int64_t sampleCount = strataSampleCounts[curStrata];
1572 int64_t samplesAdded = samplesAddedPerStrata[curStrata];
1573 if (samplesAdded == sampleCount) {
1574 numCompletedStrataQueinnec++;
1575 completedStrataQueinnec[curStrata] = true;
1576 numCompletedStrata++;
1577 completedStrata[curStrata] = true;
1578 curStrata++;
1579 continue;
1580 }
1581
1582 std::vector<helper::Index> *strataIndexes = strataIndexVectors[curStrata];
1583 size_t nextIndex = nextIndexes[curStrata];
1584 if (strataIndexes->size() == nextIndex) {
1585 numCompletedStrataQueinnec++;
1586 completedStrataQueinnec[curStrata] = true;
1587 curStrata++;
1588 continue;
1589 }
1590
1591 helper::Index index = strataIndexes->at(nextIndex);
1592 nextIndexes[curStrata]++;
1593
1594 bool valid = true;
1595 const auto [x, y] = helper::sample_to_point(GT, index);
1596 OGRPoint newPoint = OGRPoint(x, y);
1597
1598 if (useMindist) {
1599 valid = helper::is_valid_sample(x, y, neighbor_map, mindist, mindist_sq);
1600 }
1601
1602 if (valid) {
1603 existing.used ?
1604 helper::addPoint(&newPoint, p_layer, fieldVectorPointersExistingFalse[curStrata]) :
1605 helper::addPoint(&newPoint, p_layer, fieldVectorPointersNoExisting[curStrata]);
1606
1607 addedSamples++;
1608 samplesAddedPerStrata[curStrata]++;
1609
1610 if (plot) {
1611 xCoords.push_back(x);
1612 yCoords.push_back(y);
1613 }
1614 }
1615
1616 curStrata++;
1617 }
1618 }
1619
1620 strataIndexVectors = indices.getStrataIndexVectors(samplesAddedPerStrata, strataSampleCounts, rng);
1621 for (int64_t i = 0; i < numStrata; i++) {
1622 //set next indexes to 0 because the vectors are different than the queinnec vectors
1623 nextIndexes[i] = 0;
1624 }
1625 curStrata = 0;
1626
1627 //step 8: generate coordinate points for each sample index.
1628 while (numCompletedStrata < numStrata && addedSamples < numSamples) {
1629 if (curStrata == numStrata) {
1630 curStrata = 0;
1631 }
1632 if (completedStrata[curStrata]) {
1633 curStrata++;
1634 continue;
1635 }
1636
1637 int64_t sampleCount = strataSampleCounts[curStrata];
1638 int64_t samplesAdded = samplesAddedPerStrata[curStrata];
1639 if (samplesAdded == sampleCount) {
1640 numCompletedStrata++;
1641 completedStrata[curStrata] = true;
1642 curStrata++;
1643 continue;
1644 }
1645
1646 std::vector<helper::Index> *strataIndexes = strataIndexVectors[curStrata];
1647 size_t nextIndex = nextIndexes[curStrata];
1648 if (strataIndexes->size() == nextIndex) {
1649 numCompletedStrata++;
1650 completedStrata[curStrata] = true;
1651 curStrata++;
1652 continue;
1653 }
1654
1655 helper::Index index = strataIndexes->at(nextIndex);
1656 nextIndexes[curStrata]++;
1657
1658 bool valid = true;
1659 const auto [x, y] = helper::sample_to_point(GT, index);
1660 OGRPoint newPoint = OGRPoint(x, y);
1661
1662 if (useMindist) {
1663 valid = helper::is_valid_sample(x, y, neighbor_map, mindist, mindist_sq);
1664 }
1665
1666 if (valid) {
1667 existing.used ?
1668 helper::addPoint(&newPoint, p_layer, fieldVectorPointersExistingFalse[curStrata]) :
1669 helper::addPoint(&newPoint, p_layer, fieldVectorPointersNoExisting[curStrata]);
1670
1671
1672 addedSamples++;
1673 samplesAddedPerStrata[curStrata]++;
1674
1675 if (plot) {
1676 xCoords.push_back(x);
1677 yCoords.push_back(y);
1678 }
1679 }
1680
1681 curStrata++;
1682 }
1683
1684 //step 10: write vector if filename is not "".
1685 if (filename != "") {
1686 try {
1687 p_wrapper->write(filename);
1688 }
1689 catch (const std::exception& e) {
1690 std::cout << "Exception thrown trying to write file: " << e.what() << std::endl;
1691 }
1692 }
1693
1694 size_t actualSampleCount = static_cast<size_t>(p_layer->GetFeatureCount());
1695 return {{xCoords, yCoords}, p_wrapper, actualSampleCount};
1696}
1697
1698} //namespace strat
1699} //namespace sgs
Definition helper.h:976
void calculateRandValues(void)
Definition helper.h:1019
bool next(void)
Definition helper.h:1034
Definition raster.h:57
GDALDataset * getDataset()
Definition raster.h:429
int getWidth()
Definition raster.h:467
size_t getRasterBandTypeSize(int band)
Definition raster.h:735
double * getGeotransform()
Definition raster.h:590
GDALDataType getRasterBandType(int band)
Definition raster.h:724
int getHeight()
Definition raster.h:476
GDALRasterBand * getRasterBand(int band)
Definition raster.h:696
double getPixelWidth()
Definition raster.h:555
double getPixelHeight()
Definition raster.h:565
Definition strat.h:242
void updateFirstXIndexesVector(int strata, helper::Index &index)
Definition strat.h:310
std::vector< int64_t > getStrataCounts(void)
Definition strat.h:376
IndexStorageVectors(int64_t numStrata, int64_t x)
Definition strat.h:263
void updateIndexesVector(int strata, helper::Index &index)
Definition strat.h:297
int64_t getNumDataPixels(void)
Definition strat.h:386
std::vector< std::vector< helper::Index > * > getStrataIndexVectors(std::vector< int64_t > existing, std::vector< int64_t > strataSampleCounts, xso::xoshiro_4x64_plus &rng)
Definition strat.h:341
void updateStrataCounts(int strata)
Definition strat.h:285
Definition vector.h:46
OGRSpatialReference * getSRS(void)
Definition vector.h:457
void write(std::string filename)
Definition vector.h:397
boost::unordered::unordered_flat_map< std::pair< int, int >, std::vector< std::pair< double, double > >, PointHash > NeighborMap
Definition helper.h:1061
uint64_t getProbabilityMultiplier(double width, double height, double pixelWidth, double pixelHeight, int startMult, int numSamples, bool useMindist, double accessibleArea)
Definition helper.h:940
void rasterBandIO(RasterBandMetaData &band, void *p_buffer, int xBlockSize, int yBlockSize, int xBlock, int yBlock, int xValid, int yValid, bool read, bool threaded=true)
Definition helper.h:643
std::pair< double, double > sample_to_point(double *GT, Index &index)
Definition helper.h:1108
T getPixelValueDependingOnType(GDALDataType type, void *p_data, size_t index)
Definition helper.h:173
void printTypeWarningsForInt32Conversion(GDALDataType type)
Definition helper.h:251
bool is_valid_sample(double x, double y, NeighborMap &neighbor_map, float mindist, float mindist_sq)
Definition helper.h:1072
void addPoint(OGRPoint *p_point, OGRLayer *p_layer)
Definition helper.h:700
std::vector< int64_t > processBlocksStratRandom(int numSamples, int numStrata, helper::RasterBandMetaData &band, access::Access &access, existing::Existing &existing, IndexStorageVectors &indices, std::vector< std::vector< OGRPoint > > &existingSamples, uint64_t multiplier, xso::xoshiro_4x64_plus &rng, std::string allocation, OptimAllocationDataManager &optim, std::vector< double > weights, int width, int height)
Definition strat.h:440
std::vector< int64_t > processBlocksStratQueinnec(int numSamples, int numStrata, helper::RasterBandMetaData &band, access::Access &access, existing::Existing &existing, IndexStorageVectors &indices, IndexStorageVectors &queinnecIndices, FocalWindow &fw, std::vector< std::vector< OGRPoint > > &existingSamples, uint64_t multiplier, uint64_t queinnecMultiplier, xso::xoshiro_4x64_plus &rng, std::string allocation, OptimAllocationDataManager &optim, std::vector< double > weights, int width, int height)
Definition strat.h:775
std::vector< int64_t > calculateAllocation(int64_t numSamples, std::string allocation, std::vector< int64_t > strataCounts, std::vector< double > weights, int64_t numPixels)
Definition strat.h:41
std::tuple< std::vector< std::vector< double > >, vector::GDALVectorWrapper *, size_t > strat(raster::GDALRasterWrapper *p_raster, int bandNum, int64_t numSamples, int64_t numStrata, std::string allocation, std::vector< double > weights, raster::GDALRasterWrapper *p_mraster, int mrastBandNum, std::string method, int wrow, int wcol, double mindist, vector::GDALVectorWrapper *p_existing, bool force, vector::GDALVectorWrapper *p_access, std::string layerName, double buffInner, double buffOuter, std::vector< std::pair< std::string, int > > mapStratMapping, bool plot, std::string filename, std::string tempFolder)
Definition strat.h:1159
Definition access.h:23
Definition existing.h:27
Definition pca.h:23
Definition access.h:30
Definition existing.h:38
Definition helper.h:46
Definition helper.h:37
int x
Definition helper.h:38
int y
Definition helper.h:39
Definition helper.h:87
int xBlockSize
Definition helper.h:94
std::mutex * p_mutex
Definition helper.h:96
void * p_buffer
Definition helper.h:89
int yBlockSize
Definition helper.h:95
size_t size
Definition helper.h:91
GDALDataType type
Definition helper.h:90
double nan
Definition helper.h:93
GDALRasterBand * p_band
Definition helper.h:88
Definition strat.h:604
int hpad
Definition strat.h:607
int vpad
Definition strat.h:607
std::vector< bool > valid
Definition strat.h:609
int width
Definition strat.h:606
int wcol
Definition strat.h:605
void reset(int row)
Definition strat.h:639
FocalWindow(int wrow, int wcol, int width)
Definition strat.h:620
bool check(int x, int y)
Definition strat.h:671
std::vector< bool > m
Definition strat.h:608
int wrow
Definition strat.h:605
void init(int numStrata, int xBlockSize, int yBlockSize)
Definition strat.h:157
std::vector< double > getAllocationPercentages(void)
Definition strat.h:205
OptimAllocationDataManager(raster::GDALRasterWrapper *p_raster, int bandNum, std::string allocation)
Definition strat.h:123
~OptimAllocationDataManager()
Definition strat.h:141
std::vector< helper::Variance > variances
Definition strat.h:111
helper::RasterBandMetaData band
Definition strat.h:110
bool used
Definition strat.h:112
void readNewBlock(int xBlockSize, int yBlockSize, int xBlock, int yBlock, int xValid, int yValid)
Definition strat.h:174
void update(int index, int strata)
Definition strat.h:187