Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix gdal-warp -ovr ports #3200

Merged

Conversation

moradology
Copy link
Contributor

@moradology moradology commented Mar 10, 2020

Overview

This PR exposes the overview selection logic implicit in each of the OverviewStrategy instances by way of a selectOverview method. Now, instead of matching and requiring users of the sum type to implement logic themselves, a call to selectOverview with the available CellSizes and the desired CellSize will yield a selection of the CellSize corresponding to the selected Overview

Checklist

  • docs/CHANGELOG.rst updated, if necessary
  • docs guides update, if necessary
  • New user API has useful Scaladoc strings
  • Unit tests added for bug-fix or new feature

Notes

Optional. Ancillary topics, caveats, alternative strategies that didn't work out, anything else.

Closes #3196

@moradology moradology requested a review from pomadchin March 10, 2020 16:57
Copy link
Member

@pomadchin pomadchin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM and in general it fixes the problem (in case travis is happy). Apart of a small code hygiene things and the lack of a CHANGELOG, my main question is about the def selectOverview function that probably should not be a part of AST, since can be used only in a single known usecase.

Would be happy to talk through it, mb my API concerns are not applicable here.

/cc @moradology @echeipesh // and anyone else if Eugene is busy // we need 3 persons for the consensus? :D

P.S. It looks like some specs are failing i.e. geotrellis.layer.LayoutTileSourceSpec => there is some bug in a new overview selection function. Let's try to be as conservative as it is possible to preserve the old behavior (or some compat) to make RF life easier.

/cc @notthatbreezy & @jisantuc you were using it in RasterFoundry mentioning it here because this can be a pretty sensitive change for RasterFoundry.


import org.scalatest._

