-
Notifications
You must be signed in to change notification settings - Fork 364
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
Fix gdal-warp -ovr ports #3200
Conversation
There was a problem hiding this 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.
raster/src/main/scala/geotrellis/raster/io/geotiff/OverviewStrategy.scala
Outdated
Show resolved
Hide resolved
raster/src/test/scala/geotrellis/raster/io/geotiff/OverviewStrategySpec.scala
Show resolved
Hide resolved
|
||
import org.scalatest._ | ||
|
||
class OverviewStrategySpec extends FunSpec with Matchers { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1000 for Specs 👍
bc6a3c2
to
4f7fe57
Compare
There was a problem hiding this 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) |
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
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
There was a problem hiding this 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.
layer/src/test/scala/geotrellis/raster/geotiff/GeoTiffReprojectRasterSourceSpec.scala
Outdated
Show resolved
Hide resolved
layer/src/test/scala/geotrellis/raster/geotiff/GeoTiffReprojectRasterSourceSpec.scala
Outdated
Show resolved
Hide resolved
Implementation wasn't updated to properly use OverviewStrategy Also updates OverviewStrategy.selectOverview to clamp returned indices to valid range
47498f0
to
ce931ed
Compare
There was a problem hiding this 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.
spark/src/test/scala/geotrellis/spark/RasterSourceRDDSpec.scala
Outdated
Show resolved
Hide resolved
spark/src/test/scala/geotrellis/store/GeoTrellisRasterSourceSpec.scala
Outdated
Show resolved
Hide resolved
case Base => maxResultion | ||
} | ||
strategy: OverviewStrategy = OverviewStrategy.DEFAULT | ||
)(implicit f: T => CellSize): T = { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
96ab3da
to
d930be7
Compare
ebfa9cb
to
f62214e
Compare
f62214e
to
0bcb552
Compare
// 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 { |
There was a problem hiding this comment.
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.
0bcb552
to
5d7b6fd
Compare
/** | ||
* 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. |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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.
7ffbf11
to
ed78d83
Compare
4390220
to
7d894bd
Compare
* @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, _)) => |
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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
Overview
This PR exposes the overview selection logic implicit in each of the
OverviewStrategy
instances by way of aselectOverview
method. Now, instead of matching and requiring users of the sum type to implement logic themselves, a call toselectOverview
with the availableCellSizes
and the desiredCellSize
will yield a selection of theCellSize
corresponding to the selectedOverview
Checklist
docs
guides update, if necessaryNotes
Optional. Ancillary topics, caveats, alternative strategies that didn't work out, anything else.
Closes #3196