Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b93e6fe
updated scripts to include simulation-based shadow pricing
aletzdy Sep 30, 2022
11600c3
blacken
dhensle Sep 30, 2022
4b9f55e
Updated shadow_pricing.yaml for mtc example
aletzdy Sep 30, 2022
29f893e
Merge branch 'develop_RevisedShadowPricing' of https://github.com/ale…
dhensle Sep 30, 2022
846d3be
code cleanup
dhensle Sep 30, 2022
e2dde11
more cleanup
dhensle Sep 30, 2022
3863396
documentation and passing tests
dhensle Sep 30, 2022
3d1edc7
passing tests
dhensle Sep 30, 2022
c4dc4ea
passing tests
dhensle Oct 1, 2022
23df7b9
updated doc on shadow pricing
aletzdy Oct 3, 2022
4269dd5
2nd Update model doc on shadow pricing
aletzdy Oct 3, 2022
3a87acd
more doc update on shadow pricing
aletzdy Oct 3, 2022
2db5f59
fixing pandas future warning
dhensle Oct 3, 2022
b5768e3
blacken
dhensle Oct 3, 2022
30d67bc
bug in trying to access shadow price settings when not running shadow…
dhensle Oct 3, 2022
a20a396
limiting pandas version
dhensle Oct 3, 2022
4d58a85
always updating choices
dhensle Oct 3, 2022
7c706f7
testing removal of lognormal for hh vot
dhensle Oct 3, 2022
e2e0d9d
putting hh vot back in
dhensle Oct 3, 2022
95d7fd7
updating to match sharrow test versions
dhensle Oct 4, 2022
1ce6d36
raw person table for buffer instead of injectable
dhensle Oct 7, 2022
7167b65
adding segmentation, output by iteration, and external worker removal
dhensle Oct 25, 2022
bce64bd
formatting & documentation
dhensle Oct 27, 2022
ebd2bc8
ensuring TAZ is not selected if no available MAZ
dhensle Nov 4, 2022
aa8d5a3
adding logic to skip external location choice models
dhensle Nov 4, 2022
a79ac7b
consistent multiprocessing results
dhensle Dec 15, 2022
9190535
Merge branch 'develop' into develop_RevisedShadowPricing
dhensle Dec 15, 2022
0d90f87
blacken
dhensle Dec 15, 2022
0898686
Merge branch 'develop_RevisedShadowPricing' of https://github.com/ale…
dhensle Dec 15, 2022
3a78433
updating regression trips
dhensle Dec 15, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 68 additions & 6 deletions activitysim/abm/models/location_choice.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -227,7 +227,7 @@ def location_sample(
DEST_MAZ = "dest_MAZ"


def aggregate_size_terms(dest_size_terms, network_los):
def aggregate_size_terms(dest_size_terms, network_los, model_settings):
#
# aggregate MAZ_size_terms to TAZ_size_terms
#
Expand All@@ -243,6 +243,13 @@ def aggregate_size_terms(dest_size_terms, network_los):
)
MAZ_size_terms[DEST_TAZ] = MAZ_size_terms.index.map(maz_to_taz)

MAZ_size_terms["avail_MAZ"] = np.where(
(MAZ_size_terms.size_term > 0)
& (MAZ_size_terms.shadow_price_utility_adjustment > -999),
1,
0,
)

