Skip to content

Commit

Permalink
Merge pull request #74 from LDAR-Sim/73-feat-initialize-number-of-leaks
Browse files Browse the repository at this point in the history
73 feat initialize number of leaks
  • Loading branch information
SEAJang committed Jul 18, 2023
2 parents 9cb4ca9 + c28abb8 commit 5fd1a4c
Show file tree
Hide file tree
Showing 8 changed files with 175 additions and 12 deletions.
2 changes: 2 additions & 0 deletions LDAR_Sim/src/default_parameters/p_default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ emissions:
subtype_leak_dist_file: "_placeholder_str_"
units: ["kilogram", "hour"]
NRd: 365
n_init_leaks: "_placeholder_int_"
n_init_days: "_placeholder_int_"
economics:
carbon_price_tonnesCO2e: 40.0
cost_CCUS: 20.0
Expand Down
13 changes: 11 additions & 2 deletions LDAR_Sim/src/initialization/leaks.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,23 @@ def generate_initial_leaks(program, site):
NRd = program['NRd']
LPR = program['emissions']['LPR']

n_leaks = random.binomial(NRd, LPR)
if program['n_init_leaks'] is not None:
n_leaks = program['n_init_leaks']
else:
n_leaks = random.binomial(NRd, LPR)

if program['n_init_days'] is not None:
init_max_days_active = program['n_init_days']
else:
init_max_days_active = NRd

prog_start_date = datetime(*program['start_date'])
initial_site_leaks = []
site.update({'initial_leaks': n_leaks, 'cum_leaks': n_leaks})
leak_count = 0
for leak in range(n_leaks):
leak_count += 1
days_active = random.randint(0, high=NRd)
days_active = random.randint(0, high=init_max_days_active)
leak_start_date = prog_start_date - timedelta(days=days_active)
initial_site_leaks.append(
generate_leak(program, site, leak_start_date, leak_count, days_active))
Expand Down
29 changes: 19 additions & 10 deletions LDAR_Sim/src/out_processing/prog_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,21 +87,30 @@ def generate(sim_results, baseline_program, programs):
leaks['mit_vol_kg'] = leaks['nat_volume_kg'] - leaks['volume_kg']
# Get responsible companies and attribute leak mitigation to them.
leaks['init_detect_by'] = leaks['init_detect_by'].replace([None], 'active')

sim_leaks_by_NRD = agg_flatten(leaks[leaks['init_detect_by'] == 'natural'],
ps_idx,
['volume_kg'],
['sum', 'count'],
prefix="nat_vol",
include_col_name=False, include_agg_name=True)
if not leaks[leaks['init_detect_by'] == 'natural'].empty:
sim_leaks_by_NRD = agg_flatten(leaks[leaks['init_detect_by'] == 'natural'],
ps_idx,
['volume_kg'],
['sum', 'count'],
prefix="nat_vol",
include_col_name=False, include_agg_name=True)

sim_progs = merge(sim_stats_daily, sim_leaks_by_NRD,
how='left', on=["program_name", 'sim'])
else:
# these columns are created by the agg_flatten function call above.
# future work should initialize these columns all in one location instead of changing
# the data strcuture mid way through the code.
sim_progs = sim_stats_daily
sim_progs['nat_vol_sum'] = float('nan')
sim_progs['nat_vol_count'] = float('nan')
sim_progs['emis_nat_perc'] = float('nan')

sim_emis_mit = agg_flatten(leaks, ps_idx,
['mit_vol_kg', 'volume_kg'],
agg_types=['sum'],
include_col_name=True, include_agg_name=True)

