diff --git a/geomagio/Controller.py b/geomagio/Controller.py index 96ebb28c2f5c76274d90418b7a9892c76ab52ed5..0985597c37f0e3ff6912b03eaceb009a6ad0ab96 100644 --- a/geomagio/Controller.py +++ b/geomagio/Controller.py @@ -503,7 +503,7 @@ def get_input_factory(args): input_type = args.input # stream/url arguments if args.input_file is not None: - if input_type in ["netcdf", "miniseed"]: + if input_type in ["netcdf", "miniseed", "imagcdf"]: input_stream = open(args.input_file, "rb") else: input_stream = open(args.input_file, "r") @@ -547,8 +547,6 @@ def get_input_factory(args): locationCode=args.locationcode, **input_factory_args, ) - elif input_type == "imagcdf": - input_factory = ImagCDFFactory(**input_factory_args) else: # stream compatible factories if input_type == "iaga2002": @@ -573,6 +571,8 @@ def get_input_factory(args): input_factory = xml.XMLFactory(**input_factory_args) elif input_type == "covjson": input_factory = covjson.CovJSONFactory(**input_factory_args) + elif input_type == "imagcdf": + input_factory = ImagCDFFactory(**input_factory_args) # wrap stream if input_stream is not None: input_factory = StreamTimeseriesFactory( diff --git a/geomagio/ImagCDFFactory.py b/geomagio/ImagCDFFactory.py index ea94790320d45247416ca1b4957fc66b522aec67..af603201de1773abdfcbe65836f290142e28d590 100644 --- a/geomagio/ImagCDFFactory.py +++ b/geomagio/ImagCDFFactory.py @@ -164,7 +164,7 @@ class ImagCDFFactory(TimeseriesFactory): "Rec_Vary": True, "Var_Type": "zVariable", "Dim_Sizes": [], - "Sparse": "no_sparse", + "Sparse": "no_sparse", # no_sparse because there should not be time gaps. "Compress": 9, "Pad": None, } @@ -424,6 +424,47 @@ class ImagCDFFactory(TimeseriesFactory): timeseries.sort() return timeseries + def parse_string(self, data: str, **kwargs): + """ + Parse ImagCDF binary data into an ObsPy Stream. + + This method writes the provided binary data to a temporary file, + reads the file using `cdflib`, and converts the data into an ObsPy + Stream. + + Parameters + ---------- + data : bytes + Binary data containing ImagCDF content. + + Returns + ------- + Stream + An ObsPy Stream object with the parsed geomagnetic time series data. + + Raises + ------ + TimeseriesFactoryException + If an error occurs while parsing the ImagCDF data. + """ + # Create a temporary file to store the CDF data + with tempfile.NamedTemporaryFile(delete=False, suffix=".cdf") as tmp_file: + tmp_file_name = tmp_file.name + tmp_file.write(data) + + try: + # Read the CDF from the temporary file + cdf = CDFReader(tmp_file_name) + stream = self._read_cdf(cdf) + # no cdf.close() method required + except Exception as e: + raise TimeseriesFactoryException(f"Error parsing ImagCDF data: {e}") + finally: + # Clean up the temporary file + os.remove(tmp_file_name) + + return stream + def _create_global_attributes( self, timeseries: Stream, channels: List[str] ) -> dict: @@ -753,18 +794,12 @@ class ImagCDFFactory(TimeseriesFactory): # If no DEPEND_0, skip this variable as we cannot map times continue - # If we used a DataTimes fallback or similar, ensure we handle it case-insensitively - # and also confirm that time_vars keys are checked properly. - # The ImagCDF can have DataTimes, GeomagneticVectorTimes, etc. - # So try exact match first, if not found, attempt case-insensitive. + # The ImagCDF can have DataTimes, GeomagneticVectorTimes, GeomagneticScalarTimes, TemperatureNTimes (for N > 0), etc. matched_time_key = None for tkey in time_vars.keys(): if tkey == ts_name: matched_time_key = tkey break - if tkey.lower() == ts_name.lower(): - matched_time_key = tkey - break if matched_time_key not in time_vars: # If we cannot find the matching time variable, skip this variable