Skip to content

Commit

Permalink
Merge pull request #43 from VolpeUSDOT/2022_4
Browse files Browse the repository at this point in the history
2022 4
  • Loading branch information
kzhang81 committed Jan 13, 2023
2 parents cb79a8a + 4424182 commit 0129635
Show file tree
Hide file tree
Showing 17 changed files with 1,101 additions and 350 deletions.
11 changes: 11 additions & 0 deletions changelog.md
@@ -1,5 +1,16 @@
# FTOT Change Log

## v2022_4
The FTOT 2022.4 public release includes updates related to candidate generation using network density reduction (NDR), Tableau and reporting enhancements, detailed reporting on shortest paths between origin and destination facilities, and other minor bug fixes. The following changes have been made:
- Implements a new method for candidate generation scenarios through network density reduction. The new method incorporates NetworkX shortest path algorithms into (1) selection of candidate processor locations and (2) calculation of the optimal routing solution. Running candidate generation using NDR significantly decreases runtime by pre-solving the network for shortest paths; see documentation for details on methodology and known issues.
- Adds metrics for processor capacity and utilization to the text report and CSV report.
- Updates the Tableau workbook with new information on facility sizes, processor efficiencies and utilizations, and other minor aesthetic improvements.
- Expands reporting on shortest path routes between facilities in the "all_routes" CSV report (formerly "optimal_routes") and a new Tableau routes dashboard when NDR is enabled. Reporting allows users to analyze routes across different scenarios, modes, facility pairs, and optimal vs non-optimal routes. The scenario comparison dashboard has also been updated to reflect these enhancements.
- Corrects a minor bug on converting candidate processor build costs to default units.
- Replaces "kgal" with "thousand_gallon" as default liquid units in the template and example scenario XML files.

See documentation files for additional details.

## v2022_3
The FTOT 2022.3 public release includes updates related to the FTOT multimodal GIS network, Tableau and reporting enhancements, user experience (including video tutorials and supplemental tools), and resilience analysis tools. The following changes have been made:
- Refreshes the default continental United States multimodal network accompanying FTOT for 2022. Key highlights include a more detailed road network, updated pipeline tariff data, and rail and waterway networks have also been updated. For capacity-constrained scenarios, continue to use the older (2019) version of the network.
Expand Down
7 changes: 4 additions & 3 deletions program/ftot.py
Expand Up @@ -19,16 +19,17 @@
ureg = UnitRegistry()
Q_ = ureg.Quantity
ureg.define('usd = [currency]') # add the US Dollar, "USD" to the unit registry
ureg.define('thousand_gallon = kgal')
# solves issue in pint 0.9
if pint.__version__ == 0.9:
ureg.define('short_hundredweight = short_hunderdweight')
ureg.define('long_hundredweight = long_hunderdweight')
ureg.define('us_ton = US_ton')


FTOT_VERSION = "2022.3"
SCHEMA_VERSION = "6.0.3"
VERSION_DATE = "10/5/2022"
FTOT_VERSION = "2022.4"
SCHEMA_VERSION = "6.0.4"
VERSION_DATE = "1/13/2023"

# ===================================================================================================

Expand Down
36 changes: 28 additions & 8 deletions program/ftot_facilities.py
Expand Up @@ -286,7 +286,10 @@ def db_report_commodity_potentials(the_scenario, logger):

