Skip to content

Commit

Permalink
Add inverse distance weighting option to superob function (#1116)
Browse files Browse the repository at this point in the history
**Description:**

1. The superob function now incorporates the capability for inverse
distance weighted averaging. If optional parameters are provided when
calling the function, it conducts weighted averaging; otherwise, it
defaults to simple averaging.

3. The VIIRS converter has been enhanced to utilize this new
functionality. Weighted averaging is only used in the computation of
superobbed ObsValue and ObsError.

---------

Co-authored-by: ypwang19 <[email protected]>
  • Loading branch information
ypwang19 and ypwang19 authored May 21, 2024
1 parent 3796a8d commit 41493ad
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 28 deletions.
19 changes: 9 additions & 10 deletions utils/obsproc/Viirsaod2Ioda.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,8 @@ namespace gdasapp {
std::vector<std::vector<int>> mask_s;

if ( fullConfig_.has("binning") ) {
// deal with longitude when points cross the international date line
// Do superobbing
// Deal with longitude when points cross the international date line
float minLon = std::numeric_limits<float>::max();
float maxLon = std::numeric_limits<float>::min();

Expand All @@ -158,19 +159,17 @@ namespace gdasapp {
}
}


lat2d_s = gdasapp::superobutils::subsample2D(lat, mask, fullConfig_);
mask_s = gdasapp::superobutils::subsample2D(mask, mask, fullConfig_);
if (fullConfig_.has("binning.cressman radius")) {
// Weighted-average (cressman) does not work yet. Need to develop subsample2D_cressman
// function to superob.h or incorporate weighted average to subsample2D function.
// obsvalue_s = gdasapp::superobutils::subsample2D_cressman(obsvalue, lat, lon,
// lat2d_s, lon2d_s, mask, fullConfig_);
// obserror_s = gdasapp::superobutils::subsample2D_cressman(obserror, lat, lon,
// lat2d_s, lon2d_s, mask, fullConfig_);
obsvalue_s = gdasapp::superobutils::subsample2D(obsvalue, mask, fullConfig_);
obserror_s = gdasapp::superobutils::subsample2D(obserror, mask, fullConfig_);
// Weighted-average (cressman) superob
bool useCressman = true;
obsvalue_s = gdasapp::superobutils::subsample2D(obsvalue, mask, fullConfig_,
useCressman, lat, lon, lat2d_s, lon2d_s);
obserror_s = gdasapp::superobutils::subsample2D(obserror, mask, fullConfig_,
useCressman, lat, lon, lat2d_s, lon2d_s);
} else {
// Simple-average superob
obsvalue_s = gdasapp::superobutils::subsample2D(obsvalue, mask, fullConfig_);
obserror_s = gdasapp::superobutils::subsample2D(obserror, mask, fullConfig_);
}
Expand Down
90 changes: 72 additions & 18 deletions utils/obsproc/superob.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,26 @@
#include <string>
#include <vector>

#include "atlas/util/Earth.h"
#include "atlas/util/Geometry.h"
#include "atlas/util/Point.h"
#include "eckit/config/LocalConfiguration.h"



namespace gdasapp {
namespace superobutils {
// Function to perform subsampling/binning of gridded data with a given stride
template <typename T>
std::vector<std::vector<T>> subsample2D(const std::vector<std::vector<T>>& inputArray,
const std::vector<std::vector<int>>& mask,
const eckit::Configuration & fullConfig) {
const eckit::Configuration & fullConfig,
bool useCressman = false,
const std::vector<std::vector<T>>& inputlat = {},
const std::vector<std::vector<T>>& inputlon = {},
const std::vector<std::vector<T>>& targetlat = {},
const std::vector<std::vector<T>>& targetlon = {}
) {
// Get the binning configuration
int stride;
int minNumObs;
Expand All @@ -31,30 +42,73 @@ namespace gdasapp {
// Perform subsampling
T sum;
int count;
for (int i = 0; i < subsampledRows; ++i) {
for (int j = 0; j < subsampledCols; ++j) {
count = 0;
sum = static_cast<T>(0);
// Compute the average within the stride
for (int si = 0; si < stride; ++si) {
for (int sj = 0; sj < stride; ++sj) {
int row = i * stride + si;
int col = j * stride + sj;
if (row < numRows && col < numCols && mask[row][col] == 1) {
sum += inputArray[row][col];
count++;
if (!useCressman) {
for (int i = 0; i < subsampledRows; ++i) {
for (int j = 0; j < subsampledCols; ++j) {
count = 0;
sum = static_cast<T>(0);
// Compute the average within the stride
for (int si = 0; si < stride; ++si) {
for (int sj = 0; sj < stride; ++sj) {
int row = i * stride + si;
int col = j * stride + sj;
if (row < numRows && col < numCols && mask[row][col] == 1) {
sum += inputArray[row][col];
count++;
}
}
}

// Calculate the average and store it in the subsampled array
if ( count < minNumObs ) {
subsampled[i][j] = static_cast<T>(-9999);
} else {
subsampled[i][j] = sum / static_cast<T>(count);
}
}
}
} else {
// Apply Cressman interpolation if selected
// Perform Cressman interpolation
double cressmanRadius;
fullConfig.get("binning.cressman radius", cressmanRadius);
for (int i = 0; i < subsampledRows; ++i) {
for (int j = 0; j < subsampledCols; ++j) {
// Initialize sum and sumWeights for Cressman interpolation
count = 0;
sum = static_cast<T>(0);
T sumWeights = static_cast<T>(0);
// Loop through neighboring points for interpolation
for (int si = 0; si < stride; ++si) {
for (int sj = 0; sj < stride; ++sj) {
int row = i * stride + si;
int col = j * stride + sj;
if (row < numRows && col < numCols && mask[row][col] == 1) {
atlas::PointLonLat p0(inputlon[row][col], inputlat[row][col]);
atlas::PointLonLat p1(targetlon[i][j], targetlat[i][j]);
double distance = atlas::util::Earth::distance(p0, p1)/1000.0;

// Calculate the average and store it in the subsampled array
if ( count < minNumObs ) {
subsampled[i][j] = static_cast<T>(-9999);
} else {
subsampled[i][j] = sum / static_cast<T>(count);
double distance_sq = distance * distance;
double cressmanRadius_sq = cressmanRadius * cressmanRadius;
double weight = (distance <= cressmanRadius) ? (cressmanRadius_sq - distance_sq )
/ (cressmanRadius_sq + distance_sq) : 0.0;
sum += inputArray[row][col] * weight;
sumWeights += weight;
count++;
}
}
}

// Update subsampled value with Cressman interpolation
if (count < minNumObs || sumWeights == 0.0) {
subsampled[i][j] = static_cast<T>(-9999);
} else {
subsampled[i][j] = sum / static_cast<T>(sumWeights);
}
}
}
}

std::cout << " done subsampling" << std::endl;
return subsampled;
}
Expand Down

0 comments on commit 41493ad

Please sign in to comment.