-
Notifications
You must be signed in to change notification settings - Fork 1
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
Implement first draft of freight lem execution sequence #120
Conversation
…truck commodities. Changed freight spec perception value to improve result interpretation.
…Added new traversaldata handling module. Added docstring to outputting traversal matrices. Fixed commodity typo in testing freight assignment.
…t specified in run arguments. Small traversaldata refactoring.
continue | ||
purposes[commodity] = FreightPurpose(commodity_params, zonedata, resultdata) | ||
purps_to_assign = list(filter(lambda purposes: purposes[0] in | ||
list(purposes), args.specify_commodity_names)) |
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.
Create extra attributes for only specified purposes.
Scripts/freight_lem.py
Outdated
commodity_params = json.loads(file.read_text("utf-8")) | ||
commodity = commodity_params["name"] | ||
if commodity not in ("marita", "kalevi"): | ||
continue |
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.
Forgot to take this off while testing. Shouldn't be here.
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.
So will you remove it?
aux_tons = numpy.zeros([len(zones), len(zones)], dtype=numpy.float32) | ||
for ass_class in param.freight_modes: | ||
file = result_path / f"{ass_class}.txt" | ||
aux_tons += read_traversal_file(file, numpy.array(zones)) |
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 was also thinking of passing the zeros matrix to the next func and performing addition there but this seems better to me.
@@ -183,6 +183,11 @@ def prepare_freight_network(self, car_dist_unit_cost: Dict[str, float], | |||
"LINK", '@a_' + attr_name, | |||
"commodity flow", overwrite=True, | |||
scenario=self.mod_scenario) | |||
attr_name = (comm_class + "truck")[:17] | |||
self.emme_project.create_extra_attribute( | |||
"LINK", '@' + attr_name, |
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.
Commodity specific truck assignment was missing. Added into this development phase.
@@ -69,7 +69,7 @@ def __init__(self, | |||
"perception_factor": 1, | |||
}, | |||
"aux_transit_time": { | |||
"perception_factor": 10, | |||
"perception_factor": 30, |
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.
This is related to having difficulties interpreting aux time matrix results in current iteration due to timau * 3 in mode u. Instead I tested demand calc with having timau * 1 and perception factor 30 here which seemed to produce same results with easier aux time interpretation. We can drop this from this PR if needed.
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.
Looks very good! Some remarks:
int(line.split(" ")[0]) | ||
except ValueError: | ||
continue | ||
filt_data = list(filter(None, line.split(" "))) |
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 is this different from simply line.split()
?
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.
Seems that I was stuck on splitting with white spaces and forgot that split without sep specification gets rid of them. Will update.
if char not in units.keys(): | ||
continue | ||
value = f"{cell[:i]}.{cell[i+1:]}" | ||
return numpy.float32(value) * units[char] |
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.
Consider writing without the negation:
if char not in units.keys(): | |
continue | |
value = f"{cell[:i]}.{cell[i+1:]}" | |
return numpy.float32(value) * units[char] | |
if char in units.keys(): | |
value = f"{cell[:i]}.{cell[i+1:]}" | |
return numpy.float32(value) * units[char] |
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.
Very nice module!
Scripts/freight_lem.py
Outdated
base_zonedata_path = Path(BASE_FOLDER, args.baseline_data_path, BASE_ZONEDATA_FILE) | ||
cost_data_path = Path(BASE_FOLDER, args.cost_data_path) | ||
results_path = Path(BASE_FOLDER, args.results_path) | ||
emme_project_path = Path(BASE_FOLDER, args.emme_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.
This script is meant for running in production, so it should not use paths relative to BASE_FOLDER
. Would we not prefer having the paths as-is from argument parsing?
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.
This makes sense, will update.
if purpose not in args.specify_commodity_names: | ||
continue | ||
# Explicitly save commodity | ||
matrix_id = f"mf{matrix_counter}" | ||
matrix_name = f"{purpose}_{mode}" | ||
matrix_type = "demand" | ||
ass_model._create_matrix(matrix_id, matrix_name, matrix_type, overwrite=True) | ||
matrix_counter += 1 | ||
ass_model.freight_network.emme_matrices.update( | ||
{matrix_name: {matrix_type: matrix_id}}) | ||
ass_model.freight_network.set_matrix(matrix_name, demand[mode]) | ||
with resultmatrices.open("freight_demand", "vrk", zone_numbers, m="a") as mtx: | ||
mtx[matrix_name] = demand[mode] | ||
if purpose in args.specify_commodity_names: | ||
ass_model.freight_network.save_network_volumes(purpose) | ||
matrix_counter += 7 # Shift to next 10 digit |
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.
Let's leave this as it is for now (or remove it if the script works without it), but I will integrate it in AssignmentModel
as soon I have finished the refactoring of ditto.
Scripts/freight_lem.py
Outdated
config = { | ||
"LOG_LEVEL": "INFO", | ||
"LOG_FORMAT": "TEXT", | ||
"SCENARIO_NAME": "test", | ||
"BASELINE_DATA_PATH": "tests/test_data/Scenario_input_data/2030_test/", | ||
"COST_DATA_PATH": "tests/test_data/Scenario_input_data/2030_test/costdata.json", | ||
"RESULTS_PATH": "tests/test_data/Results/test/", | ||
"EMME_PATH": "tests/test_data/Results/test_assignment/test_assignment.emp", | ||
"FIRST_SCENARIO_ID": 19, | ||
"SAVE_EMME_MATRICES": True, | ||
"FIRST_MATRIX_ID": 200, | ||
"SPECIFY_COMMODITY_NAMES": ["marita"] | ||
} |
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.
Please remove from here. We can use exisiting Config
class (taking the defaults from dev-config.json
) if we want to have default values.
Scripts/freight_lem.py
Outdated
impedance = { | ||
"truck": { | ||
"dist": impedance["dist"]["truck"], | ||
"time": impedance["time"]["truck"], | ||
"toll": zeros | ||
}, | ||
"freight_train": { | ||
"dist": impedance["dist"]["freight_train"], | ||
"time": impedance["time"]["freight_train"], | ||
}, | ||
"ship": { | ||
"dist": impedance["dist"]["ship"], | ||
"channel": zeros | ||
}, | ||
"freight_train_aux": { | ||
"dist": impedance["aux_dist"]["freight_train"], | ||
"time": impedance["aux_time"]["freight_train"], | ||
"toll": zeros | ||
}, | ||
"ship_aux": { | ||
"dist": impedance["aux_dist"]["ship"], | ||
"time": impedance["aux_time"]["ship"], | ||
"toll": zeros | ||
} |
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 suggest integrating impedance_aux
into impedance
in calc_rail_cost
, calc_ship_cost
and get_aux_cost
, so that names of "aux_dist" and "aux_time" would not change. The name changes "aux_dist" -> "dist" and "aux_time" -> "time" could happen inside get_aux_cost
. In that way you would not have to do this hard-coded remapping here. This would then be enough here:
impedance = {mode: {mtx_type: impedance[mtx_type][mode] for mtx_type in impedance
if mode in impedance[mtx_type]} for mode in ("truck", "freight_train", "ship")}
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.
Yeah I also was not thoroughly content with this section and forgot to comment on it. The reasoning for this was that we had previously refactored freight cost calc impedance formatting into a cleaner look, which however, now contradicted assign() return formatting of freight_assignment.py. I was thinking of similar dict comprehension per suggestion but in the end opted for this longer but easier to interpret structure.
Anyway, I agree with the aux name formatting which I will update along with the dict comprehension suggestion. Besides these to points, we can let this be as it is for time being.
…tead of using an explicit aux impedance parameter in freight cost calc, refactored to store all matrices in single impedance parameter.
line = line.strip() | ||
try: | ||
int(line.split(" ")[0]) | ||
except ValueError: | ||
continue | ||
data = list(line.split()) |
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.
line = line.strip() | |
try: | |
int(line.split(" ")[0]) | |
except ValueError: | |
continue | |
data = list(line.split()) | |
data = line.split() | |
try: | |
int(data[0]) | |
except ValueError: | |
continue |
Scripts/freight_lem.py
Outdated
commodity_params = json.loads(file.read_text("utf-8")) | ||
commodity = commodity_params["name"] | ||
if commodity not in ("marita", "kalevi"): | ||
continue |
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.
So will you remove it?
Scripts/freight_lem.py
Outdated
parser = ArgumentParser(epilog="Freight lem-model-system entry point script.") | ||
config = utils.config.read_from_file() | ||
config["SAVE_EMME_MATRICES"] = True | ||
config["SPECIFY_COMMODITY_NAMES"] = ["marita"] |
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.
If you really want to have this as the default, could you move it to dev-config.json
?
Scripts/freight_lem.py
Outdated
if not isinstance(args.specify_commodity_names, list): | ||
raise TypeError("Invalid type for save commodity names") | ||
for name in args.specify_commodity_names: | ||
if name not in list(commodity_conversion): | ||
raise ValueError("Invalid given commodity name.") |
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 think that what you want to use is the nargs="*"
and choices=commodity_conversion
arguments in add_argument
for "--specify-commodity-names". Setting type
is unnecessary when dealing with strings. See docs here: https://docs.python.org/3/library/argparse.html#nargs
Scripts/utils/freight_costs.py
Outdated
aux_dist = impedance["aux_dist"] | ||
impedance["dist"] = impedance[f"aux_dist"] | ||
del impedance[f"aux_dist"] | ||
try: | ||
impedance["time"] = impedance[f"aux_time"] | ||
del impedance[f"aux_time"] | ||
except KeyError: | ||
pass | ||
try: | ||
del impedance["channel"] | ||
except KeyError: | ||
pass |
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.
Modifying an existing dict can have unpredictable effects outside the function. I suggest creating a new dict:
aux_dist = impedance["aux_dist"] | |
impedance["dist"] = impedance[f"aux_dist"] | |
del impedance[f"aux_dist"] | |
try: | |
impedance["time"] = impedance[f"aux_time"] | |
del impedance[f"aux_time"] | |
except KeyError: | |
pass | |
try: | |
del impedance["channel"] | |
except KeyError: | |
pass | |
impedance_aux = { | |
"dist": impedance["aux_dist"], | |
"time": impedance["aux_time"], | |
} |
Why would "aux_time" not exist?
Good comments, addressed them to improve coherency. A matter which I noticed is that most of the current freight json parameters currently have wrong header naming. This causes the program to pick up a purpose "freight" which obviously does not exist. I have already fixed this model naming issue on the module that creates these json files. My suggestion is that, as we know that the freight parameter files in the repo are outdated due to the recently found size issue, we'll not include the updated models into this PR. Instead I will add open a new PR where we go over these updated freight models. |
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.
Looks very good!
First iteration implementation to run freight forecasting in lem model system environment. Draft uses similar user argument parsing to lem.py.
Currently performs demand calculation and traversal data handling for each freight parameter given in params path. User can specify eligible commodity names that are also assigned to network. Commodity extra attribute creation is only performed for specified commodities.
This PR is currently open for discussion.