How to include car ferries in OSMnx graphs - overpass-api

Is it possible to have OSMnx (great tool BTW) include car ferries when building a graph? Failing that, what would be the most direct way to build such a graph? The problem isn't just that the ferry routes themselves aren't present but, without the ferries, islands that are in reality reachable by car aren't included in the road network.
I have tried using osmnx.settings.useful_tags_way to no avail. Using 'route'='ferry' in overpass-api returns what I would like to include in the graph so I have been editing the OSMnx downloads.py file trying to alter the overpass-api call directly.
Thanks!

First pass (hacky)
I've came up with fairly hacky partial solution by editing osmnx's downloads.py file and replacing the line (originally around line 350):
query_str = f"{overpass_settings};(way{osm_filter}(poly:'{polygon_coord_str}');>;);out;"
with:
osm_filter2 = f'["route"="ferry"]'
query_str = f"{overpass_settings};(way{osm_filter}(poly:'{polygon_coord_str}');>;way{osm_filter2}(poly:'{polygon_coord_str}');>;);out;"
The query string format took some trial and error. If this, or something like it, turns out to be the best approach, I'll try to make it more broadly applicable (add "ferry" to the predefined filter list rather than hardcoded, pass a list of filters, etc).
Much Better
I found that building separate graphs and unioning them using networkx.union or networkx.disjoint_union did not give usable results. So I have added a multiple filter capability to my version of the osmnx downloads.py file. I also added some additional network type options. So it's now possible to pass, for instance, "ferry" as a network_type for the osmnx.graph_from_* functions:
network_type = "ferry"
I can also now pass multiple network types using a pipe delimiter:
network_type = "drive|ferry"
to get a graph that is the union of the two. When doing this, I found that it's useful to create a second ferry-only graph and use that as a reference to update the tags in the combined network graph. It is also better to load non-simplified graphs at first and and simplify it/them yourself after this step.
Still experimenting
Still having some issues with non-connectedness - now in the ferry-only network. Car ferries at isolated crossings than don't share a harbor with a through-ferry are not included in the ferries-only graphs and therefore the tags of their counterparts in the combined network aren't getting updated as needed. The ferries in the combined network (network_type = "drive|ferry") are all present and connected correctly and therefore their respective islands are now on the road network - which is great. But, because their tags aren't being updated, these isolated ferries are getting default highway speeds (and I'm doing travel time analysis). I can use work around this using:
if not 'highway' in edge[3]:
but, for a robust solution, I think we want to be able to tag them explicitly.
I'd still love to hear what other think.

Related

scala for mapbox vector tiles - getting an 'id' field into the Features written to vector tiles

