agentscript
agentscript copied to clipboard
slope on droplets off
I was looking at the slopes on the droplets model https://code.agentscript.org/views2/droplets.html , and it occurred to me that the slopes look wrong. If you look at model.slopes
they are all values like 1.4 which is like 80 degrees. I was not expecting slopes bigger than like 10 degrees for that area.
I think it has to do with the way dzdx and dzdy are calculated. They are treating the z values in meters, but the x,y values in terms of pixel dimensions. I think that the x and y should be in terms of meters too.
I wrote some helper functions that seem to work. My question is wether you would be interested in me putting those into a pull request? would we be interested in another class for GeoDatasets?
/**
* utils
*
* */
function geoDzdx(elevation, widthInMeters) {
const pixelScale = widthInMeters / elevation.width
const dzdx = elevation.dzdx(2, (1/8) * (1/pixelScale)) // (1/8) for the kernel and 1/pixelscale to get units right
return dzdx
}
function geoDzdy(elevation, heightInMeters) {
const pixelScale = heightInMeters / elevation.height
const dzdy = elevation.dzdy(2, (1/8) * (1/pixelScale))
return dzdy
}
function slope(dzdx, dzdy) {
const slopes = dzdx.map((x, i) => {
const y = dzdy.data[i]
const a = Math.hypot(-x, -y)
const sl = (Math.PI / 2) - Math.atan2(1, a)
return sl
})
return slopes
}
/**
* Calculate the slope of elevation Dataset in meters
* @param {DataSet} elevationDS
* @param {number} widthMeters The width in meters of the elevation dataset
* @param {number} heightMeters The height in meters of the elevation dataset
* @return {DataSet} slopes The slopes in radians
* */
function slopeFromElevationDS(elevationDS, widthMeters, heightMeters) {
const dzdx = geoDzdx(elevationDS, widthMeters)
const dzdy = geoDzdy(elevationDS, heightMeters)
const slopes = slope(dzdx, dzdy)
return slopes
}
/**
* Calculate the slope of elevation Dataset in meters
* @param {DataSet} elevationDS
* @param {[west, south, east, north]} bounds
* @return {DataSet} slopes The slopes in radians
* */
function slopeFromElevationDS_bounds(elevationDS, bounds) {
const sizeMeters = bboxMetricSize(bounds)
return slopeFromElevationDS(elevationDS, sizeMeters[0], sizeMeters[1])
}
Sounds possible. That would be an issue in DataSet.js and it's convolutions, we could fix those. Alas, I'm stuck with medical stuff today so can't get to that right now.
Here's the code: https://github.com/backspaces/agentscript/blob/master/src/DataSet.js#L352
This is an important distinction that we've talked about in AnyHazard over 8 years. For some model usecases, like sculpting sand and visualizing the general flows on watesheds, we do want dZ/dPixels. As a hack, I'm always trying to find the right delta time when I'm sculpting sand with water because I believe it's written as dZ/dX (meters). I recognized there's a difference of opinion of how this should be.
The current use of the plume model (hazmat and smoke) in AnyHazard is also probably better dealt with in dZ/dPixel.
For cases where you're doing a physical sim and care about time of arrival or distance, you do want dZ / dX (meters). Your avalanche model is probably a good case.
@stephenguerin Thanks for the insight.
So does this suggest a few new methods in the DataSet.js module? The current methods are simple convolutions without units (meters etc)
I was thinking about making a class that inherits from dataset , maybe geodataset, that overrides the slope, aspect, dzdx, etc methods to take bounds.
That makes sense. By bounds you mean bbox? I.e. [west, south, east, north]?
Yeah.
thinking about it, I can see going with delta physical units height / delta physical distance by default and then leave it to modeler to simulate/visualize delta height / deltaPixels
On Sat, Aug 13, 2022, 9:28 AM Owen Densmore @.***> wrote:
@stephenguerin https://github.com/stephenguerin Thanks for the insight.
So does this suggest a few new methods in the DataSet.js module? The current methods are simple convolutions without units (meters etc)
— Reply to this email directly, view it on GitHub https://github.com/backspaces/agentscript/issues/67#issuecomment-1214176913, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAIHKJ6N7CY2OS6QXNZGZZ3VY65JJANCNFSM56MJTMAQ . You are receiving this because you were mentioned.Message ID: @.***>
Does GeoDataSet resolve this? I think it does. I have to really dig in and understand GeoDataSet, touches on a lot of geo concepts I currently lack! Time for a beer.
It's kinda like World.js & GeoWorld.js.
Yeah. When I dug in, I started seeing more and more methods I needed to change.
It really is like the World/GeoWorld: it has coord xfms that go from/to bbox <-> dataset .. i.e. a lonlat for each item in the dataset. Very nice!
One minor request: lat, lng -> lng, lat i.e have "x" first. I say that because other gis-y methods in AS do this. gis.js sez:
- Current gis.js and others use [lon, lat] coords, i.e. x,y.
- gis.latlon(lonlat) converts [lon, lat] to [lat, lon], i.e. y,x as used by leaflet
So: getLatLng(lat, lng) would go to getLngLat(lng, lat), x,y order.
A less important naming convention:
- gis.js and other use "lon" rather than "lng". Might be useful to rename lng to lon.
Why? To disambiguate between leaflet (lat, lng) and more common (currently) use of "lon". I actually researched this, and https://macwright.com/lonlat/ helped
No big at all deal however .. x,y is the high order bit.
Oh, and geojson coords:
[ -105.914164, 35.7241074 ],
.. put lon first.
I need to look through geoworld. There is some good stuff in there.
Sorry to be too chatty, but it occurred to me to ask:
- Should LeafletDataSet, and the newer BBoxDataSet use GeoDataSet?
- Are there other models that should convert as well?
It looks like LeafletDataSet will be easy to change over https://github.com/backspaces/agentscript/pull/68/commits/5d85db73c109bb0cb75c879131a9e7a354e8b578. I converted the droplets model, but I am not sure what other models could use it.
Actually looking at it, since zxyToDataSet
returns a GeoDataSet most of the demos are already using it.
Cool!
I note you have import BBoxTransform from './World.js'
in GeoDataSet. I don't think you need it. And the reason it's not exported in World.js is because it's exposed indirectly via world.bboxTransform(minX, minY, maxX, maxY)
And GeoWorld uses it via inheritance. this.xfm = this.bboxTransform(...bbox)
That is a bit convoluted, I realize! But it keeps is "private" and only exposed to World and it's subclasses.
This is kinda fun, thanks for your patience!