@@ -381,9 +381,9 @@ def __init__(self, output_file_path, logger_name=None):
381381 self ._logger = _get_logger (logger_name )
382382 self .output_file_path = output_file_path
383383
384- f = open (self .output_file_path )
385- self ._lines = list (f .readlines ())
386- f . close ()
384+ with open (self .output_file_path , encoding = 'utf-8' ) as f :
385+ self ._lines = list (f .readlines ())
386+ self . _lines_by_category = self . _get_lines_by_category ()
387387
388388 # TODO generic-er result value map
389389
@@ -393,19 +393,26 @@ def __init__(self, output_file_path, logger_name=None):
393393 fields = category_fields [1 ]
394394
395395 self .result [category ] = {}
396+ category_lines = self ._lines_by_category .get (category , [])
397+
396398 for field in fields :
397399 if isinstance (field , _EqualSignDelimitedField ):
398- self .result [category ][field .field_name ] = self ._get_equal_sign_delimited_field (field .field_name )
400+ self .result [category ][field .field_name ] = self ._get_equal_sign_delimited_field (
401+ field .field_name , search_lines = category_lines
402+ )
399403 elif isinstance (field , _UnlabeledStringField ):
400404 self .result [category ][field .field_name ] = self ._get_unlabeled_string_field (
401- field .field_name , field .marker_prefixes
405+ field .field_name , field .marker_prefixes , search_lines = category_lines
402406 )
403407 else :
404408 is_string_field = isinstance (field , _StringValueField )
405409 field_name = field .field_name if is_string_field else field
406410 indent = 4 if category != 'Simulation Metadata' else 1
407411 self .result [category ][field_name ] = self ._get_result_field (
408- field_name , is_string_value_field = is_string_field , min_indentation_spaces = indent
412+ field_name ,
413+ is_string_value_field = is_string_field ,
414+ min_indentation_spaces = indent ,
415+ search_lines = category_lines ,
409416 )
410417
411418 try :
@@ -446,6 +453,35 @@ def __init__(self, output_file_path, logger_name=None):
446453 if self ._get_end_use_option () is not None :
447454 self .result ['metadata' ]['End-Use Option' ] = self ._get_end_use_option ().name
448455
456+ def _get_lines_by_category (self ) -> dict [str , list [str ]]:
457+ """
458+ Parses the raw output file lines into a dictionary where keys are
459+ category headers and values are the lines belonging to that category.
460+ """
461+ lines_by_category = {}
462+ current_category = None
463+ known_headers = list (self ._RESULT_FIELDS_BY_CATEGORY .keys ())
464+
465+ for line in self ._lines :
466+
467+ def get_header_content (h_ : str ) -> str :
468+ if h_ == 'Simulation Metadata' :
469+ return h_
470+ return f'***{ h_ } ***'
471+
472+ # Check if the line is a category header
473+ found_header = next ((h for h in known_headers if get_header_content (h ) == line .strip ()), None )
474+
475+ if found_header :
476+ current_category = found_header
477+ if current_category not in lines_by_category :
478+ lines_by_category [current_category ] = []
479+ elif current_category :
480+ # Append the line to the current category if one has been found
481+ lines_by_category [current_category ].append (line )
482+
483+ return lines_by_category
484+
449485 @property
450486 def direct_use_heat_breakeven_price_USD_per_MMBTU (self ):
451487 summary = self .result ['SUMMARY OF RESULTS' ]
@@ -552,9 +588,18 @@ def _json_fields(self) -> MappingProxyType:
552588 except FileNotFoundError :
553589 return {}
554590
555- def _get_result_field (self , field_name : str , is_string_value_field : bool = False , min_indentation_spaces : int = 4 ):
591+ def _get_result_field (
592+ self ,
593+ field_name : str ,
594+ is_string_value_field : bool = False ,
595+ min_indentation_spaces : int = 4 ,
596+ search_lines : list [str ] | None = None ,
597+ ):
598+ if search_lines is None :
599+ search_lines = self ._lines
600+
556601 # TODO make this less fragile with proper regex
557- matching_lines = set (filter (lambda line : f'{ min_indentation_spaces * " " } { field_name } : ' in line , self . _lines ))
602+ matching_lines = set (filter (lambda line : f'{ min_indentation_spaces * " " } { field_name } : ' in line , search_lines ))
558603
559604 if len (matching_lines ) == 0 :
560605 self ._logger .debug (f'Field not found: { field_name } ' )
@@ -592,14 +637,17 @@ def normalize_spaces(matched_line):
592637
593638 return {'value' : self ._parse_number (str_val , field = f'field "{ field_name } "' ), 'unit' : unit }
594639
595- def _get_equal_sign_delimited_field (self , field_name ):
640+ def _get_equal_sign_delimited_field (self , field_name , search_lines : list [str ] | None = None ):
641+ if search_lines is None :
642+ search_lines = self ._lines
643+
596644 metadata_markers = (
597645 f' { field_name } = ' ,
598646 # Previous versions of GEOPHIRES erroneously included an extra space after the field name so we include
599647 # the pattern for it for backwards compatibility with existing .out files.
600648 f' { field_name } = ' ,
601649 )
602- matching_lines = set (filter (lambda line : any (m in line for m in metadata_markers ), self . _lines ))
650+ matching_lines = set (filter (lambda line : any (m in line for m in metadata_markers ), search_lines ))
603651
604652 if len (matching_lines ) == 0 :
605653 self ._logger .debug (f'Equal sign-delimited field not found: { field_name } ' )
@@ -619,8 +667,13 @@ def _get_equal_sign_delimited_field(self, field_name):
619667 self ._logger .error (f'Unexpected error extracting equal sign-delimited field { field_name } ' ) # Shouldn't happen
620668 return None
621669
622- def _get_unlabeled_string_field (self , field_name : str , marker_prefixes : list [str ]):
623- matching_lines = set (filter (lambda line : any (m in line for m in marker_prefixes ), self ._lines ))
670+ def _get_unlabeled_string_field (
671+ self , field_name : str , marker_prefixes : list [str ], search_lines : list [str ] | None = None
672+ ):
673+ if search_lines is None :
674+ search_lines = self ._lines
675+
676+ matching_lines = set (filter (lambda line : any (m in line for m in marker_prefixes ), search_lines ))
624677
625678 if len (matching_lines ) == 0 :
626679 self ._logger .debug (f'Unlabeled string field not found: { field_name } ' )
0 commit comments