I'm writing MapBox vector tiles using geotrellis vectorpipe.
see here for the basic flow: https://geotrellis.github.io/vectorpipe/usage.html
Typically GeoJson Features can have an id field, so that Features can be rolled up into FeatureCollections. I need to make use of this field, but vectorpipe doesn't (natively) have this capability.
This is the Feature type used, and you can see it only has space for 1) a Geometry and 2) a data object D (which ends up populating properties in the output). There is no spot for an id.
https://geotrellis.github.io/scaladocs/latest/index.html#geotrellis.vector.Feature
Upstream there's a method called writeFeatureJsonWithID() that does let you inject an id field into a Feature when writing GeoJson.
https://github.com/locationtech/geotrellis/blob/master/vector/src/main/scala/geotrellis/vector/io/json/FeatureFormats.scala#L41-L49
My question is this:
I have worked through the vectorpipe code (https://github.com/geotrellis/vectorpipe), and I can't figure out if/where the data ever exists as GeoJson in a way where I can override and inject the id, maybe using the writeFeatureJsonWithID() or something I write explicitly. A lot of conversions are implicit, but it also may never explicitly sit as json.
Any ideas for how to get an id field in the final GeoJson written to vector tiles?
EDIT
Right now I think the trick is going to be finding a way to override .unfeature() method here:
https://github.com/locationtech/geotrellis/blob/master/vectortile/src/main/scala/geotrellis/vectortile/Layer.scala
The problem is that the internal.vector_tile.Tile is private, so I can construct it without forking the project.
Ended up having to fork geotrellis, hard-code a metadata => id function in Layer.unfeature() and compile locally to include in my project. Not ideal, but it works fine.
Also opened an issue here: https://github.com/locationtech/geotrellis/issues/2884

How do I make use of ILocation source and target in custom routing?

This is my sample network and idea of trying how to make a new routing instead of just the shortest path (the path i want to follow is via the pink arrows)
What am I missing here to make my predefined function work?
Fixing the basics
As explained here, you can't instantiate a Java List, because it is an interface. You can however instantiate any implementing Class of a List, for example an ArrayList.
With this in mind your code will look like this:
List<Path> myPath = new ArrayList<Path>();
myPath.add(path14);
myPath.add(path8);
myPath.add(path);
myPath.add(path1);
myPath.add(path4);
myPath.add(path13);
return myPath;
So far for the basics.
Where to go from here
To get it to consider your actual source and destination for the route planning, define both as input parameters of type ILocation in the properties of the function.
Now comes the really tricky part: writing your own or importing a routing algorithm that can give you that list of paths automatically based on criteria that you define. This is however a topic too broad for this question. The basic steps will be:
Create a graph that represents your AnyLogic path network
Solve the graph routing problem with a solving algorithm (eg. Dijkstra Algorithm), using the graph, the startpoint and the endpoint
Convert the solution you get from the solver back again to an ArrayList that you can work with in AnyLogic
You can do these steps on your own, eg. by implementing the Dijkstra Algorithm yourself, or you import into AnyLogic one of the available graph solving Java packages like JUNG or Graphhopper. In this article I explain step by step how to do so with JUNG.

How do you get around Cloned Templates losing Element References?

I noticed that hyperHTML preserves references I make to elements:
let div = document.createElement("div");
div.textContent = "Before Update";
hyperHTML.bind(document.body)`static1 - ${div} - static2`;
div.textContent = "After Update";
Above will produce a page that says:
static1 - After Update - static2
It is my understanding that hyperHTML ultimately clones an HTML <tempate> element to render the final output. However, don't you typical lose references when cloning an HTML template (like the variable "div" in the example above)?
Therefore, on the initial render, does hyperHTML somehow replace cloned elements with their originals after cloning the HTML template?
Here's how I think it works:
Create an HTML Template of the original template literal while
replacing all interpolations with comments.
Clone the html template with comments left in.
Make elements or document fragments out of each interpolation originally recieved
Replace each comment in the clone with its processed interpolation.
Is this correct?
I am not sure what is the question here, but there is a documentation page, and various examples too to understand how to use hyperHTML, which is not exactly in the way you are using it.
In fact, there's no need to have any reference there because hyperHTML is declarative, so you'd rather write:
function update(text) {
var render = hyperHTML.bind(document.body);
render`static1 - <div>${text}</div> - static2`;
}
and call update("any text") any time you need.
Here's how I think it works ... Is this correct?
No, it's not. hyperHTML doesn't clone anything the way you described, it associates once per unique template tag a sanitized version to the output and finds out all interpolated holes in it.
The part of the library that does this is called domtagger, and the mapping per template literal is based on the standard fact that these are unique per scope:
const templates = [];
function addTemplate(template, value) {
templates.push(template);
return template.join(value);
}
function asTemplate(value) {
return addTemplate`number ${value}!`;
}
asTemplate(1);
asTemplate(2);
asTemplate(Math.random());
templates[0] === templates[1]; // true
templates[1] === templates[2]; // true
// it is always the same template object!
After that, any other element using once that very same tag template will have a clone of that fragment with a map to find holes once and some complex logic to avoid replacing anything that's already known, being that text, attributes, events, or any other kind of node.
hyperHTML never removes comments, it uses these as pin and then uses domdiff to eventually update nodes related to these pins whenever there's a need to update anything.
Domdiff is a vDOM-less implementation of the petit-dom algorithm, which in turns is based on E.W Myers' "An O(ND) Difference Algorithm and Its Variations" paper.
Whenever you have DOM nodes in the holes, hyperHTML understand that and fill these holes with those nodes. If you pass repeatedly the same node, hyperHTML won't do anything 'cause it's full of algorithm and smart decisions, all described in the documentation, to obtain best performance out of its abstraction.
All these things, and much more, normalized for any browser out there, makes hyperHTML weight roughly 7K once minified and gzipped, bit it also offers:
Custom Elements like hooks through onconnected/disconnected listeners
lightweight components through hyperHTML.Component
SVG manipulation as content or via wire
easy Custom Elements definition through HyperHTMLElement class
As summary, if you need these simplifications and you don't want to reinvent the wheel, I suggest you give it a better try.
If you instead are just trying to understand how it works, there's no need to assume anything because the project is fully open source.
So far, all I've read from your questions here and there, is that you just believe to understand how it works so I hope in this reply I've put together all the missing pieces you need to fully understand it.
Do you want to write your own lit/hyperHTML library? Go ahead, feel free to use the domtagger or the domdiff library too, few others are already doing the same.

How to pass heatPorts.T to DynamicPipe flowModel?

In the implementation of a flow models that function with Modelica Standard Library DynamicPipe (or a similar model that builds from PartialTwoPortFlow) there are examples of flow models that take place in an environment with heat transfer that requires wall properties (e.g., heatPorts.T and/or heatPorts.Q_flow) in order to calculate the pressure drop.
For example, a pressure drop model may need to calculate a new visocisty or Prandtl number based on the medium pressure and the wall temperature to capture cooling/heating effects, etc.
The heat transfer model obtains properties of the medium via passing the "states" however there is no existing connection in DynamicPipe or PartialTwoPortFlow that goes the other way.
I've tried numerous variations of ideas and have had no success, including creating a new PartialTwoPortFlow that contains all the heat transfer calls that exist in DynamicPipe.
I hesitate to post this question as I am surprised I am having so much difficulty with this and would not be surprised to find a straight forward solution. Nevertheless I need this ability and curious if others have already solved this issue as I am running short on ideas.
So my questions is:
What is a proper/efficient means of passing the heatPorts.T values to the flowModel?
For those familiar with the MSL Fluids library and more specifically the Pipe models provided, this answer should (hopefully) make sense.
Aside:
It seems the dynamic pipe could be improved a little bit by not restricting the heat transfer area to the perimeter x lengths and instead introduce a parameter (e.g., heatTransferArea) that would permit the user to define it and default to perimeter x lengths. See below
parameter SI.Area heatTransferArea = perimeter*lengths "Total heat transfer area";
HeatTransfer heatTransfer(
...
final surfaceAreas=heatTransferArea , //perimeter*lengths <- replaced
...
End Aside:
In order to communicate heatPorts.T to the flowModel and to not have errors when I checked each of the models I had to do the following:
Make an "input" in the flowModel for Ts_w. Not parameter (take a look at how mediums.state is passed)! Might have to do some finagling with it like "diameters" (see DetailedPipeFlow) to make it be used how you think it's going to be used.
Duplicate PartialTwoPortFlow and add the final Ts_w = Ts_wFM to flowModel. Additionally define the variable SI.Temperature[nFM+1] Ts_wFM in PartialTwoPortFlow and establish definitions similar to statesFM in the equation section.
This will require adding a HeatPorts model to be added.
Duplicate DynamicPipe and change the extension to the new PartialTwoPortFlow. Set use_HeatTransfer to true (as I've set it up this has to be true now for this to work which isn't ideal but manageable). Might be good to make it a final parameter so it can't be changed.
Don't forget to connect heatPorts to the heatports added in step 2.
I believe that this capture a quick version of how I was able to get the wall temperature passed to the flowModel. Perhaps there is a more elegant way but I though this was pretty serviceable. I now simply have one more Partial model and one more pipe model called PartialTwoPort_wTemp and GenericDynamicPipe (I also incorporated my surfaceArea correction in the new pipe).

training a new model using pascal kit

need some help on this.
Currently I am doing a project on computer vision that requires me to train a new model to detect a certain object.
In this case, I am using the system provided by P. Felzenszwalb, D. McAllester, D. Ramaman and his team => Discriminatively trained deformable part models which is implemented in Matlab.
Project webpage: http://www.cs.uchicago.edu/~pff/latent/.
However I have no idea how to direct the system to use my dataset(a collection of images and annotation) which is different from the the PASCAL datasets so as to train a new model.
By directing, I meant a line of code that allows me to change the dataset the system reads from, for training a model.
E.g.
% directory for caching models, intermediate data, and results
cachedir = ['/var/tmp/rbg/YOURPATH/' VOCyear '/'];
I tried looking at their Readme and documentation guides but they do not make any mention. Do correct me if I am wrong.
Let me know if I have not made my problem clear enough.
I tried looking at some files such as global.m but no go.
Your help is much appreciated and thanks in advance!
You can try to read pascal.m in the DPM package(voc-release5), there are similar code working on VOC2007/2010 dataset.
There are plenty of parts that need to be adapted to achieve this. For example the voc_config has to be adapted in order to read from your files.
The same with the pascal_train.m function. Depending on the images and the way you parse them, this may require quite some time to adapt this function.
Other functions to consider:
imreadx
pascal_test
pascaleval