weighted_average_cols = [
"shadow_price_size_term_adjustment",
"shadow_price_utility_adjustment",
Expand All@@ -261,6 +268,24 @@ def aggregate_size_terms(dest_size_terms, network_los):
for c in weighted_average_cols:
TAZ_size_terms[c] /= TAZ_size_terms["size_term"] # weighted average

spc = shadow_pricing.load_shadow_price_calculator(model_settings)
if spc.use_shadow_pricing and (
spc.shadow_settings["SHADOW_PRICE_METHOD"] == "simulation"
):
# allow TAZs with at least one underassigned MAZ in them, therefore with a shadowprice larger than -999, to be selected again
TAZ_size_terms["shadow_price_utility_adjustment"] = np.where(
(TAZ_size_terms["shadow_price_utility_adjustment"] > -999)
& (TAZ_size_terms["avail_MAZ"] > 0),
0,
-999,
)
# now, negative size term means shadow price is -999. Setting size_term to 0 so the prob of that MAZ being selected becomes 0
MAZ_size_terms["size_term"] = np.where(
MAZ_size_terms["shadow_price_utility_adjustment"] < 0,
0,
MAZ_size_terms["size_term"],
)

if TAZ_size_terms.isna().any(axis=None):
logger.warning(
f"TAZ_size_terms with NAN values\n{TAZ_size_terms[TAZ_size_terms.isna().any(axis=1)]}"
Expand DownExpand Up@@ -308,7 +333,9 @@ def location_presample(
alt_dest_col_name = model_settings["ALT_DEST_COL_NAME"]
assert DEST_TAZ != alt_dest_col_name

MAZ_size_terms, TAZ_size_terms = aggregate_size_terms(dest_size_terms, network_los)
MAZ_size_terms, TAZ_size_terms = aggregate_size_terms(
dest_size_terms, network_los, model_settings
)

# convert MAZ zone_id to 'TAZ' in choosers (persons_merged)
# persons_merged[HOME_TAZ] = persons_merged[HOME_MAZ].map(maz_to_taz)
Expand DownExpand Up@@ -856,6 +883,7 @@ def iterate_location_choice(

# chooser segmentation allows different sets coefficients for e.g. different income_segments or tour_types
chooser_segment_column = model_settings["CHOOSER_SEGMENT_COLUMN_NAME"]
segment_ids = model_settings["SEGMENT_IDS"]

assert (
chooser_segment_column in persons_merged_df
Expand All@@ -869,11 +897,20 @@ def iterate_location_choice(

for iteration in range(1, max_iterations + 1):

persons_merged_df_ = persons_merged_df.copy()

if spc.use_shadow_pricing and iteration > 1:
spc.update_shadow_prices()

choices_df, save_sample_df = run_location_choice(
persons_merged_df,
if spc.shadow_settings["SHADOW_PRICE_METHOD"] == "simulation":
# filter from the sampled persons
persons_merged_df_ = persons_merged_df_[
persons_merged_df_.index.isin(spc.sampled_persons.index)
]
persons_merged_df_ = persons_merged_df_.sort_index()

choices_df_, save_sample_df = run_location_choice(
persons_merged_df_,
network_los,
shadow_price_calculator=spc,
want_logsums=logsum_column_name is not None,
Expand All@@ -886,10 +923,35 @@ def iterate_location_choice(
trace_label=tracing.extend_trace_label(trace_label, "i%s" % iteration),
)

# choices_df is a pandas DataFrame with columns 'choice' and (optionally) 'logsum'
if choices_df is None:
# choices_df is a pandas DataFrame with columns "choice" and (optionally) "logsum"
if choices_df_ is None:
break

if spc.use_shadow_pricing:
# handle simulation method
if (
spc.shadow_settings["SHADOW_PRICE_METHOD"] == "simulation"
and iteration > 1
):
# if a process ends up with no sampled workers in it, hence an empty choice_df_, then choice_df wil be what it was previously
if len(choices_df_) == 0:
choices_df = choices_df
else:
choices_df = pd.concat([choices_df, choices_df_], axis=0)
choices_df_index = choices_df_.index.name
choices_df = choices_df.reset_index()
# update choices of workers/students
choices_df = choices_df.drop_duplicates(
subset=[choices_df_index], keep="last"
)
choices_df = choices_df.set_index(choices_df_index)
choices_df = choices_df.sort_index()
else:
choices_df = choices_df_.copy()

else:
choices_df = choices_df_

spc.set_choices(
choices=choices_df["choice"],
segment_ids=persons_merged_df[chooser_segment_column].reindex(
Expand Down
4 changes: 1 addition & 3 deletions activitysim/abm/models/trip_purpose.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,9 +71,7 @@ def choose_intermediate_trip_purpose(

# probs should sum to 1 across rows
sum_probs = probs_spec[purpose_cols].sum(axis=1)
probs_spec.loc[:, purpose_cols] = probs_spec.loc[:, purpose_cols].div(
sum_probs, axis=0
)
probs_spec[purpose_cols] = probs_spec[purpose_cols].div(sum_probs, axis=0)

# left join trips to probs (there may be multiple rows per trip for multiple depart ranges)
choosers = pd.merge(
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b93e6fe
updated scripts to include simulation-based shadow pricing
aletzdy Sep 30, 2022
11600c3
blacken
dhensle Sep 30, 2022
4b9f55e
Updated shadow_pricing.yaml for mtc example
aletzdy Sep 30, 2022
29f893e
Merge branch 'develop_RevisedShadowPricing' of https://github.com/ale…
dhensle Sep 30, 2022
846d3be
code cleanup
dhensle Sep 30, 2022
e2dde11
more cleanup
dhensle Sep 30, 2022
3863396
documentation and passing tests
dhensle Sep 30, 2022
3d1edc7
passing tests
dhensle Sep 30, 2022
c4dc4ea
passing tests
dhensle Oct 1, 2022
23df7b9
updated doc on shadow pricing
aletzdy Oct 3, 2022
4269dd5
2nd Update model doc on shadow pricing
aletzdy Oct 3, 2022
3a87acd
more doc update on shadow pricing
aletzdy Oct 3, 2022
2db5f59
fixing pandas future warning
dhensle Oct 3, 2022
b5768e3
blacken
dhensle Oct 3, 2022
30d67bc
bug in trying to access shadow price settings when not running shadow…
dhensle Oct 3, 2022
a20a396
limiting pandas version
dhensle Oct 3, 2022
4d58a85
always updating choices
dhensle Oct 3, 2022
7c706f7
testing removal of lognormal for hh vot
dhensle Oct 3, 2022
e2e0d9d
putting hh vot back in
dhensle Oct 3, 2022
95d7fd7
updating to match sharrow test versions
dhensle Oct 4, 2022
1ce6d36
raw person table for buffer instead of injectable
dhensle Oct 7, 2022
7167b65
adding segmentation, output by iteration, and external worker removal
dhensle Oct 25, 2022
bce64bd
formatting & documentation
dhensle Oct 27, 2022
ebd2bc8
ensuring TAZ is not selected if no available MAZ
dhensle Nov 4, 2022
aa8d5a3
adding logic to skip external location choice models
dhensle Nov 4, 2022
a79ac7b
consistent multiprocessing results
dhensle Dec 15, 2022
9190535
Merge branch 'develop' into develop_RevisedShadowPricing
dhensle Dec 15, 2022
0d90f87
blacken
dhensle Dec 15, 2022
0898686
Merge branch 'develop_RevisedShadowPricing' of https://github.com/ale…
dhensle Dec 15, 2022
3a78433
updating regression trips
dhensle Dec 15, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 68 additions & 6 deletions activitysim/abm/models/location_choice.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -227,7 +227,7 @@ def location_sample(
DEST_MAZ = "dest_MAZ"


def aggregate_size_terms(dest_size_terms, network_los):
def aggregate_size_terms(dest_size_terms, network_los, model_settings):
#
# aggregate MAZ_size_terms to TAZ_size_terms
#
Expand All@@ -243,6 +243,13 @@ def aggregate_size_terms(dest_size_terms, network_los):
)
MAZ_size_terms[DEST_TAZ] = MAZ_size_terms.index.map(maz_to_taz)

MAZ_size_terms["avail_MAZ"] = np.where(
(MAZ_size_terms.size_term > 0)
& (MAZ_size_terms.shadow_price_utility_adjustment > -999),
1,
0,
)

weighted_average_cols = [
"shadow_price_size_term_adjustment",
"shadow_price_utility_adjustment",
Expand All@@ -261,6 +268,24 @@ def aggregate_size_terms(dest_size_terms, network_los):
for c in weighted_average_cols:
TAZ_size_terms[c] /= TAZ_size_terms["size_term"] # weighted average

spc = shadow_pricing.load_shadow_price_calculator(model_settings)
if spc.use_shadow_pricing and (
spc.shadow_settings["SHADOW_PRICE_METHOD"] == "simulation"
):
# allow TAZs with at least one underassigned MAZ in them, therefore with a shadowprice larger than -999, to be selected again
TAZ_size_terms["shadow_price_utility_adjustment"] = np.where(
(TAZ_size_terms["shadow_price_utility_adjustment"] > -999)
& (TAZ_size_terms["avail_MAZ"] > 0),
0,
-999,
)
# now, negative size term means shadow price is -999. Setting size_term to 0 so the prob of that MAZ being selected becomes 0
MAZ_size_terms["size_term"] = np.where(
MAZ_size_terms["shadow_price_utility_adjustment"] < 0,
0,
MAZ_size_terms["size_term"],
)

if TAZ_size_terms.isna().any(axis=None):
logger.warning(
f"TAZ_size_terms with NAN values\n{TAZ_size_terms[TAZ_size_terms.isna().any(axis=1)]}"
Expand DownExpand Up@@ -308,7 +333,9 @@ def location_presample(
alt_dest_col_name = model_settings["ALT_DEST_COL_NAME"]
assert DEST_TAZ != alt_dest_col_name

MAZ_size_terms, TAZ_size_terms = aggregate_size_terms(dest_size_terms, network_los)
MAZ_size_terms, TAZ_size_terms = aggregate_size_terms(
dest_size_terms, network_los, model_settings
)

# convert MAZ zone_id to 'TAZ' in choosers (persons_merged)
# persons_merged[HOME_TAZ] = persons_merged[HOME_MAZ].map(maz_to_taz)
Expand DownExpand Up@@ -856,6 +883,7 @@ def iterate_location_choice(

# chooser segmentation allows different sets coefficients for e.g. different income_segments or tour_types
chooser_segment_column = model_settings["CHOOSER_SEGMENT_COLUMN_NAME"]
segment_ids = model_settings["SEGMENT_IDS"]

assert (
chooser_segment_column in persons_merged_df
Expand All@@ -869,11 +897,20 @@ def iterate_location_choice(

for iteration in range(1, max_iterations + 1):

persons_merged_df_ = persons_merged_df.copy()

if spc.use_shadow_pricing and iteration > 1:
spc.update_shadow_prices()

choices_df, save_sample_df = run_location_choice(
persons_merged_df,
if spc.shadow_settings["SHADOW_PRICE_METHOD"] == "simulation":
# filter from the sampled persons
persons_merged_df_ = persons_merged_df_[
persons_merged_df_.index.isin(spc.sampled_persons.index)
]
persons_merged_df_ = persons_merged_df_.sort_index()

choices_df_, save_sample_df = run_location_choice(
persons_merged_df_,
network_los,
shadow_price_calculator=spc,
want_logsums=logsum_column_name is not None,
Expand All@@ -886,10 +923,35 @@ def iterate_location_choice(
trace_label=tracing.extend_trace_label(trace_label, "i%s" % iteration),
)

# choices_df is a pandas DataFrame with columns 'choice' and (optionally) 'logsum'
if choices_df is None:
# choices_df is a pandas DataFrame with columns "choice" and (optionally) "logsum"
if choices_df_ is None:
break

if spc.use_shadow_pricing:
# handle simulation method
if (
spc.shadow_settings["SHADOW_PRICE_METHOD"] == "simulation"
and iteration > 1
):
# if a process ends up with no sampled workers in it, hence an empty choice_df_, then choice_df wil be what it was previously
if len(choices_df_) == 0:
choices_df = choices_df
else:
choices_df = pd.concat([choices_df, choices_df_], axis=0)
choices_df_index = choices_df_.index.name
choices_df = choices_df.reset_index()
# update choices of workers/students
choices_df = choices_df.drop_duplicates(
subset=[choices_df_index], keep="last"
)
choices_df = choices_df.set_index(choices_df_index)
choices_df = choices_df.sort_index()
else:
choices_df = choices_df_.copy()

else:
choices_df = choices_df_

spc.set_choices(
choices=choices_df["choice"],
segment_ids=persons_merged_df[chooser_segment_column].reindex(
Expand Down
4 changes: 1 addition & 3 deletions activitysim/abm/models/trip_purpose.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,9 +71,7 @@ def choose_intermediate_trip_purpose(

# probs should sum to 1 across rows
sum_probs = probs_spec[purpose_cols].sum(axis=1)
probs_spec.loc[:, purpose_cols] = probs_spec.loc[:, purpose_cols].div(
sum_probs, axis=0
)
probs_spec[purpose_cols] = probs_spec[purpose_cols].div(sum_probs, axis=0)

# left join trips to probs (there may be multiple rows per trip for multiple depart ranges)
choosers = pd.merge(
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b93e6fe
updated scripts to include simulation-based shadow pricing
aletzdy Sep 30, 2022
11600c3
blacken
dhensle Sep 30, 2022
4b9f55e
Updated shadow_pricing.yaml for mtc example
aletzdy Sep 30, 2022
29f893e
Merge branch 'develop_RevisedShadowPricing' of https://github.com/ale…
dhensle Sep 30, 2022
846d3be
code cleanup
dhensle Sep 30, 2022
e2dde11
more cleanup
dhensle Sep 30, 2022
3863396
documentation and passing tests
dhensle Sep 30, 2022
3d1edc7
passing tests
dhensle Sep 30, 2022
c4dc4ea
passing tests
dhensle Oct 1, 2022
23df7b9
updated doc on shadow pricing
aletzdy Oct 3, 2022
4269dd5
2nd Update model doc on shadow pricing
aletzdy Oct 3, 2022
3a87acd
more doc update on shadow pricing
aletzdy Oct 3, 2022
2db5f59
fixing pandas future warning
dhensle Oct 3, 2022
b5768e3
blacken
dhensle Oct 3, 2022
30d67bc
bug in trying to access shadow price settings when not running shadow…
dhensle Oct 3, 2022
a20a396
limiting pandas version
dhensle Oct 3, 2022
4d58a85
always updating choices
dhensle Oct 3, 2022
7c706f7
testing removal of lognormal for hh vot
dhensle Oct 3, 2022
e2e0d9d
putting hh vot back in
dhensle Oct 3, 2022
95d7fd7
updating to match sharrow test versions
dhensle Oct 4, 2022
1ce6d36
raw person table for buffer instead of injectable
dhensle Oct 7, 2022
7167b65
adding segmentation, output by iteration, and external worker removal
dhensle Oct 25, 2022
bce64bd
formatting & documentation
dhensle Oct 27, 2022
ebd2bc8
ensuring TAZ is not selected if no available MAZ
dhensle Nov 4, 2022
aa8d5a3
adding logic to skip external location choice models
dhensle Nov 4, 2022
a79ac7b
consistent multiprocessing results
dhensle Dec 15, 2022
9190535
Merge branch 'develop' into develop_RevisedShadowPricing
dhensle Dec 15, 2022
0d90f87
blacken
dhensle Dec 15, 2022
0898686
Merge branch 'develop_RevisedShadowPricing' of https://github.com/ale…
dhensle Dec 15, 2022
3a78433
updating regression trips
dhensle Dec 15, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 68 additions & 6 deletions activitysim/abm/models/location_choice.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -227,7 +227,7 @@ def location_sample(
DEST_MAZ = "dest_MAZ"


def aggregate_size_terms(dest_size_terms, network_los):
def aggregate_size_terms(dest_size_terms, network_los, model_settings):
#
# aggregate MAZ_size_terms to TAZ_size_terms
#
Expand All@@ -243,6 +243,13 @@ def aggregate_size_terms(dest_size_terms, network_los):
)
MAZ_size_terms[DEST_TAZ] = MAZ_size_terms.index.map(maz_to_taz)

MAZ_size_terms["avail_MAZ"] = np.where(
(MAZ_size_terms.size_term > 0)
& (MAZ_size_terms.shadow_price_utility_adjustment > -999),
1,
0,
)

weighted_average_cols = [
"shadow_price_size_term_adjustment",
"shadow_price_utility_adjustment",
Expand All@@ -261,6 +268,24 @@ def aggregate_size_terms(dest_size_terms, network_los):
for c in weighted_average_cols:
TAZ_size_terms[c] /= TAZ_size_terms["size_term"] # weighted average

spc = shadow_pricing.load_shadow_price_calculator(model_settings)
if spc.use_shadow_pricing and (
spc.shadow_settings["SHADOW_PRICE_METHOD"] == "simulation"
):
# allow TAZs with at least one underassigned MAZ in them, therefore with a shadowprice larger than -999, to be selected again
TAZ_size_terms["shadow_price_utility_adjustment"] = np.where(
(TAZ_size_terms["shadow_price_utility_adjustment"] > -999)
& (TAZ_size_terms["avail_MAZ"] > 0),
0,
-999,
)
# now, negative size term means shadow price is -999. Setting size_term to 0 so the prob of that MAZ being selected becomes 0
MAZ_size_terms["size_term"] = np.where(
MAZ_size_terms["shadow_price_utility_adjustment"] < 0,
0,
MAZ_size_terms["size_term"],
)

if TAZ_size_terms.isna().any(axis=None):
logger.warning(
f"TAZ_size_terms with NAN values\n{TAZ_size_terms[TAZ_size_terms.isna().any(axis=1)]}"
Expand DownExpand Up@@ -308,7 +333,9 @@ def location_presample(
alt_dest_col_name = model_settings["ALT_DEST_COL_NAME"]
assert DEST_TAZ != alt_dest_col_name

MAZ_size_terms, TAZ_size_terms = aggregate_size_terms(dest_size_terms, network_los)
MAZ_size_terms, TAZ_size_terms = aggregate_size_terms(
dest_size_terms, network_los, model_settings
)

# convert MAZ zone_id to 'TAZ' in choosers (persons_merged)
# persons_merged[HOME_TAZ] = persons_merged[HOME_MAZ].map(maz_to_taz)
Expand DownExpand Up@@ -856,6 +883,7 @@ def iterate_location_choice(

# chooser segmentation allows different sets coefficients for e.g. different income_segments or tour_types
chooser_segment_column = model_settings["CHOOSER_SEGMENT_COLUMN_NAME"]
segment_ids = model_settings["SEGMENT_IDS"]

assert (
chooser_segment_column in persons_merged_df
Expand All@@ -869,11 +897,20 @@ def iterate_location_choice(

for iteration in range(1, max_iterations + 1):

persons_merged_df_ = persons_merged_df.copy()

if spc.use_shadow_pricing and iteration > 1:
spc.update_shadow_prices()

choices_df, save_sample_df = run_location_choice(
persons_merged_df,
if spc.shadow_settings["SHADOW_PRICE_METHOD"] == "simulation":
# filter from the sampled persons
persons_merged_df_ = persons_merged_df_[
persons_merged_df_.index.isin(spc.sampled_persons.index)
]
persons_merged_df_ = persons_merged_df_.sort_index()

choices_df_, save_sample_df = run_location_choice(
persons_merged_df_,
network_los,
shadow_price_calculator=spc,
want_logsums=logsum_column_name is not None,
Expand All@@ -886,10 +923,35 @@ def iterate_location_choice(
trace_label=tracing.extend_trace_label(trace_label, "i%s" % iteration),
)

# choices_df is a pandas DataFrame with columns 'choice' and (optionally) 'logsum'
if choices_df is None:
# choices_df is a pandas DataFrame with columns "choice" and (optionally) "logsum"
if choices_df_ is None:
break

if spc.use_shadow_pricing:
# handle simulation method
if (
spc.shadow_settings["SHADOW_PRICE_METHOD"] == "simulation"
and iteration > 1
):
# if a process ends up with no sampled workers in it, hence an empty choice_df_, then choice_df wil be what it was previously
if len(choices_df_) == 0:
choices_df = choices_df
else:
choices_df = pd.concat([choices_df, choices_df_], axis=0)
choices_df_index = choices_df_.index.name
choices_df = choices_df.reset_index()
# update choices of workers/students
choices_df = choices_df.drop_duplicates(
subset=[choices_df_index], keep="last"
)
choices_df = choices_df.set_index(choices_df_index)
choices_df = choices_df.sort_index()
else:
choices_df = choices_df_.copy()

else:
choices_df = choices_df_

spc.set_choices(
choices=choices_df["choice"],
segment_ids=persons_merged_df[chooser_segment_column].reindex(
Expand Down
4 changes: 1 addition & 3 deletions activitysim/abm/models/trip_purpose.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,9 +71,7 @@ def choose_intermediate_trip_purpose(

# probs should sum to 1 across rows
sum_probs = probs_spec[purpose_cols].sum(axis=1)
probs_spec.loc[:, purpose_cols] = probs_spec.loc[:, purpose_cols].div(
sum_probs, axis=0
)
probs_spec[purpose_cols] = probs_spec[purpose_cols].div(sum_probs, axis=0)

# left join trips to probs (there may be multiple rows per trip for multiple depart ranges)
choosers = pd.merge(
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b93e6fe
updated scripts to include simulation-based shadow pricing
aletzdy Sep 30, 2022
11600c3
blacken
dhensle Sep 30, 2022
4b9f55e
Updated shadow_pricing.yaml for mtc example
aletzdy Sep 30, 2022
29f893e
Merge branch 'develop_RevisedShadowPricing' of https://github.com/ale…
dhensle Sep 30, 2022
846d3be
code cleanup
dhensle Sep 30, 2022
e2dde11
more cleanup
dhensle Sep 30, 2022
3863396
documentation and passing tests
dhensle Sep 30, 2022
3d1edc7
passing tests
dhensle Sep 30, 2022
c4dc4ea
passing tests
dhensle Oct 1, 2022
23df7b9
updated doc on shadow pricing
aletzdy Oct 3, 2022
4269dd5
2nd Update model doc on shadow pricing
aletzdy Oct 3, 2022
3a87acd
more doc update on shadow pricing
aletzdy Oct 3, 2022
2db5f59
fixing pandas future warning
dhensle Oct 3, 2022
b5768e3
blacken
dhensle Oct 3, 2022
30d67bc
bug in trying to access shadow price settings when not running shadow…
dhensle Oct 3, 2022
a20a396
limiting pandas version
dhensle Oct 3, 2022
4d58a85
always updating choices
dhensle Oct 3, 2022
7c706f7
testing removal of lognormal for hh vot
dhensle Oct 3, 2022
e2e0d9d
putting hh vot back in
dhensle Oct 3, 2022
95d7fd7
updating to match sharrow test versions
dhensle Oct 4, 2022
1ce6d36
raw person table for buffer instead of injectable
dhensle Oct 7, 2022
7167b65
adding segmentation, output by iteration, and external worker removal
dhensle Oct 25, 2022
bce64bd
formatting & documentation
dhensle Oct 27, 2022
ebd2bc8
ensuring TAZ is not selected if no available MAZ
dhensle Nov 4, 2022
aa8d5a3
adding logic to skip external location choice models
dhensle Nov 4, 2022
a79ac7b
consistent multiprocessing results
dhensle Dec 15, 2022
9190535
Merge branch 'develop' into develop_RevisedShadowPricing
dhensle Dec 15, 2022
0d90f87
blacken
dhensle Dec 15, 2022
0898686
Merge branch 'develop_RevisedShadowPricing' of https://github.com/ale…
dhensle Dec 15, 2022
3a78433
updating regression trips
dhensle Dec 15, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 68 additions & 6 deletions activitysim/abm/models/location_choice.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -227,7 +227,7 @@ def location_sample(
DEST_MAZ = "dest_MAZ"


def aggregate_size_terms(dest_size_terms, network_los):
def aggregate_size_terms(dest_size_terms, network_los, model_settings):
#
# aggregate MAZ_size_terms to TAZ_size_terms
#
Expand All@@ -243,6 +243,13 @@ def aggregate_size_terms(dest_size_terms, network_los):
)
MAZ_size_terms[DEST_TAZ] = MAZ_size_terms.index.map(maz_to_taz)

MAZ_size_terms["avail_MAZ"] = np.where(
(MAZ_size_terms.size_term > 0)
& (MAZ_size_terms.shadow_price_utility_adjustment > -999),
1,
0,
)

weighted_average_cols = [
"shadow_price_size_term_adjustment",
"shadow_price_utility_adjustment",
Expand All@@ -261,6 +268,24 @@ def aggregate_size_terms(dest_size_terms, network_los):
for c in weighted_average_cols:
TAZ_size_terms[c] /= TAZ_size_terms["size_term"] # weighted average

spc = shadow_pricing.load_shadow_price_calculator(model_settings)
if spc.use_shadow_pricing and (
spc.shadow_settings["SHADOW_PRICE_METHOD"] == "simulation"
):
# allow TAZs with at least one underassigned MAZ in them, therefore with a shadowprice larger than -999, to be selected again
TAZ_size_terms["shadow_price_utility_adjustment"] = np.where(
(TAZ_size_terms["shadow_price_utility_adjustment"] > -999)
& (TAZ_size_terms["avail_MAZ"] > 0),
0,
-999,
)
# now, negative size term means shadow price is -999. Setting size_term to 0 so the prob of that MAZ being selected becomes 0
MAZ_size_terms["size_term"] = np.where(
MAZ_size_terms["shadow_price_utility_adjustment"] < 0,
0,
MAZ_size_terms["size_term"],
)

if TAZ_size_terms.isna().any(axis=None):
logger.warning(
f"TAZ_size_terms with NAN values\n{TAZ_size_terms[TAZ_size_terms.isna().any(axis=1)]}"
Expand DownExpand Up@@ -308,7 +333,9 @@ def location_presample(
alt_dest_col_name = model_settings["ALT_DEST_COL_NAME"]
assert DEST_TAZ != alt_dest_col_name

MAZ_size_terms, TAZ_size_terms = aggregate_size_terms(dest_size_terms, network_los)
MAZ_size_terms, TAZ_size_terms = aggregate_size_terms(
dest_size_terms, network_los, model_settings
)

# convert MAZ zone_id to 'TAZ' in choosers (persons_merged)
# persons_merged[HOME_TAZ] = persons_merged[HOME_MAZ].map(maz_to_taz)
Expand DownExpand Up@@ -856,6 +883,7 @@ def iterate_location_choice(

# chooser segmentation allows different sets coefficients for e.g. different income_segments or tour_types
chooser_segment_column = model_settings["CHOOSER_SEGMENT_COLUMN_NAME"]
segment_ids = model_settings["SEGMENT_IDS"]

assert (
chooser_segment_column in persons_merged_df
Expand All@@ -869,11 +897,20 @@ def iterate_location_choice(

for iteration in range(1, max_iterations + 1):

persons_merged_df_ = persons_merged_df.copy()

if spc.use_shadow_pricing and iteration > 1:
spc.update_shadow_prices()

choices_df, save_sample_df = run_location_choice(
persons_merged_df,
if spc.shadow_settings["SHADOW_PRICE_METHOD"] == "simulation":
# filter from the sampled persons
persons_merged_df_ = persons_merged_df_[
persons_merged_df_.index.isin(spc.sampled_persons.index)
]
persons_merged_df_ = persons_merged_df_.sort_index()

choices_df_, save_sample_df = run_location_choice(
persons_merged_df_,
network_los,
shadow_price_calculator=spc,
want_logsums=logsum_column_name is not None,
Expand All@@ -886,10 +923,35 @@ def iterate_location_choice(
trace_label=tracing.extend_trace_label(trace_label, "i%s" % iteration),
)

# choices_df is a pandas DataFrame with columns 'choice' and (optionally) 'logsum'
if choices_df is None:
# choices_df is a pandas DataFrame with columns "choice" and (optionally) "logsum"
if choices_df_ is None:
break

if spc.use_shadow_pricing:
# handle simulation method
if (
spc.shadow_settings["SHADOW_PRICE_METHOD"] == "simulation"
and iteration > 1
):
# if a process ends up with no sampled workers in it, hence an empty choice_df_, then choice_df wil be what it was previously
if len(choices_df_) == 0:
choices_df = choices_df
else:
choices_df = pd.concat([choices_df, choices_df_], axis=0)
choices_df_index = choices_df_.index.name
choices_df = choices_df.reset_index()
# update choices of workers/students
choices_df = choices_df.drop_duplicates(
subset=[choices_df_index], keep="last"
)
choices_df = choices_df.set_index(choices_df_index)
choices_df = choices_df.sort_index()
else:
choices_df = choices_df_.copy()

else:
choices_df = choices_df_

spc.set_choices(
choices=choices_df["choice"],
segment_ids=persons_merged_df[chooser_segment_column].reindex(
Expand Down
4 changes: 1 addition & 3 deletions activitysim/abm/models/trip_purpose.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,9 +71,7 @@ def choose_intermediate_trip_purpose(

# probs should sum to 1 across rows
sum_probs = probs_spec[purpose_cols].sum(axis=1)
probs_spec.loc[:, purpose_cols] = probs_spec.loc[:, purpose_cols].div(
sum_probs, axis=0
)
probs_spec[purpose_cols] = probs_spec[purpose_cols].div(sum_probs, axis=0)

# left join trips to probs (there may be multiple rows per trip for multiple depart ranges)
choosers = pd.merge(
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b93e6fe
updated scripts to include simulation-based shadow pricing
aletzdy Sep 30, 2022
11600c3
blacken
dhensle Sep 30, 2022
4b9f55e
Updated shadow_pricing.yaml for mtc example
aletzdy Sep 30, 2022
29f893e
Merge branch 'develop_RevisedShadowPricing' of https://github.com/ale…
dhensle Sep 30, 2022
846d3be
code cleanup
dhensle Sep 30, 2022
e2dde11
more cleanup
dhensle Sep 30, 2022
3863396
documentation and passing tests
dhensle Sep 30, 2022
3d1edc7
passing tests
dhensle Sep 30, 2022
c4dc4ea
passing tests
dhensle Oct 1, 2022
23df7b9
updated doc on shadow pricing
aletzdy Oct 3, 2022
4269dd5
2nd Update model doc on shadow pricing
aletzdy Oct 3, 2022
3a87acd
more doc update on shadow pricing
aletzdy Oct 3, 2022
2db5f59
fixing pandas future warning
dhensle Oct 3, 2022
b5768e3
blacken
dhensle Oct 3, 2022
30d67bc
bug in trying to access shadow price settings when not running shadow…
dhensle Oct 3, 2022
a20a396
limiting pandas version
dhensle Oct 3, 2022
4d58a85
always updating choices
dhensle Oct 3, 2022
7c706f7
testing removal of lognormal for hh vot
dhensle Oct 3, 2022
e2e0d9d
putting hh vot back in
dhensle Oct 3, 2022
95d7fd7
updating to match sharrow test versions
dhensle Oct 4, 2022
1ce6d36
raw person table for buffer instead of injectable
dhensle Oct 7, 2022
7167b65
adding segmentation, output by iteration, and external worker removal
dhensle Oct 25, 2022
bce64bd
formatting & documentation
dhensle Oct 27, 2022
ebd2bc8
ensuring TAZ is not selected if no available MAZ
dhensle Nov 4, 2022
aa8d5a3
adding logic to skip external location choice models
dhensle Nov 4, 2022
a79ac7b
consistent multiprocessing results
dhensle Dec 15, 2022
9190535
Merge branch 'develop' into develop_RevisedShadowPricing
dhensle Dec 15, 2022
0d90f87
blacken
dhensle Dec 15, 2022
0898686
Merge branch 'develop_RevisedShadowPricing' of https://github.com/ale…
dhensle Dec 15, 2022
3a78433
updating regression trips
dhensle Dec 15, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 68 additions & 6 deletions activitysim/abm/models/location_choice.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -227,7 +227,7 @@ def location_sample(
DEST_MAZ = "dest_MAZ"


def aggregate_size_terms(dest_size_terms, network_los):
def aggregate_size_terms(dest_size_terms, network_los, model_settings):
#
# aggregate MAZ_size_terms to TAZ_size_terms
#
Expand All@@ -243,6 +243,13 @@ def aggregate_size_terms(dest_size_terms, network_los):
)
MAZ_size_terms[DEST_TAZ] = MAZ_size_terms.index.map(maz_to_taz)

MAZ_size_terms["avail_MAZ"] = np.where(
(MAZ_size_terms.size_term > 0)
& (MAZ_size_terms.shadow_price_utility_adjustment > -999),
1,
0,
)

weighted_average_cols = [
"shadow_price_size_term_adjustment",
"shadow_price_utility_adjustment",
Expand All@@ -261,6 +268,24 @@ def aggregate_size_terms(dest_size_terms, network_los):
for c in weighted_average_cols:
TAZ_size_terms[c] /= TAZ_size_terms["size_term"] # weighted average

spc = shadow_pricing.load_shadow_price_calculator(model_settings)
if spc.use_shadow_pricing and (
spc.shadow_settings["SHADOW_PRICE_METHOD"] == "simulation"
):
# allow TAZs with at least one underassigned MAZ in them, therefore with a shadowprice larger than -999, to be selected again
TAZ_size_terms["shadow_price_utility_adjustment"] = np.where(
(TAZ_size_terms["shadow_price_utility_adjustment"] > -999)
& (TAZ_size_terms["avail_MAZ"] > 0),
0,
-999,
)
# now, negative size term means shadow price is -999. Setting size_term to 0 so the prob of that MAZ being selected becomes 0
MAZ_size_terms["size_term"] = np.where(
MAZ_size_terms["shadow_price_utility_adjustment"] < 0,
0,
MAZ_size_terms["size_term"],
)

if TAZ_size_terms.isna().any(axis=None):
logger.warning(
f"TAZ_size_terms with NAN values\n{TAZ_size_terms[TAZ_size_terms.isna().any(axis=1)]}"
Expand DownExpand Up@@ -308,7 +333,9 @@ def location_presample(
alt_dest_col_name = model_settings["ALT_DEST_COL_NAME"]
assert DEST_TAZ != alt_dest_col_name

MAZ_size_terms, TAZ_size_terms = aggregate_size_terms(dest_size_terms, network_los)
MAZ_size_terms, TAZ_size_terms = aggregate_size_terms(
dest_size_terms, network_los, model_settings
)

# convert MAZ zone_id to 'TAZ' in choosers (persons_merged)
# persons_merged[HOME_TAZ] = persons_merged[HOME_MAZ].map(maz_to_taz)
Expand DownExpand Up@@ -856,6 +883,7 @@ def iterate_location_choice(

# chooser segmentation allows different sets coefficients for e.g. different income_segments or tour_types
chooser_segment_column = model_settings["CHOOSER_SEGMENT_COLUMN_NAME"]
segment_ids = model_settings["SEGMENT_IDS"]

assert (
chooser_segment_column in persons_merged_df
Expand All@@ -869,11 +897,20 @@ def iterate_location_choice(

for iteration in range(1, max_iterations + 1):

persons_merged_df_ = persons_merged_df.copy()

if spc.use_shadow_pricing and iteration > 1:
spc.update_shadow_prices()

choices_df, save_sample_df = run_location_choice(
persons_merged_df,
if spc.shadow_settings["SHADOW_PRICE_METHOD"] == "simulation":
# filter from the sampled persons
persons_merged_df_ = persons_merged_df_[
persons_merged_df_.index.isin(spc.sampled_persons.index)
]
persons_merged_df_ = persons_merged_df_.sort_index()

choices_df_, save_sample_df = run_location_choice(
persons_merged_df_,
network_los,
shadow_price_calculator=spc,
want_logsums=logsum_column_name is not None,
Expand All@@ -886,10 +923,35 @@ def iterate_location_choice(
trace_label=tracing.extend_trace_label(trace_label, "i%s" % iteration),
)

# choices_df is a pandas DataFrame with columns 'choice' and (optionally) 'logsum'
if choices_df is None:
# choices_df is a pandas DataFrame with columns "choice" and (optionally) "logsum"
if choices_df_ is None:
break

if spc.use_shadow_pricing:
# handle simulation method
if (
spc.shadow_settings["SHADOW_PRICE_METHOD"] == "simulation"
and iteration > 1
):
# if a process ends up with no sampled workers in it, hence an empty choice_df_, then choice_df wil be what it was previously
if len(choices_df_) == 0:
choices_df = choices_df
else:
choices_df = pd.concat([choices_df, choices_df_], axis=0)
choices_df_index = choices_df_.index.name
choices_df = choices_df.reset_index()
# update choices of workers/students
choices_df = choices_df.drop_duplicates(
subset=[choices_df_index], keep="last"
)
choices_df = choices_df.set_index(choices_df_index)
choices_df = choices_df.sort_index()
else:
choices_df = choices_df_.copy()

else:
choices_df = choices_df_

spc.set_choices(
choices=choices_df["choice"],
segment_ids=persons_merged_df[chooser_segment_column].reindex(
Expand Down
4 changes: 1 addition & 3 deletions activitysim/abm/models/trip_purpose.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,9 +71,7 @@ def choose_intermediate_trip_purpose(

# probs should sum to 1 across rows
sum_probs = probs_spec[purpose_cols].sum(axis=1)
probs_spec.loc[:, purpose_cols] = probs_spec.loc[:, purpose_cols].div(
sum_probs, axis=0
)
probs_spec[purpose_cols] = probs_spec[purpose_cols].div(sum_probs, axis=0)

# left join trips to probs (there may be multiple rows per trip for multiple depart ranges)
choosers = pd.merge(
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b93e6fe
updated scripts to include simulation-based shadow pricing
aletzdy Sep 30, 2022
11600c3
blacken
dhensle Sep 30, 2022
4b9f55e
Updated shadow_pricing.yaml for mtc example
aletzdy Sep 30, 2022
29f893e
Merge branch 'develop_RevisedShadowPricing' of https://github.com/ale…
dhensle Sep 30, 2022
846d3be
code cleanup
dhensle Sep 30, 2022
e2dde11
more cleanup
dhensle Sep 30, 2022
3863396
documentation and passing tests
dhensle Sep 30, 2022
3d1edc7
passing tests
dhensle Sep 30, 2022
c4dc4ea
passing tests
dhensle Oct 1, 2022
23df7b9
updated doc on shadow pricing
aletzdy Oct 3, 2022
4269dd5
2nd Update model doc on shadow pricing
aletzdy Oct 3, 2022
3a87acd
more doc update on shadow pricing
aletzdy Oct 3, 2022
2db5f59
fixing pandas future warning
dhensle Oct 3, 2022
b5768e3
blacken
dhensle Oct 3, 2022
30d67bc
bug in trying to access shadow price settings when not running shadow…
dhensle Oct 3, 2022
a20a396
limiting pandas version
dhensle Oct 3, 2022
4d58a85
always updating choices
dhensle Oct 3, 2022
7c706f7
testing removal of lognormal for hh vot
dhensle Oct 3, 2022
e2e0d9d
putting hh vot back in
dhensle Oct 3, 2022
95d7fd7
updating to match sharrow test versions
dhensle Oct 4, 2022
1ce6d36
raw person table for buffer instead of injectable
dhensle Oct 7, 2022
7167b65
adding segmentation, output by iteration, and external worker removal
dhensle Oct 25, 2022
bce64bd
formatting & documentation
dhensle Oct 27, 2022
ebd2bc8
ensuring TAZ is not selected if no available MAZ
dhensle Nov 4, 2022
aa8d5a3
adding logic to skip external location choice models
dhensle Nov 4, 2022
a79ac7b
consistent multiprocessing results
dhensle Dec 15, 2022
9190535
Merge branch 'develop' into develop_RevisedShadowPricing
dhensle Dec 15, 2022
0d90f87
blacken
dhensle Dec 15, 2022
0898686
Merge branch 'develop_RevisedShadowPricing' of https://github.com/ale…
dhensle Dec 15, 2022
3a78433
updating regression trips
dhensle Dec 15, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 68 additions & 6 deletions activitysim/abm/models/location_choice.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -227,7 +227,7 @@ def location_sample(
DEST_MAZ = "dest_MAZ"


def aggregate_size_terms(dest_size_terms, network_los):
def aggregate_size_terms(dest_size_terms, network_los, model_settings):
#
# aggregate MAZ_size_terms to TAZ_size_terms
#
Expand All@@ -243,6 +243,13 @@ def aggregate_size_terms(dest_size_terms, network_los):
)
MAZ_size_terms[DEST_TAZ] = MAZ_size_terms.index.map(maz_to_taz)

MAZ_size_terms["avail_MAZ"] = np.where(
(MAZ_size_terms.size_term > 0)
& (MAZ_size_terms.shadow_price_utility_adjustment > -999),
1,
0,
)

weighted_average_cols = [
"shadow_price_size_term_adjustment",
"shadow_price_utility_adjustment",
Expand All@@ -261,6 +268,24 @@ def aggregate_size_terms(dest_size_terms, network_los):
for c in weighted_average_cols:
TAZ_size_terms[c] /= TAZ_size_terms["size_term"] # weighted average

spc = shadow_pricing.load_shadow_price_calculator(model_settings)
if spc.use_shadow_pricing and (
spc.shadow_settings["SHADOW_PRICE_METHOD"] == "simulation"
):
# allow TAZs with at least one underassigned MAZ in them, therefore with a shadowprice larger than -999, to be selected again
TAZ_size_terms["shadow_price_utility_adjustment"] = np.where(
(TAZ_size_terms["shadow_price_utility_adjustment"] > -999)
& (TAZ_size_terms["avail_MAZ"] > 0),
0,
-999,
)
# now, negative size term means shadow price is -999. Setting size_term to 0 so the prob of that MAZ being selected becomes 0
MAZ_size_terms["size_term"] = np.where(
MAZ_size_terms["shadow_price_utility_adjustment"] < 0,
0,
MAZ_size_terms["size_term"],
)

if TAZ_size_terms.isna().any(axis=None):
logger.warning(
f"TAZ_size_terms with NAN values\n{TAZ_size_terms[TAZ_size_terms.isna().any(axis=1)]}"
Expand DownExpand Up@@ -308,7 +333,9 @@ def location_presample(
alt_dest_col_name = model_settings["ALT_DEST_COL_NAME"]
assert DEST_TAZ != alt_dest_col_name

MAZ_size_terms, TAZ_size_terms = aggregate_size_terms(dest_size_terms, network_los)
MAZ_size_terms, TAZ_size_terms = aggregate_size_terms(
dest_size_terms, network_los, model_settings
)

# convert MAZ zone_id to 'TAZ' in choosers (persons_merged)
# persons_merged[HOME_TAZ] = persons_merged[HOME_MAZ].map(maz_to_taz)
Expand DownExpand Up@@ -856,6 +883,7 @@ def iterate_location_choice(

# chooser segmentation allows different sets coefficients for e.g. different income_segments or tour_types
chooser_segment_column = model_settings["CHOOSER_SEGMENT_COLUMN_NAME"]
segment_ids = model_settings["SEGMENT_IDS"]

assert (
chooser_segment_column in persons_merged_df
Expand All@@ -869,11 +897,20 @@ def iterate_location_choice(

for iteration in range(1, max_iterations + 1):

persons_merged_df_ = persons_merged_df.copy()

if spc.use_shadow_pricing and iteration > 1:
spc.update_shadow_prices()

choices_df, save_sample_df = run_location_choice(
persons_merged_df,
if spc.shadow_settings["SHADOW_PRICE_METHOD"] == "simulation":
# filter from the sampled persons
persons_merged_df_ = persons_merged_df_[
persons_merged_df_.index.isin(spc.sampled_persons.index)
]
persons_merged_df_ = persons_merged_df_.sort_index()

choices_df_, save_sample_df = run_location_choice(
persons_merged_df_,
network_los,
shadow_price_calculator=spc,
want_logsums=logsum_column_name is not None,
Expand All@@ -886,10 +923,35 @@ def iterate_location_choice(
trace_label=tracing.extend_trace_label(trace_label, "i%s" % iteration),
)

# choices_df is a pandas DataFrame with columns 'choice' and (optionally) 'logsum'
if choices_df is None:
# choices_df is a pandas DataFrame with columns "choice" and (optionally) "logsum"
if choices_df_ is None:
break

if spc.use_shadow_pricing:
# handle simulation method
if (
spc.shadow_settings["SHADOW_PRICE_METHOD"] == "simulation"
and iteration > 1
):
# if a process ends up with no sampled workers in it, hence an empty choice_df_, then choice_df wil be what it was previously
if len(choices_df_) == 0:
choices_df = choices_df
else:
choices_df = pd.concat([choices_df, choices_df_], axis=0)
choices_df_index = choices_df_.index.name
choices_df = choices_df.reset_index()
# update choices of workers/students
choices_df = choices_df.drop_duplicates(
subset=[choices_df_index], keep="last"
)
choices_df = choices_df.set_index(choices_df_index)
choices_df = choices_df.sort_index()
else:
choices_df = choices_df_.copy()

else:
choices_df = choices_df_

spc.set_choices(
choices=choices_df["choice"],
segment_ids=persons_merged_df[chooser_segment_column].reindex(
Expand Down
4 changes: 1 addition & 3 deletions activitysim/abm/models/trip_purpose.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,9 +71,7 @@ def choose_intermediate_trip_purpose(

# probs should sum to 1 across rows
sum_probs = probs_spec[purpose_cols].sum(axis=1)
probs_spec.loc[:, purpose_cols] = probs_spec.loc[:, purpose_cols].div(
sum_probs, axis=0
)
probs_spec[purpose_cols] = probs_spec[purpose_cols].div(sum_probs, axis=0)

# left join trips to probs (there may be multiple rows per trip for multiple depart ranges)
choosers = pd.merge(
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b93e6fe
updated scripts to include simulation-based shadow pricing
aletzdy Sep 30, 2022
11600c3
blacken
dhensle Sep 30, 2022
4b9f55e
Updated shadow_pricing.yaml for mtc example
aletzdy Sep 30, 2022
29f893e
Merge branch 'develop_RevisedShadowPricing' of https://github.com/ale…
dhensle Sep 30, 2022
846d3be
code cleanup
dhensle Sep 30, 2022
e2dde11
more cleanup
dhensle Sep 30, 2022
3863396
documentation and passing tests
dhensle Sep 30, 2022
3d1edc7
passing tests
dhensle Sep 30, 2022
c4dc4ea
passing tests
dhensle Oct 1, 2022
23df7b9
updated doc on shadow pricing
aletzdy Oct 3, 2022
4269dd5
2nd Update model doc on shadow pricing
aletzdy Oct 3, 2022
3a87acd
more doc update on shadow pricing
aletzdy Oct 3, 2022
2db5f59
fixing pandas future warning
dhensle Oct 3, 2022
b5768e3
blacken
dhensle Oct 3, 2022
30d67bc
bug in trying to access shadow price settings when not running shadow…
dhensle Oct 3, 2022
a20a396
limiting pandas version
dhensle Oct 3, 2022
4d58a85
always updating choices
dhensle Oct 3, 2022
7c706f7
testing removal of lognormal for hh vot
dhensle Oct 3, 2022
e2e0d9d
putting hh vot back in
dhensle Oct 3, 2022
95d7fd7
updating to match sharrow test versions
dhensle Oct 4, 2022
1ce6d36
raw person table for buffer instead of injectable
dhensle Oct 7, 2022
7167b65
adding segmentation, output by iteration, and external worker removal
dhensle Oct 25, 2022
bce64bd
formatting & documentation
dhensle Oct 27, 2022
ebd2bc8
ensuring TAZ is not selected if no available MAZ
dhensle Nov 4, 2022
aa8d5a3
adding logic to skip external location choice models
dhensle Nov 4, 2022
a79ac7b
consistent multiprocessing results
dhensle Dec 15, 2022
9190535
Merge branch 'develop' into develop_RevisedShadowPricing
dhensle Dec 15, 2022
0d90f87
blacken
dhensle Dec 15, 2022
0898686
Merge branch 'develop_RevisedShadowPricing' of https://github.com/ale…
dhensle Dec 15, 2022
3a78433
updating regression trips
dhensle Dec 15, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 68 additions & 6 deletions activitysim/abm/models/location_choice.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -227,7 +227,7 @@ def location_sample(
DEST_MAZ = "dest_MAZ"


def aggregate_size_terms(dest_size_terms, network_los):
def aggregate_size_terms(dest_size_terms, network_los, model_settings):
#
# aggregate MAZ_size_terms to TAZ_size_terms
#
Expand All@@ -243,6 +243,13 @@ def aggregate_size_terms(dest_size_terms, network_los):
)
MAZ_size_terms[DEST_TAZ] = MAZ_size_terms.index.map(maz_to_taz)

MAZ_size_terms["avail_MAZ"] = np.where(
(MAZ_size_terms.size_term > 0)
& (MAZ_size_terms.shadow_price_utility_adjustment > -999),
1,
0,
)

weighted_average_cols = [
"shadow_price_size_term_adjustment",
"shadow_price_utility_adjustment",
Expand All@@ -261,6 +268,24 @@ def aggregate_size_terms(dest_size_terms, network_los):
for c in weighted_average_cols:
TAZ_size_terms[c] /= TAZ_size_terms["size_term"] # weighted average

spc = shadow_pricing.load_shadow_price_calculator(model_settings)
if spc.use_shadow_pricing and (
spc.shadow_settings["SHADOW_PRICE_METHOD"] == "simulation"
):
# allow TAZs with at least one underassigned MAZ in them, therefore with a shadowprice larger than -999, to be selected again
TAZ_size_terms["shadow_price_utility_adjustment"] = np.where(
(TAZ_size_terms["shadow_price_utility_adjustment"] > -999)
& (TAZ_size_terms["avail_MAZ"] > 0),
0,
-999,
)
# now, negative size term means shadow price is -999. Setting size_term to 0 so the prob of that MAZ being selected becomes 0
MAZ_size_terms["size_term"] = np.where(
MAZ_size_terms["shadow_price_utility_adjustment"] < 0,
0,
MAZ_size_terms["size_term"],
)

if TAZ_size_terms.isna().any(axis=None):
logger.warning(
f"TAZ_size_terms with NAN values\n{TAZ_size_terms[TAZ_size_terms.isna().any(axis=1)]}"
Expand DownExpand Up@@ -308,7 +333,9 @@ def location_presample(
alt_dest_col_name = model_settings["ALT_DEST_COL_NAME"]
assert DEST_TAZ != alt_dest_col_name

MAZ_size_terms, TAZ_size_terms = aggregate_size_terms(dest_size_terms, network_los)
MAZ_size_terms, TAZ_size_terms = aggregate_size_terms(
dest_size_terms, network_los, model_settings
)

# convert MAZ zone_id to 'TAZ' in choosers (persons_merged)
# persons_merged[HOME_TAZ] = persons_merged[HOME_MAZ].map(maz_to_taz)
Expand DownExpand Up@@ -856,6 +883,7 @@ def iterate_location_choice(

# chooser segmentation allows different sets coefficients for e.g. different income_segments or tour_types
chooser_segment_column = model_settings["CHOOSER_SEGMENT_COLUMN_NAME"]
segment_ids = model_settings["SEGMENT_IDS"]

assert (
chooser_segment_column in persons_merged_df
Expand All@@ -869,11 +897,20 @@ def iterate_location_choice(

for iteration in range(1, max_iterations + 1):

persons_merged_df_ = persons_merged_df.copy()

if spc.use_shadow_pricing and iteration > 1:
spc.update_shadow_prices()

choices_df, save_sample_df = run_location_choice(
persons_merged_df,
if spc.shadow_settings["SHADOW_PRICE_METHOD"] == "simulation":
# filter from the sampled persons
persons_merged_df_ = persons_merged_df_[
persons_merged_df_.index.isin(spc.sampled_persons.index)
]
persons_merged_df_ = persons_merged_df_.sort_index()

choices_df_, save_sample_df = run_location_choice(
persons_merged_df_,
network_los,
shadow_price_calculator=spc,
want_logsums=logsum_column_name is not None,
Expand All@@ -886,10 +923,35 @@ def iterate_location_choice(
trace_label=tracing.extend_trace_label(trace_label, "i%s" % iteration),
)

# choices_df is a pandas DataFrame with columns 'choice' and (optionally) 'logsum'
if choices_df is None:
# choices_df is a pandas DataFrame with columns "choice" and (optionally) "logsum"
if choices_df_ is None:
break

if spc.use_shadow_pricing:
# handle simulation method
if (
spc.shadow_settings["SHADOW_PRICE_METHOD"] == "simulation"
and iteration > 1
):
# if a process ends up with no sampled workers in it, hence an empty choice_df_, then choice_df wil be what it was previously
if len(choices_df_) == 0:
choices_df = choices_df
else:
choices_df = pd.concat([choices_df, choices_df_], axis=0)
choices_df_index = choices_df_.index.name
choices_df = choices_df.reset_index()
# update choices of workers/students
choices_df = choices_df.drop_duplicates(
subset=[choices_df_index], keep="last"
)
choices_df = choices_df.set_index(choices_df_index)
choices_df = choices_df.sort_index()
else:
choices_df = choices_df_.copy()

else:
choices_df = choices_df_

spc.set_choices(
choices=choices_df["choice"],
segment_ids=persons_merged_df[chooser_segment_column].reindex(
Expand Down
4 changes: 1 addition & 3 deletions activitysim/abm/models/trip_purpose.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,9 +71,7 @@ def choose_intermediate_trip_purpose(

# probs should sum to 1 across rows
sum_probs = probs_spec[purpose_cols].sum(axis=1)
probs_spec.loc[:, purpose_cols] = probs_spec.loc[:, purpose_cols].div(
sum_probs, axis=0
)
probs_spec[purpose_cols] = probs_spec[purpose_cols].div(sum_probs, axis=0)

# left join trips to probs (there may be multiple rows per trip for multiple depart ranges)
choosers = pd.merge(
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b93e6fe
updated scripts to include simulation-based shadow pricing
aletzdy Sep 30, 2022
11600c3
blacken
dhensle Sep 30, 2022
4b9f55e
Updated shadow_pricing.yaml for mtc example
aletzdy Sep 30, 2022
29f893e
Merge branch 'develop_RevisedShadowPricing' of https://github.com/ale…
dhensle Sep 30, 2022
846d3be
code cleanup
dhensle Sep 30, 2022
e2dde11
more cleanup
dhensle Sep 30, 2022
3863396
documentation and passing tests
dhensle Sep 30, 2022
3d1edc7
passing tests
dhensle Sep 30, 2022
c4dc4ea
passing tests
dhensle Oct 1, 2022
23df7b9
updated doc on shadow pricing
aletzdy Oct 3, 2022
4269dd5
2nd Update model doc on shadow pricing
aletzdy Oct 3, 2022
3a87acd
more doc update on shadow pricing
aletzdy Oct 3, 2022
2db5f59
fixing pandas future warning
dhensle Oct 3, 2022
b5768e3
blacken
dhensle Oct 3, 2022
30d67bc
bug in trying to access shadow price settings when not running shadow…
dhensle Oct 3, 2022
a20a396
limiting pandas version
dhensle Oct 3, 2022
4d58a85
always updating choices
dhensle Oct 3, 2022
7c706f7
testing removal of lognormal for hh vot
dhensle Oct 3, 2022
e2e0d9d
putting hh vot back in
dhensle Oct 3, 2022
95d7fd7
updating to match sharrow test versions
dhensle Oct 4, 2022
1ce6d36
raw person table for buffer instead of injectable
dhensle Oct 7, 2022
7167b65
adding segmentation, output by iteration, and external worker removal
dhensle Oct 25, 2022
bce64bd
formatting & documentation
dhensle Oct 27, 2022
ebd2bc8
ensuring TAZ is not selected if no available MAZ
dhensle Nov 4, 2022
aa8d5a3
adding logic to skip external location choice models
dhensle Nov 4, 2022
a79ac7b
consistent multiprocessing results
dhensle Dec 15, 2022
9190535
Merge branch 'develop' into develop_RevisedShadowPricing
dhensle Dec 15, 2022
0d90f87
blacken
dhensle Dec 15, 2022
0898686
Merge branch 'develop_RevisedShadowPricing' of https://github.com/ale…
dhensle Dec 15, 2022
3a78433
updating regression trips
dhensle Dec 15, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 68 additions & 6 deletions activitysim/abm/models/location_choice.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -227,7 +227,7 @@ def location_sample(
DEST_MAZ = "dest_MAZ"


def aggregate_size_terms(dest_size_terms, network_los):
def aggregate_size_terms(dest_size_terms, network_los, model_settings):
#
# aggregate MAZ_size_terms to TAZ_size_terms
#
Expand All@@ -243,6 +243,13 @@ def aggregate_size_terms(dest_size_terms, network_los):
)
MAZ_size_terms[DEST_TAZ] = MAZ_size_terms.index.map(maz_to_taz)

MAZ_size_terms["avail_MAZ"] = np.where(
(MAZ_size_terms.size_term > 0)
& (MAZ_size_terms.shadow_price_utility_adjustment > -999),
1,
0,
)

weighted_average_cols = [
"shadow_price_size_term_adjustment",
"shadow_price_utility_adjustment",
Expand All@@ -261,6 +268,24 @@ def aggregate_size_terms(dest_size_terms, network_los):
for c in weighted_average_cols:
TAZ_size_terms[c] /= TAZ_size_terms["size_term"] # weighted average

spc = shadow_pricing.load_shadow_price_calculator(model_settings)
if spc.use_shadow_pricing and (
spc.shadow_settings["SHADOW_PRICE_METHOD"] == "simulation"
):
# allow TAZs with at least one underassigned MAZ in them, therefore with a shadowprice larger than -999, to be selected again
TAZ_size_terms["shadow_price_utility_adjustment"] = np.where(
(TAZ_size_terms["shadow_price_utility_adjustment"] > -999)
& (TAZ_size_terms["avail_MAZ"] > 0),
0,
-999,
)
# now, negative size term means shadow price is -999. Setting size_term to 0 so the prob of that MAZ being selected becomes 0
MAZ_size_terms["size_term"] = np.where(
MAZ_size_terms["shadow_price_utility_adjustment"] < 0,
0,
MAZ_size_terms["size_term"],
)

if TAZ_size_terms.isna().any(axis=None):
logger.warning(
f"TAZ_size_terms with NAN values\n{TAZ_size_terms[TAZ_size_terms.isna().any(axis=1)]}"
Expand DownExpand Up@@ -308,7 +333,9 @@ def location_presample(
alt_dest_col_name = model_settings["ALT_DEST_COL_NAME"]
assert DEST_TAZ != alt_dest_col_name

MAZ_size_terms, TAZ_size_terms = aggregate_size_terms(dest_size_terms, network_los)
MAZ_size_terms, TAZ_size_terms = aggregate_size_terms(
dest_size_terms, network_los, model_settings
)

# convert MAZ zone_id to 'TAZ' in choosers (persons_merged)
# persons_merged[HOME_TAZ] = persons_merged[HOME_MAZ].map(maz_to_taz)
Expand DownExpand Up@@ -856,6 +883,7 @@ def iterate_location_choice(

# chooser segmentation allows different sets coefficients for e.g. different income_segments or tour_types
chooser_segment_column = model_settings["CHOOSER_SEGMENT_COLUMN_NAME"]
segment_ids = model_settings["SEGMENT_IDS"]

assert (
chooser_segment_column in persons_merged_df
Expand All@@ -869,11 +897,20 @@ def iterate_location_choice(

for iteration in range(1, max_iterations + 1):

persons_merged_df_ = persons_merged_df.copy()

if spc.use_shadow_pricing and iteration > 1:
spc.update_shadow_prices()

choices_df, save_sample_df = run_location_choice(
persons_merged_df,
if spc.shadow_settings["SHADOW_PRICE_METHOD"] == "simulation":
# filter from the sampled persons
persons_merged_df_ = persons_merged_df_[
persons_merged_df_.index.isin(spc.sampled_persons.index)
]
persons_merged_df_ = persons_merged_df_.sort_index()

choices_df_, save_sample_df = run_location_choice(
persons_merged_df_,
network_los,
shadow_price_calculator=spc,
want_logsums=logsum_column_name is not None,
Expand All@@ -886,10 +923,35 @@ def iterate_location_choice(
trace_label=tracing.extend_trace_label(trace_label, "i%s" % iteration),
)

# choices_df is a pandas DataFrame with columns 'choice' and (optionally) 'logsum'
if choices_df is None:
# choices_df is a pandas DataFrame with columns "choice" and (optionally) "logsum"
if choices_df_ is None:
break

if spc.use_shadow_pricing:
# handle simulation method
if (
spc.shadow_settings["SHADOW_PRICE_METHOD"] == "simulation"
and iteration > 1
):
# if a process ends up with no sampled workers in it, hence an empty choice_df_, then choice_df wil be what it was previously
if len(choices_df_) == 0:
choices_df = choices_df
else:
choices_df = pd.concat([choices_df, choices_df_], axis=0)
choices_df_index = choices_df_.index.name
choices_df = choices_df.reset_index()
# update choices of workers/students
choices_df = choices_df.drop_duplicates(
subset=[choices_df_index], keep="last"
)
choices_df = choices_df.set_index(choices_df_index)
choices_df = choices_df.sort_index()
else:
choices_df = choices_df_.copy()

else:
choices_df = choices_df_

spc.set_choices(
choices=choices_df["choice"],
segment_ids=persons_merged_df[chooser_segment_column].reindex(
Expand Down
4 changes: 1 addition & 3 deletions activitysim/abm/models/trip_purpose.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,9 +71,7 @@ def choose_intermediate_trip_purpose(

# probs should sum to 1 across rows
sum_probs = probs_spec[purpose_cols].sum(axis=1)
probs_spec.loc[:, purpose_cols] = probs_spec.loc[:, purpose_cols].div(
sum_probs, axis=0
)
probs_spec[purpose_cols] = probs_spec[purpose_cols].div(sum_probs, axis=0)

# left join trips to probs (there may be multiple rows per trip for multiple depart ranges)
choosers = pd.merge(
Expand Down
Loading