sim_progs = merge(sim_stats_daily, sim_leaks_by_NRD,
how='left', on=["program_name", 'sim'])
sim_progs = merge(sim_progs, sim_emis_mit, how='left',
on=["program_name", 'sim'])
sim_progs = merge(sim_progs, sim_sites_count,
Expand All @@ -119,14 +128,14 @@ def generate(sim_results, baseline_program, programs):
sim_progs['emis_nat_perc'] = sim_progs['nat_vol_sum'] / \
sim_progs['volume_kg_sum']
sim_progs.replace([inf, -inf], NaN, inplace=True)

sim_progs = sim_progs.rename(columns={
'cost_day_sum': 'cost', 'nat_vol_count': 'nat_leak_repair_count'})
out_table = sim_progs[[
'program_name', 'sim', 'emis_kg_day_site_med', 'act_leaks_day_site_med',
'mit_vol_tco2e', 'mit_vol_perc', 'cost', 'cost_mit_vol_tco2e',
'nat_leak_repair_count', 'emis_nat_perc'
]]

out_table = agg_flatten(out_table, ['program_name'], agg_types=['mean'],
include_col_name=True, include_agg_name=False)
out_table = out_table.drop(columns=['sim'])
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
""" Fixtures for testing leaks"""

import pytest
from datetime import datetime
from typing import Any, Dict


@pytest.fixture(name="mock_program")
def mock_program_fix():
return {
'subtype_file': None,
'NRd': 10,
'n_init_leaks': None,
'n_init_days': None,
'start_date': (2022, 1, 1),
'emissions': {
'LPR': 0.5,
'leak_file': None,
},
'leak_rate_source': 'sample',
'empirical_leak_rates': [1],

}


@pytest.fixture(name="mock_program_2")
def mock_program_2_fix():
return {
'subtype_file': None,
'NRd': 10,
'n_init_leaks': 1,
'n_init_days': 10,
'start_date': (2022, 1, 1),
'emissions': {
'LPR': 0.5,
'leak_file': None,
},
'leak_rate_source': 'sample',
'empirical_leak_rates': [1],
}


@pytest.fixture(name="mock_site_for_leak_test")
def mock_site_for_leak_test_fix() -> Dict[str, Any]:
return {
'facility_ID': 'test',
'equipment_groups': 1,
'empirical_leak_rates': [1],
'lat': 52.0,
'lon': -114.0,
'leak_rate_source': 'sample',
}


@pytest.fixture(name="mock_site_return_test")
def mock_site_return_test_fix() -> list[Dict[str, Any]]:
return [{
'leak_ID': 'test_0000000001',
'facility_ID': 'test',
'equipment_group': 0,
'rate': 1,
'lat': 52.0,
'lon': -114.0,
'status': 'active',
'days_active': 0,
'volume': None,
'estimated_volume': None,
'estimated_volume_b': None,
'measured_rate': None,
'tagged': False,
'component': 'unknown',
'date_began': datetime(2022, 1, 1, 0, 0),
'day_ts_began': 0,
'estimated_date_began': None,
'date_tagged': None,
'tagged_by_company': None,
'tagged_by_crew': None,
'init_detect_by': None,
'init_detect_date': None,
'requires_shutdown': False,
'date_repaired': None,
'repair_delay': None,
}]
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"""
Module to test generate_initial_leaks
"""

from src.initialization.leaks import generate_initial_leaks
from testing.unit_testing.test_initialization.test_leaks.leak_testing_fixtures import (
mock_site_for_leak_test_fix,
mock_site_return_test_fix,
mock_program_fix,
mock_program_2_fix,
)


def test_042_initialize_leaks(mock_site_for_leak_test, mock_program, mock_site_return_test, mocker):
mocker.patch('src.initialization.leaks.random.binomial', return_value=1)
mocker.patch('src.initialization.leaks.random.randint', return_value=0)

# Call the function under test
result = generate_initial_leaks(mock_program, mock_site_for_leak_test)

# Assert the expected result
assert result == mock_site_return_test


def test_042_initialize_leaks_2(mock_site_for_leak_test, mock_program_2, mock_site_return_test, mocker):
mocker.patch('src.initialization.leaks.random.binomial', return_value=1)
mocker.patch('src.initialization.leaks.random.randint', return_value=0)

# Call the function under test
result = generate_initial_leaks(mock_program_2, mock_site_for_leak_test)

# Assert the expected result
assert result == mock_site_return_test
26 changes: 26 additions & 0 deletions USER_MANUAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -935,6 +935,30 @@ method_labels:

**Notes of caution:** N/A

### n_init_leaks

**Data type:** Integer

**Default input:** N/A

**Description:** The number of leaks present per site in the system at the time of the simulation start date

**Notes on acquisition:** Estimate from empirical data or use previously published value. This value can be calculated by multiplying the n_init_days by LPR.

**Notes of caution:** This will overwrite the original functionality of utilizing NRd and LPR to calculate the number of initial leaks present in the simulation. Additionally, this value is will be set for all sites, and cannot be specified for individual subtypes at this given time.

### n_init_days

**Data type:** Integer

**Default input:** N/A (will be set to NRd if left blank)

**Description:** The number of days the initial leaks could potentially been active for before the simulation started. Recommended to always set this value between 0 and NRd.

**Notes on acquisition:** Known assumptions based on operations.

**Notes of caution:** If value is larger than NRd, the number of leaks present in the initial system could potentially be less than the indicated value.

### NRD

**Data type:** Integer
Expand All @@ -951,6 +975,8 @@ Can alternatively be provided in the ```subtype_file```, which will overwrite wh

The NRd value should be the same for **all** programs

Additionally, NRd is recommended to be always be equal or greater than n_init_days.

### program_name

**Data type:** String
Expand Down
1 change: 1 addition & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[pytest]
python_files = test_*.py
pythonpath = LDAR_Sim/src LDAR_Sim/external_sensors

0 comments on commit 5fd1a4c

Please sign in to comment.