class OverviewStrategySpec extends FunSpec with Matchers {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1000 for Specs 👍

@moradology moradology force-pushed the fix/gdal-auto-overview-strategy branch from bc6a3c2 to 4f7fe57 Compare March 11, 2020 19:06
@moradology moradology requested a review from pomadchin March 11, 2020 19:07
Copy link
Member

@pomadchin pomadchin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once Travis is happy I think we can merge it 👍

case Base =>
overviewCS.indexOf(overviewCS.min)
case AutoHigherResolution =>
selectIndexByProximity(overviewCS, desiredCS, 1.0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Waiting for Travis to be happy with this change. This behavior should match to the tested old behavior (the old one had a long testing path).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests turned out to require a bit more attention than I'd anticipated as some of them baked in the AutoHigher behavior rather than Auto

Copy link
Member

@pomadchin pomadchin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once Travis is happy I think we can merge it, but I decided to put a changes request to review it once tests would be fixed 👍; Hope this would not be too bad.

moradology and others added 5 commits March 31, 2020 15:03
Implementation wasn't updated to properly use OverviewStrategy

Also updates OverviewStrategy.selectOverview
to clamp returned indices to valid range
@CloudNiner CloudNiner force-pushed the fix/gdal-auto-overview-strategy branch 2 times, most recently from 47498f0 to ce931ed Compare March 31, 2020 19:15
Copy link
Member

@pomadchin pomadchin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but have questions about why everywhere we use Base instead of the former default AutoHigher (as a sainity check that we preserved the old behavior).

And is it okay that getClosestResolution changed its signature? (im fine with that btw, I don't have a strong opinion about that function atm). If so, what kind of errors can it throw? Can we add a small test? Before this change it returned an Option type so nothing really was to test here.

case Base => maxResultion
}
strategy: OverviewStrategy = OverviewStrategy.DEFAULT
)(implicit f: T => CellSize): T = {
Copy link
Member

@pomadchin pomadchin Mar 31, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this change made this function throw, do we have tests for that? What kind of exceptions can it throw?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, should have mentioned this sooner.

It was Option[Int] because some operations could return an out of bounds index. It's not clear how GDAL handles this situation, so we decided that it would be simpler if OverviewStrategy.selectOverview always returned an in bounds index. Which it now does due to additional error handling there. Before this change, we were doing an option.get everywhere which just pushes the throw further down. In that case, I wasn't sure how we would even handle getting a bad overview.

I can add some additional docstrings to note that selectOverview should always return a clamped index, this was apparently the intent of the code based on a test that predates me picking this task up.

Copy link
Member

@pomadchin pomadchin Mar 31, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When it can’t find an overview the idea was to use the Base layer, since it looks like what GDAL does. That is why function returned Option - it is a normal behavior not to find any overviews

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does that reconcile with the idea that we've decided to include the base layer in the resolutions list in all RasterSource implementations?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this discussion should be moved offline as well?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After a discussion we decided on the following:

  • Revert OverviewStrategy.DEFAULT = AutoHigherResolution to make the default consistent with the old behavior for now. We'll address changing the default at a later date
  • Update AutoHigherResolution implementation to match the docstring and old behavior, and verify it with tests
  • OverviewStrategy.selectOverview still clamps to available indices. Each overview strategy can perform custom clamping behavior, like AutoHigher above, but in the absence of that, the index will be clamped to the nearest valid value, e.g. -1 -> 0 or list.size + 5 -> list.size - 1
  • Revert tests where possible to use the AutoHigher default in order to appropriately test the old behavior.

Fixes methods in:
- RasterSourceRDD.apply
- RasterSource.reprojectToGrid

where OverviewStrategy was not correctly passed to some
resample operations.

**NOTE:**: RasterSourceRDD still inconsistently uses both
ResampleMethod and OverviewStrategy. For best results,
its necessary to use RasterSourceRDD.apply directly.
Same issue as in previous commit for
RasterSourceRDDSpec, need to provide strategy.

See: locationtech#3216
Sets to WARN by default, to reduce
verbosity in build logs which
make it difficult to see the test
results.
In RasterSourceRDD tests in order to better
preserve original test intent (since the
default strategy used to be AutoHigher)
To retain backwards compatibility with
existing code that uses the default strategy.

We expect to change this default to Auto(0)
in the future.
Specifically it should now clamp to Base if
the index is OOB in any direction
@CloudNiner CloudNiner force-pushed the fix/gdal-auto-overview-strategy branch from 96ab3da to d930be7 Compare April 1, 2020 14:42
@pomadchin pomadchin force-pushed the fix/gdal-auto-overview-strategy branch from ebfa9cb to f62214e Compare April 1, 2020 22:09
@pomadchin pomadchin force-pushed the fix/gdal-auto-overview-strategy branch from f62214e to 0bcb552 Compare April 1, 2020 22:12
// This method is unsafe. It's up to the selectOverview method to handle each index OOB error for
// each indivdual strategy
private def selectIndexByProximity(overviewCS: List[CellSize], desiredCS: CellSize, proximityThreshold: Double): Int =
overviewCS.search(desiredCS) match {
Copy link
Member

@pomadchin pomadchin Apr 1, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this could be replaced with a foldM function. Amyway this list should be sorted ¯_(ツ)_/¯ so it could be more easy to read.

@pomadchin pomadchin force-pushed the fix/gdal-auto-overview-strategy branch from 0bcb552 to 5d7b6fd Compare April 1, 2020 23:15
/**
* Select appropriate overview given the strategy.
*
* WARN: this function assumes that CellSizes are sorted. It interprets idx 0 as the position with the highest CellSize.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Taking into the account that this is true, usage of the search function in the selectIndexByProximity function makes it really hard to interpret.

val idx = selectIndexByProximity(overviewCS, desiredCS, 1.0)
// AutoHigherResolution defaults to the closest level
// idx > overviewCS.size means, that idx = overviewCS.size (last idx + 1)
if (idx > overviewCS.size) idx - 1 else idx
Copy link
Member

@pomadchin pomadchin Apr 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to know where is the highest resolution to interpret the index the selectIndexByProximity function returns. If the input list is sorted, idx > overviewCS.size means the lower resolution. In case it is reversed, it means the higher resolution. If the list is not sorted, this index makes no sense for its interpretation.

@pomadchin pomadchin force-pushed the fix/gdal-auto-overview-strategy branch from 7ffbf11 to ed78d83 Compare April 2, 2020 02:26
@pomadchin pomadchin force-pushed the fix/gdal-auto-overview-strategy branch from 4390220 to 7d894bd Compare April 2, 2020 14:29
* @return index of the closest cellSize. Returns -1 in case nothing was found or the input list was not sorted.
*/
private def selectIndexByProximity(overviewCS: List[CellSize], desiredCS: CellSize, proximityThreshold: Double): Int =
overviewCS.zipWithIndex.foldLeftM(Option.empty[(CellSize, Int)]) { case (acc, r @ (rightCZ, _)) =>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure that with folding it is much easier to read, however it is more explicit about sorting.

// - negative if rightCZ < leftCZ
// - positive if rightCZ > leftCZ
// - zero otherwise (if rightCZ == leftCZ)
if (Ordering[CellSize].compare(rightCZ, leftCZ) < 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

short circuiting if the list is not sorted

@echeipesh echeipesh self-requested a review April 2, 2020 19:20
@echeipesh echeipesh merged commit 7c245f3 into locationtech:master Apr 6, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Conform to GDAL Warp -ovr Overview Selection Options
4 participants