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

All Person attributes default to java.lang.String when saving to MATSim xml #158

Closed
KasiaKoz opened this issue Jul 14, 2022 · 4 comments
Closed

Comments

@KasiaKoz
Copy link
Contributor

All attributes for a Person are currently saved as java.lang.String in the MATSim xml files:
https://github.com/arup-group/pam/blob/main/pam/write.py#L177

Sometimes MATSim requires different java types. Below is an error caused by running the multimodal contrib, which is expecting Person's age to be saved as java.lang.Integer for example:

  | java.lang.ClassCastException: class java.lang.String cannot be cast to class java.lang.Integer (java.lang.String and java.lang.Integer are in module java.base of loader 'bootstrap')
  | at org.matsim.contrib.multimodal.router.util.WalkTravelTime.setPerson(WalkTravelTime.java:276) ~[columbus-2.1.0-jar-with-dependencies.jar:2.1.0]
  | at org.matsim.contrib.multimodal.router.util.WalkTravelTime.getLinkTravelTime(WalkTravelTime.java:139) ~[columbus-2.1.0-jar-with-dependencies.jar:2.1.0]
  | at org.matsim.core.router.AStarEuclidean.addToPendingNodes(AStarEuclidean.java:152) ~[columbus-2.1.0-jar-with-dependencies.jar:2.1.0]
  | at org.matsim.core.router.Dijkstra.relaxNodeLogic(Dijkstra.java:438) ~[columbus-2.1.0-jar-with-dependencies.jar:2.1.0]
  | at org.matsim.core.router.Dijkstra.relaxNode(Dijkstra.java:409) ~[columbus-2.1.0-jar-with-dependencies.jar:2.1.0]
  | at org.matsim.core.router.AStarLandmarks.relaxNode(AStarLandmarks.java:137) ~[columbus-2.1.0-jar-with-dependencies.jar:2.1.0]
  | at org.matsim.core.router.Dijkstra.searchLogic(Dijkstra.java:317) ~[columbus-2.1.0-jar-with-dependencies.jar:2.1.0]
  | at org.matsim.core.router.Dijkstra.calcLeastCostPath(Dijkstra.java:234) ~[columbus-2.1.0-jar-with-dependencies.jar:2.1.0]
  | at org.matsim.core.router.AStarLandmarks.calcLeastCostPath(AStarLandmarks.java:124) ~[columbus-2.1.0-jar-with-dependencies.jar:2.1.0]
  | at org.matsim.core.router.NetworkRoutingModule.calcRoute(NetworkRoutingModule.java:108) ~[columbus-2.1.0-jar-with-dependencies.jar:2.1.0]
  | at org.matsim.core.router.TripRouter.calcRoute(TripRouter.java:182) ~[columbus-2.1.0-jar-with-dependencies.jar:2.1.0]
  | at org.matsim.core.router.PlanRouter.run(PlanRouter.java:101) ~[columbus-2.1.0-jar-with-dependencies.jar:2.1.0]
  | at org.matsim.core.population.algorithms.PersonPrepareForSim.run(PersonPrepareForSim.java:219) ~[columbus-2.1.0-jar-with-dependencies.jar:2.1.0]
  | at org.matsim.core.population.algorithms.ParallelPersonAlgorithmUtils$PersonAlgoThread.run(ParallelPersonAlgorithmUtils.java:145) ~[columbus-2.1.0-jar-with-dependencies.jar:2.1.0]
  | at java.lang.Thread.run(Thread.java:834) ~[?:?]

We had a go at 'guessing' java types from python types in genet: arup-group/genet#124, master/genet/utils/java_dtypes.py, which may be of use here.

@KasiaKoz
Copy link
Contributor Author

KasiaKoz commented Aug 4, 2022

Now also found on a recent project:

java.lang.ClassCastException: class java.lang.String cannot be cast to class org.matsim.vehicles.PersonVehicles (java.lang.String is in module java.base of loader 'bootstrap'; org.matsim.vehicles.PersonVehicles is in unnamed module of loader 'app')

person attributes after reading and writing out through pam have resulted in:

<attribute class="java.lang.String" name="vehicles">{"car":"person_vehicle_id"}</attribute>

instead of expected

<attribute name="vehicles" class="org.matsim.vehicles.PersonVehicles">{"car":"person_vehicle_id"}</attribute>

/cc @fredshone @Theodore-Chatziioannou

@fredshone
Copy link
Collaborator

fredshone commented Aug 4, 2022

thanks Kasia, we now have a BIP (branch in progress); write-leg-attributes which includes a fix for this specific case in the write_matsim (v12) function:

attributes = et.SubElement(person_xml, 'attributes', {})
            for k, v in person.attributes.items():
                if k == "vehicles":  # todo make something more robust for future 'special' classes
                    attribute = et.SubElement(
                        attributes, 'attribute', {'class': 'org.matsim.vehicles.PersonVehicles', 'name': str(k)}
                        )
                else:
                    attribute = et.SubElement(
                        attributes, 'attribute', {'class': 'java.lang.String', 'name': str(k)}
                        )
                attribute.text = str(v)

This seems to be a working fix but is obviously a bit trash to maintain and will require us to treat the "vehicles" attribute as special/protected forever after.

@fredshone
Copy link
Collaborator

fredshone commented Aug 4, 2022

We also have a type issue in one of the new leg attributes:

                        for k, v in component.attributes.items():
                            if k == 'enterVehicleTime':  # todo make something more robust for future 'special' classes
                                attribute = et.SubElement(
                                attributes, 'attribute', {'class': 'java.lang.Double', 'name': str(k)}
                                )
                            else:
                                attribute = et.SubElement(
                                    attributes, 'attribute', {'class': 'java.lang.String', 'name': str(k)}
                                    )
                            attribute.text = str(v)

This one would be fixed by your type mapping. But i will also look to roll out more broadly for "attributes".

@fredshone
Copy link
Collaborator

fixed badly by 163

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

No branches or pull requests

2 participants