# -----------------------------------
with sqlite3.connect(the_scenario.main_db) as db_con:
sql = """ select c.commodity_name, fti.facility_type, fc.io, case when sum(fc.scaled_quantity) is null then 'Unconstrained' else sum(fc.scaled_quantity) end as scaled_quantity, fc.units
sql = """ select c.commodity_name, fti.facility_type, fc.io,
(case when sum(case when fc.scaled_quantity is null then 1 else 0 end) = 0 then sum(fc.scaled_quantity)
else 'Unconstrained' end) as scaled_quantity,
fc.units
from facility_commodities fc
join commodities c on fc.commodity_id = c.commodity_id
join facilities f on f.facility_id = fc.facility_id
Expand All @@ -312,7 +315,10 @@ def db_report_commodity_potentials(the_scenario, logger):
# Add the ignored processing capacity.
# Note this doesn't happen until the bx step.
# -------------------------------------------
sql = """ select c.commodity_name, fti.facility_type, fc.io, case when sum(fc.scaled_quantity) is null then 'Unconstrained' else sum(fc.scaled_quantity) end as scaled_quantity, fc.units, f.ignore_facility
sql = """ select c.commodity_name, fti.facility_type, fc.io,
(case when sum(case when fc.scaled_quantity is null then 1 else 0 end) = 0 then sum(fc.scaled_quantity)
else 'Unconstrained' end) as scaled_quantity,
fc.units, f.ignore_facility
from facility_commodities fc
join commodities c on fc.commodity_id = c.commodity_id
join facilities f on f.facility_id = fc.facility_id
Expand All @@ -339,7 +345,10 @@ def db_report_commodity_potentials(the_scenario, logger):

# Report out net quantities with ignored facilities removed from the query
# -------------------------------------------------------------------------
sql = """ select c.commodity_name, fti.facility_type, fc.io, case when sum(fc.scaled_quantity) is null then 'Unconstrained' else sum(fc.scaled_quantity) end as scaled_quantity, fc.units
sql = """ select c.commodity_name, fti.facility_type, fc.io,
(case when sum(case when fc.scaled_quantity is null then 1 else 0 end) = 0 then sum(fc.scaled_quantity)
else 'Unconstrained' end) as scaled_quantity,
fc.units
from facility_commodities fc
join commodities c on fc.commodity_id = c.commodity_id
join facilities f on f.facility_id = fc.facility_id
Expand Down Expand Up @@ -553,7 +562,7 @@ def load_facility_commodities_input_data(the_scenario, commodity_input_file, log
logger.debug('the CSV file has a blank in the first column. Skipping this line: {}'.format(
list(row.values())))
continue
# {'units': 'kgal', 'facility_name': 'd:01053', 'phase_of_matter': 'liquid', 'value': '9181.521484',
# {'units': 'thousand_gallon', 'facility_name': 'd:01053', 'phase_of_matter': 'liquid', 'value': '9181.521484',
# 'commodity': 'diesel', 'io': 'o', 'share_max_transport_distance'; 'Y'}
io = row["io"]
facility_name = str(row["facility_name"])
Expand Down Expand Up @@ -664,11 +673,22 @@ def load_facility_commodities_input_data(the_scenario, commodity_input_file, log
if commodity_phase.lower() == 'solid':
commodity_unit = the_scenario.default_units_solid_phase

if commodity_name == 'cost_formula':
pass
else:
if commodity_name == 'cost_formula': # handle cost formula units
commodity_unit = commodity_unit.split("/")[-1] # get the denominator from string version
if str(ureg(commodity_unit).dimensionality) == '[length] ** 3' : # if denominator unit looks like a volume
commodity_phase = 'liquid' # then phase is liquid
commodity_unit = ureg.usd/the_scenario.default_units_liquid_phase # and cost unit phase should use default liquid
elif str(ureg(commodity_unit).dimensionality) == '[mass]': # if denominator unit looks like a mass
commodity_phase = 'solid' # then phase is solid
commodity_unit = ureg.usd/the_scenario.default_units_solid_phase # and cost unit phase should use default solid

# now that we process cost_formula, all properties can use this (with try statement in case)
try:
commodity_quantity = commodity_quantity_and_units.to(commodity_unit).magnitude

except Exception as e:
logger.error("FAIL: {} ".format(e))
raise Exception("FAIL: {}".format(e))

if max_processor_input != 'Null':
max_processor_input = max_input_quantity_and_units.to(commodity_unit).magnitude
if min_processor_input != 'Null':
Expand Down

0 comments on commit 0129635

Please sign in to comment.