12 #include "oops/util/Logger.h"
18 #include <boost/make_unique.hpp>
25 return 180.0f / numBands;
31 const std::vector<float> &latitudes,
32 const std::vector<float> &longitudes,
33 const std::vector<util::DateTime> &datetimes,
34 const std::vector<float> *pressures,
35 const std::vector<int> &stationIds)
36 : options_(options), latitudes_(latitudes), longitudes_(longitudes),
37 datetimes_(datetimes), pressures_(pressures), stationIds_(stationIds)
41 const std::vector<size_t> & validObsIds) {
42 std::vector<int> validObsIdsInSortOrder;
43 std::vector<int> bandLbounds;
49 std::vector<int> &validObsIdsInSortOrder,
50 std::vector<int> &bandLbounds)
54 validObsIdsInSortOrder.clear();
55 validObsIdsInSortOrder.reserve(validObsIds.size());
61 std::vector<int> bandIndices(validObsIds.size());
62 for (
size_t validObsIndex = 0; validObsIndex < validObsIds.size(); ++validObsIndex) {
63 const size_t obsId = validObsIds[validObsIndex];
66 bandIndices[validObsIndex] =
67 std::max(0,
static_cast<int>((89.999f -
latitudes_[obsId]) / bandWidth));
75 [
this, &validObsIds](
size_t obsIndexA,
size_t obsIndexB)
77 size_t obsIdA = validObsIds[obsIndexA];
78 size_t obsIdB = validObsIds[obsIndexB];
91 int currentBandIndex = -1;
92 for (
auto group : splitter.
groups()) {
93 for (
size_t validObsIndex : group) {
94 const size_t obsId = validObsIds[validObsIndex];
95 for (
int band = currentBandIndex + 1; band <= bandIndices[validObsIndex]; ++band) {
96 bandLbounds[band] = validObsIdsInSortOrder.size();
98 currentBandIndex = bandIndices[validObsIndex];
99 validObsIdsInSortOrder.push_back(obsId);
102 for (
int band = currentBandIndex + 1; band < bandLbounds.size(); ++band) {
103 bandLbounds[band] = validObsIds.size();
106 oops::Log::trace() <<
"Buddy check: " << validObsIds.size() <<
" input observations" << std::endl;
110 const std::vector<int> &validObsIdsInSortOrder,
111 const std::vector<int> &bandLbounds) {
113 std::vector<MetOfficeBuddyPair> pairs;
119 const float searchDLatB = searchDLat + 0.5f * bandWidth;
120 const int numSearchBands =
static_cast<int>(searchDLat / bandWidth) + 1;
122 typedef std::vector<int>::const_iterator ObsIdIt;
123 typedef std::vector<int>::const_reverse_iterator ObsIdRevIt;
129 bandBegins[bandIndex] = validObsIdsInSortOrder.begin() + bandLbounds[bandIndex];
130 bandEnds[bandIndex] = validObsIdsInSortOrder.begin() + bandLbounds[bandIndex + 1];
143 const int firstBandToSearch = jBandA;
145 jBandA + numSearchBands);
147 firstObsToCheckInBands = bandBegins;
150 for (ObsIdIt obsIdItA = bandBegins[jBandA]; obsIdItA != bandEnds[jBandA]; ++obsIdItA) {
151 const int obsIdA = *obsIdItA;
153 const float minLonToCheck =
longitudes_[obsIdA] - lonSearchRangeHalfWidth;
154 const float maxLonToCheck =
longitudes_[obsIdA] + lonSearchRangeHalfWidth;
156 buddyCollector->reset(obsIdA);
159 for (
int jBandB = firstBandToSearch; jBandB <= lastBandToSearch; ++jBandB) {
160 float midBandLatB = 90.0f - bandWidth * (jBandB + 0.5f);
164 ObsIdIt firstObsIdItB = firstObsToCheckInBands[jBandB];
165 if (jBandA == jBandB)
166 firstObsIdItB = obsIdItA + 1;
169 bool firstObsInSearchRangeFound =
false;
170 for (ObsIdIt obsIdItB = firstObsIdItB; obsIdItB != bandEnds[jBandB]; ++obsIdItB) {
171 const int obsIdB = *obsIdItB;
176 if (!firstObsInSearchRangeFound) {
177 firstObsToCheckInBands[jBandB] = obsIdItB;
178 firstObsInSearchRangeFound =
true;
181 buddyCollector->examinePotentialBuddy(obsIdB);
182 if (buddyCollector->foundEnoughBuddies())
183 goto FinishProcessingObsA;
184 if (buddyCollector->foundEnoughBuddiesInCurrentBand())
185 goto FinishProcessingBandB;
189 if (maxLonToCheck > 180 && (jBandA != jBandB || lonSearchRangeHalfWidth < 180)) {
191 float wrappedMaxLonToCheck = maxLonToCheck - 360;
192 for (ObsIdIt obsIdItB = bandBegins[jBandB]; obsIdItB != bandEnds[jBandB]; ++obsIdItB) {
193 const int obsIdB = *obsIdItB;
198 buddyCollector->examinePotentialBuddy(obsIdB);
199 if (buddyCollector->foundEnoughBuddies())
200 goto FinishProcessingObsA;
201 if (buddyCollector->foundEnoughBuddiesInCurrentBand())
202 goto FinishProcessingBandB;
207 if (minLonToCheck < -180 && jBandA != jBandB) {
209 float wrappedMinLonToCheck = minLonToCheck + 360;
210 for (ObsIdRevIt obsIdItB(bandEnds[jBandB]), reverseBandEnd(bandBegins[jBandB]);
211 obsIdItB != reverseBandEnd; ++obsIdItB) {
212 const int obsIdB = *obsIdItB;
217 buddyCollector->examinePotentialBuddy(obsIdB);
218 if (buddyCollector->foundEnoughBuddies())
219 goto FinishProcessingObsA;
220 if (buddyCollector->foundEnoughBuddiesInCurrentBand())
221 goto FinishProcessingBandB;
225 FinishProcessingBandB:
226 buddyCollector->startProcessingNextBand();
228 FinishProcessingObsA:
229 buddyCollector->appendBuddyPairsTo(pairs);
233 oops::Log::trace() <<
"Found " << pairs.size() <<
" buddy pairs.\n";
248 float bandWidth)
const {
253 const float midBandLatA = 90.0f - bandWidth * (bandIndex + 0.5f);
255 const float rad = earthRadius * std::cos((
std::abs(midBandLatA) + bandWidth * 0.5f) *
deg2rad);