Skip to content

Commit ddd9cec

Browse files
sam cash flow profile csv support
1 parent d5be6f5 commit ddd9cec

File tree

3 files changed

+105
-47
lines changed

3 files changed

+105
-47
lines changed

src/geophires_x_client/geophires_x_result.py

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ def __init__(self, v_u):
458458
v_u = ValueUnit(value_unit)
459459
csv_entries.append([category, field_display, '', v_u.value_display, v_u.unit_display])
460460
else:
461-
if category not in (
461+
if category in (
462462
'POWER GENERATION PROFILE',
463463
'HEAT AND/OR ELECTRICITY EXTRACTION AND GENERATION PROFILE',
464464
'EXTENDED ECONOMIC PROFILE',
@@ -467,26 +467,50 @@ def __init__(self, v_u):
467467
GeophiresXResult.CCUS_PROFILE_LEGACY_NAME,
468468
'S-DAC-GT PROFILE',
469469
):
470-
raise RuntimeError('unexpected category')
471-
472-
for i in range(len(fields[0][1:])):
473-
field_profile = fields[0][i + 1]
474-
unit_split = field_profile.split(' (')
475-
field_display = unit_split[0]
476-
unit_display = ''
477-
if len(unit_split) > 1:
478-
unit_display = unit_split[1].replace(')', '')
479-
for j in range(len(fields[1:])):
480-
year_entry = fields[j + 1]
481-
year = year_entry[0]
482-
profile_year_val = year_entry[i + 1]
483-
csv_entries.append([category, field_display, year, profile_year_val, unit_display])
470+
471+
for i in range(len(fields[0][1:])):
472+
field_profile = fields[0][i + 1]
473+
name_unit_split = field_profile.split(' (')
474+
field_display = name_unit_split[0]
475+
unit_display = ''
476+
if len(name_unit_split) > 1:
477+
unit_display = name_unit_split[1].replace(')', '')
478+
for j in range(len(fields[1:])):
479+
year_entry = fields[j + 1]
480+
year = year_entry[0]
481+
profile_year_val = year_entry[i + 1]
482+
csv_entries.append([category, field_display, year, profile_year_val, unit_display])
483+
elif category == 'SAM CASH FLOW PROFILE':
484+
for row_num in range(len(fields) - 1):
485+
row_idx = row_num + 1
486+
row_data = fields[row_idx]
487+
if len(row_data) > 1:
488+
name_unit_split = GeophiresXResult._get_sam_cash_flow_row_name_unit_split(
489+
fields[row_idx][0]
490+
)
491+
row_name = name_unit_split[0]
492+
unit_display = name_unit_split[1]
493+
for year in range(len(row_data) - 1):
494+
row_datapoint = row_data[year + 1]
495+
csv_entries.append([category, row_name, year, row_datapoint, unit_display])
496+
497+
else:
498+
raise RuntimeError(f'Unexpected category: {category}')
484499

485500
for csv_entry in csv_entries:
486501
w.writerow(csv_entry)
487502

488503
return f.getvalue()
489504

505+
@staticmethod
506+
def _get_sam_cash_flow_row_name_unit_split(first_entry_in_row) -> list[str]:
507+
name_unit_split = [it[::-1] for it in first_entry_in_row[::-1].split('( ', maxsplit=1)][::-1]
508+
if len(name_unit_split) < 2:
509+
name_unit_split.append('')
510+
511+
name_unit_split[1] = name_unit_split[1].replace(')', '')
512+
return name_unit_split
513+
490514
@property
491515
def json_output_file_path(self) -> Path:
492516
return Path(self.output_file_path).with_suffix('.json')
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from geophires_x_client import GeophiresXResult
2+
from tests.base_test_case import BaseTestCase
3+
4+
5+
class GeophiresXResultTestCase(BaseTestCase):
6+
7+
def test_get_sam_cash_flow_row_name_unit_split(self) -> None:
8+
cases = [
9+
('Electricity to grid (kWh)', ['Electricity to grid', 'kWh']),
10+
('Federal tax benefit (liability) ($)', ['Federal tax benefit (liability)', '$']),
11+
('Underwater baskets', ['Underwater baskets', '']),
12+
]
13+
14+
for case in cases:
15+
with self.subTest(msg=case[0]):
16+
actual = GeophiresXResult._get_sam_cash_flow_row_name_unit_split(case[0])
17+
self.assertListEqual(actual, case[1])

tests/test_geophires_x_client.py

Lines changed: 49 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -487,37 +487,6 @@ def test_csv(self):
487487
3. Copy-paste the value of `as_csv` (in Threads & Variables tab in PyCharm) to example1_addons.csv
488488
"""
489489

490-
def assertFileContentsEqual(expected_file_path, actual_file_path, tol=0.01):
491-
with open(expected_file_path, encoding='utf-8') as ef:
492-
expected_lines = ef.readlines()
493-
with open(actual_file_path, encoding='utf-8') as af:
494-
actual_lines = af.readlines()
495-
496-
self.assertEqual(len(expected_lines), len(actual_lines), 'The number of lines in the files do not match.')
497-
498-
for line_index, (expected_line, actual_line) in enumerate(zip(expected_lines, actual_lines), start=1):
499-
expected_parts = expected_line.strip().split(',')
500-
actual_parts = actual_line.strip().split(',')
501-
self.assertEqual(
502-
len(expected_parts),
503-
len(actual_parts),
504-
f'The number of columns in line {line_index} does not match.',
505-
)
506-
for col_index, (expected, actual) in enumerate(zip(expected_parts, actual_parts), start=1):
507-
try:
508-
expected_float = float(expected)
509-
actual_float = float(actual)
510-
self.assertTrue(
511-
abs(expected_float - actual_float) < tol,
512-
f'Float values differ at line {line_index}, column {col_index}: {expected} != {actual}',
513-
)
514-
except ValueError:
515-
self.assertEqual(
516-
expected,
517-
actual,
518-
f'String values differ at line {line_index}, column {col_index}: {expected} != {actual}',
519-
)
520-
521490
def assert_csv_equal(case_report_file_path, expected_csv_file_path):
522491
test_result_path = self._get_test_file_path(case_report_file_path)
523492
result = GeophiresXResult(test_result_path)
@@ -527,7 +496,7 @@ def assert_csv_equal(case_report_file_path, expected_csv_file_path):
527496
result_file = Path(tempfile.gettempdir(), f'test_csv-result_{uuid.uuid1()!s}.csv')
528497
with open(result_file, 'w', newline='', encoding='utf-8') as rf:
529498
rf.write(as_csv)
530-
assertFileContentsEqual(self._get_test_file_path(expected_csv_file_path), result_file)
499+
self.assertCsvFileContentsEqual(self._get_test_file_path(expected_csv_file_path), result_file)
531500

532501
for case in [
533502
('examples/example1_addons.out', 'example1_addons.csv'),
@@ -536,6 +505,54 @@ def assert_csv_equal(case_report_file_path, expected_csv_file_path):
536505
with self.subTest(msg=case[0]):
537506
assert_csv_equal(case[0], case[1])
538507

508+
op_example_file = 'examples/example_overpressure.out'
509+
with self.subTest(msg=op_example_file):
510+
# Ensure overpressure-specific RESERVOIR POWER REQUIRED PROFILES doesn't cause issues
511+
op_result = GeophiresXResult(self._get_test_file_path(op_example_file))
512+
op_csv = op_result.as_csv()
513+
self.assertIsNotNone(op_csv)
514+
515+
sam_example_file = 'examples/example_SAM-single-owner-PPA.out'
516+
with self.subTest(msg=sam_example_file):
517+
sam_result = GeophiresXResult(self._get_test_file_path(sam_example_file))
518+
sam_csv = sam_result.as_csv()
519+
self.assertIsNotNone(sam_csv)
520+
sam_cf_lines = [line.split(',') for line in sam_csv.split('\n') if line.startswith('SAM CASH FLOW PROFILE')]
521+
self.assertGreater(len(sam_cf_lines), 250)
522+
# TODO test more of the content (but not full result given how big/complex it is, which would add undue
523+
# maintenance overhead)
524+
525+
def assertCsvFileContentsEqual(self, expected_file_path, actual_file_path, tol=0.01):
526+
with open(expected_file_path, encoding='utf-8') as ef:
527+
expected_lines = ef.readlines()
528+
with open(actual_file_path, encoding='utf-8') as af:
529+
actual_lines = af.readlines()
530+
531+
self.assertEqual(len(expected_lines), len(actual_lines), 'The number of lines in the files do not match.')
532+
533+
for line_index, (expected_line, actual_line) in enumerate(zip(expected_lines, actual_lines), start=1):
534+
expected_parts = expected_line.strip().split(',')
535+
actual_parts = actual_line.strip().split(',')
536+
self.assertEqual(
537+
len(expected_parts),
538+
len(actual_parts),
539+
f'The number of columns in line {line_index} does not match.',
540+
)
541+
for col_index, (expected, actual) in enumerate(zip(expected_parts, actual_parts), start=1):
542+
try:
543+
expected_float = float(expected)
544+
actual_float = float(actual)
545+
self.assertTrue(
546+
abs(expected_float - actual_float) < tol,
547+
f'Float values differ at line {line_index}, column {col_index}: {expected} != {actual}',
548+
)
549+
except ValueError:
550+
self.assertEqual(
551+
expected,
552+
actual,
553+
f'String values differ at line {line_index}, column {col_index}: {expected} != {actual}',
554+
)
555+
539556
def test_parse_chp_percent_cost_allocation(self):
540557
result = GeophiresXResult(self._get_test_file_path('examples/example3.out'))
541558
self.assertEqual(

0 commit comments

Comments
 (0)