715 std::map<
int, std::vector<double>> userProbabilites,
717 std::string filename,
718 std::string tempFolder,
721 std::map<std::string, std::string> driverOptions,
729 std::string projection = std::string(p_raster->
getDataset()->GetProjectionRef());
731 GDALDataset *p_dataset =
nullptr;
733 int bandCount = userProbabilites.size();
734 std::vector<std::vector<double>> probabilities;
735 std::vector<std::string> bandNames = p_raster->
getBands();
737 std::vector<helper::RasterBandMetaData> dataBands(bandCount);
738 std::vector<helper::RasterBandMetaData> stratBands(bandCount +
map);
739 std::vector<helper::VRTBandDatasetInfo> VRTBandInfo;
741 bool isMEMDataset = !largeRaster && filename ==
"";
742 bool isVRTDataset = largeRaster && filename ==
"";
744 std::mutex dataBandMutex;
745 std::mutex stratBandMutex;
746 std::vector<std::mutex> stratBandMutexes(isVRTDataset * (bandCount +
map));
749 if (isMEMDataset || isVRTDataset) {
750 driver = isMEMDataset ?
"MEM" :
"VRT";
754 std::filesystem::path filepath = filename;
755 std::string extension = filepath.extension().string();
757 if (extension ==
".tif") {
761 throw std::runtime_error(
"sgs only supports .tif files right now");
766 GDALDataType stratPixelType = GDT_Int8;
767 size_t stratPixelSize = 1;
769 for (
auto const& [key, val] : userProbabilites) {
775 p_dataBand->
p_band = p_band;
779 p_dataBand->
nan = p_band->GetNoDataValue();
780 p_dataBand->
p_mutex = &dataBandMutex;
784 probabilities.push_back(val);
787 size_t maxStrata = val.size() + 1;
789 p_stratBand->
name =
"strat_" + bandNames[key];
792 p_stratBand->
p_mutex = isVRTDataset ? &stratBandMutexes[band] : &stratBandMutex;
798 else if (isVRTDataset) {
802 if (stratPixelSize < p_stratBand->size) {
803 stratPixelSize = p_stratBand->
size;
804 stratPixelType = p_stratBand->
type;
812 std::vector<size_t> multipliers(probabilities.size(), 1);
815 for (
int i = 0; i < bandCount - 1; i++) {
816 multipliers[i + 1] = multipliers[i] * (probabilities[i].size() + 1);
821 size_t maxStrata = multipliers.back() * (probabilities.back().size() + 1);
823 p_stratBand->
name =
"strat_map";
824 p_stratBand->
xBlockSize = dataBands[0].xBlockSize;
825 p_stratBand->
yBlockSize = dataBands[0].yBlockSize;
826 p_stratBand->
p_mutex = isVRTDataset ? &stratBandMutexes.back() : &stratBandMutex;
832 else if (isVRTDataset) {
836 if (stratPixelSize < p_stratBand->size) {
837 stratPixelSize = p_stratBand->
size;
838 stratPixelType = p_stratBand->
type;
844 if (!isMEMDataset && !isVRTDataset) {
845 bool useTiles = stratBands[0].xBlockSize != width &&
846 stratBands[0].yBlockSize != height;
848 for (
size_t band = 0; band < stratBands.size(); band++) {
849 stratBands[band].size = stratPixelSize;
850 stratBands[band].type = stratPixelType;
851 stratBands[band].p_buffer = !largeRaster ? VSIMalloc3(height, width, stratPixelSize) :
nullptr;
868 std::vector<std::vector<double>>
quantiles(probabilities.size());
870 pybind11::gil_scoped_acquire acquire;
871 boost::asio::thread_pool pool(threadCount);
874 std::vector<std::mutex> mutexes(
map ? 1 : bandCount);
875 std::vector<std::condition_variable> cvs(
map ? 1 : bandCount);
876 bool *quantilesCalculated =
reinterpret_cast<bool *
>(VSIMalloc2(bandCount,
sizeof(
bool)));
879 for (
int i = 0; i < bandCount; i++) {
881 quantiles[i].resize(probabilities[i].size());
882 quantilesCalculated[i] =
false;
883 if (band.
type != GDT_Float64) {
887 std::ref(probabilities[i]),
889 std::ref(mutexes[
map ? 0 : i]),
890 std::ref(cvs[
map ? 0 : i]),
891 std::ref(quantilesCalculated[i]),
892 static_cast<double>(eps)
899 std::ref(probabilities[i]),
901 std::ref(mutexes[i]),
903 std::ref(quantilesCalculated[i]),
904 static_cast<double>(eps)
914 std::unique_lock lock(mutexes[0]);
915 bool allBandsQuantilesCalculated =
true;
916 for (
int i = 0; i < bandCount; i++) {
917 allBandsQuantilesCalculated &= quantilesCalculated[i];
920 while (!allBandsQuantilesCalculated) {
922 allBandsQuantilesCalculated =
true;
923 for (
int i = 0; i < bandCount; i++) {
924 allBandsQuantilesCalculated &= quantilesCalculated[i];
929 int xBlockSize = dataBands[0].xBlockSize;
930 int yBlockSize = dataBands[0].yBlockSize;
932 int xBlocks = (p_raster->
getWidth() + xBlockSize - 1) / xBlockSize;
933 int yBlocks = (p_raster->
getHeight() + yBlockSize - 1) / yBlockSize;
934 int chunkSize = yBlocks / threadCount;
936 for (
int yBlockStart = 0; yBlockStart < yBlocks; yBlockStart += chunkSize) {
937 int yBlockEnd = std::min(yBlockStart + chunkSize, yBlocks);
939 boost::asio::post(pool, [
951 std::vector<void *> dataBuffers(dataBands.size());
952 std::vector<void *> stratBuffers(stratBands.size());
953 for (
size_t band = 0; band < dataBuffers.size(); band++) {
954 dataBuffers[band] = VSIMalloc3(xBlockSize, yBlockSize, dataBands[band].size);
955 stratBuffers[band] = VSIMalloc3(xBlockSize, yBlockSize, stratBands[band].size);
957 stratBuffers.back() = VSIMalloc3(xBlockSize, yBlockSize, stratBands.back().size);
959 for (
int yBlock = yBlockStart; yBlock < yBlockEnd; yBlock++) {
960 for (
int xBlock = 0; xBlock < xBlocks; xBlock++) {
962 dataBands[0].p_mutex->lock();
963 dataBands[0].p_band->GetActualBlockSize(xBlock, yBlock, &xValid, &yValid);
964 dataBands[0].p_mutex->unlock();
967 for (
size_t band = 0; band < static_cast<size_t>(bandCount); band++) {
982 for (
int y = 0; y < yValid; y++) {
983 size_t index =
static_cast<size_t>(y * xBlockSize);
984 for (
int x = 0; x < xValid; x++) {
988 for (
size_t band = 0; band < static_cast<size_t>(bandCount); band++) {
1003 stratBands.back().type,
1004 stratBuffers.back(),
1015 for (
size_t band = 0; band <= static_cast<size_t>(bandCount); band++) {
1031 for (
size_t band = 0; band < dataBuffers.size(); band++) {
1032 VSIFree(dataBuffers[band]);
1033 VSIFree(stratBuffers[band]);
1035 VSIFree(stratBuffers.back());
1040 for (
size_t band = 0; band < static_cast<size_t>(bandCount); band++) {
1047 int xBlocks = (p_raster->
getWidth() + xBlockSize - 1) / xBlockSize;
1048 int yBlocks = (p_raster->
getHeight() + yBlockSize - 1) / yBlockSize;
1049 int chunkSize = yBlocks / threadCount;
1051 for (
int yBlockStart = 0; yBlockStart < yBlocks; yBlockStart += chunkSize) {
1052 int yBlockEnd = std::min(yBlocks, yBlockStart + chunkSize);
1053 std::vector<double> *p_quantiles = &
quantiles[band];
1054 std::mutex *p_mutex = &mutexes[band];
1055 std::condition_variable *p_cv = &cvs[band];
1056 bool *p_calculated = &quantilesCalculated[band];
1058 boost::asio::post(pool, [
1071 std::unique_lock lock(*p_mutex);
1073 if (!(*p_calculated)) {
1077 void *p_data = VSIMalloc3(xBlockSize, yBlockSize, p_dataBand->
size);
1078 void *p_strat = VSIMalloc3(xBlockSize, yBlockSize, p_stratBand->
size);
1081 for (
int yBlock = yBlockStart; yBlock < yBlockEnd; yBlock++) {
1082 for (
int xBlock = 0; xBlock < xBlocks; xBlock++) {
1084 p_dataBand->
p_band->GetActualBlockSize(xBlock, yBlock, &xValid, &yValid);
1085 p_dataBand->
p_mutex->unlock();
1101 for (
int y = 0; y < yValid; y++) {
1102 size_t index =
static_cast<size_t>(y * xBlockSize);
1103 for (
int x = 0; x < xValid; x++) {
1104 processPixel(index, p_data, p_dataBand, p_strat, p_stratBand, *p_quantiles);
1131 VSIFree(quantilesCalculated);
1132 pybind11::gil_scoped_release release;
1136 for (
int i = 0; i < bandCount; i++) {
1138 quantiles[i].resize(probabilities[i].size());
1139 (band.
type != GDT_Float64) ?
1144 size_t pixelCount =
static_cast<size_t>(p_raster->
getWidth()) *
static_cast<size_t>(p_raster->
getHeight());
1146 for (
size_t index = 0; index < pixelCount; index++) {
1147 bool mapNan =
false;
1148 size_t mapStrat = 0;
1150 for (
size_t band = 0; band < static_cast<size_t>(bandCount); band++) {
1154 dataBands[band].p_buffer,
1156 stratBands[band].p_buffer,
1165 stratBands.back().type,
1166 stratBands.back().p_buffer,
1174 for (
size_t band = 0; band < static_cast<size_t>(bandCount); band++) {
1175 for (
size_t i = 0; i < pixelCount; i++) {
1178 dataBands[band].p_buffer,
1180 stratBands[band].p_buffer,
1189 if (!isVRTDataset && !isMEMDataset) {
1191 for (
size_t band = 0; band < stratBands.size(); band++) {
1192 err = stratBands[band].p_band->RasterIO(
1198 stratBands[band].p_buffer,
1201 stratBands[band].type,
1206 throw std::runtime_error(
"error writing band to file.");
1215 for (
size_t band = 0; band < VRTBandInfo.size(); band++) {
1216 GDALClose(VRTBandInfo[band].p_dataset);
1222 std::vector<void *> buffers(stratBands.size());
1224 for (
size_t band = 0; band < stratBands.size(); band++) {
1225 buffers[band] = stratBands[band].p_buffer;
1229 std::unordered_map<std::string, std::vector<double>> quantileValues;
1230 for (
size_t i = 0; i < dataBands.size(); i++) {
1231 quantileValues.insert({std::string(dataBands[i].p_band->GetDescription()),
quantiles[i]});