From 82befe4ace95997929a8cc181df888f58034f047 Mon Sep 17 00:00:00 2001 From: pgbrodrick Date: Fri, 21 Jan 2022 10:27:11 -0800 Subject: [PATCH 01/47] ummg updates --- emit_utils/daac_converter.py | 135 +++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index 1454126..18b6e20 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -13,6 +13,7 @@ from osgeo import gdal, osr from spectral.io import envi from typing import List +import json from emit_utils.file_checks import envi_header @@ -202,6 +203,140 @@ def makeGlobalAttr(nc_ds: netCDF4.Dataset, primary_envi_file: str, glt_envi_file nc_ds.sync() # flush +def get_required_ummg(): + """ Get the required UMMG base dictionary + + Returns: + ummg: dictionary with required parameters + + """ + ummg = {} + ummg['MetadataSpecification'] = {} + ummg['GranuleUR'] = '' + ummg['ProviderDates'] = [] + ummg['CollectionReference'] = '' + return ummg + + +def initialize_ummg(granule_name: str, creation_time: str, collection_name: str, collection_version: str = "1.0"): + """ Initialize a UMMG metadata output file + Args: + granule_name: granule UR tag + creation_time: creation timestamp + collection_name: short name of collection reference + collection_version: collection version + + Returns: + none + """ + + ummg = get_required_ummg() + ummg['MetadataSpecification'] = {'URL': 'https://cdn.earthdata.nasa.gov/umm/granule/v1.6.3', 'Name': 'UMM-G', + 'Version': '1.6.3'} + ummg['Platforms'] = {'ShortName': 'ISS', 'Instruments': {'ShortName': 'EMIT'} } + ummg['GranuleUR'] = granule_name + ummg['ProviderDates'].append({'Date': creation_time, 'Type': "Insert"}) + ummg['AdditionalAttributes'] = [{'Name': 'SPATIAL_RESOLUTION', 'Values': ["60.0"]}] + ummg['CollectionReference'] = { + "ShortName": collection_name, + "Version": collection_version + }, + + +def dump_json(json_content: dict, filename: str): + """ + Dump the dictionary to an output json file + Args: + json_content: dictionary to write out + filename: output filename to write to + """ + + with open(filename, errors='ignore') as fout: + fout.write(json.dumps(json_content, indent=2, sort_keys=False)) + + +def add_boundary_ummg(ummg: dict, boundary_points: list): + """ + Add boundary points list to UMMG in correct format + Args: + ummg: existing UMMG to augment + boundary_points: list of lists, each major list entry is a pair of (lon, lat) coordinates + + Returns: + dictionary representation of ummg + """ + + hsd = {"Geometry": {"GPolygons": [{"Boundary": {"Points": []}}]}} + for point in boundary_points: + hsd['HorizontalSpatialDomain']['Geometry']['GPolygons'][0]['Boundary']['Points'].append( + {'Longitude': point[0], 'Latitude': point[1]}) + + ummg['HorizontalSpatialDomain'] = hsd + return ummg + + +def add_data_file_ummg(ummg: dict, data_file_name: str, format: str ='netCDF-4'): + """ + Add boundary points list to UMMG in correct format + Args: + ummg: existing UMMG to augment + data_file_name: path to existing data file to add + + Returns: + dictionary representation of ummg with new data granule + """ + + ummg['DataGranule'] = { + 'ArchiveAndDistributionInformation': [{ + "Name": os.path.basename(data_file_name), + "SizeInBytes": os.path.getsize(data_file_name), + "Format": format, + "Checksum": { + 'Value': calc_checksum(data_file_name), + 'Algorithm': 'sha512' + } + }] + } + return ummg + + + +def write_ummg(output_filename: str, ummg: dict): + """ + Write UMMG file to disk + Args: + output_filename: destination to write file to + ummg: dictionary to write out + + Returns: + none + """ + errors = check_ummg() + if len(errors) > 0: + return errors + + with open(output_filename, errors='ignore') as fout: + fout.write(json.dumps(ummg, indent=2, sort_keys=False)) + + +def check_ummg(ummg: dict): + """ + Args: + ummg: dict to check for UMMG format + + Returns: + error: list of errors + + """ + error_list = [] + base_ummg = get_required_ummg() + for key in base_ummg.keys(): + if key not in ummg.keys() or isinstance(type(base_ummg[key]), type(ummg[key])) is False: + error_list.append(f'Key {key} missing or formatted incorrectly') + + return error_list + + def calc_checksum(path, hash_alg="sha512"): checksum = {} if hash_alg.lower() == "sha512": From 6a29a4b8fc37727becff1ff7582a2f1594a35f02 Mon Sep 17 00:00:00 2001 From: Phil Brodrick Date: Fri, 21 Jan 2022 12:19:29 -0800 Subject: [PATCH 02/47] bug fixes, ummg working now --- emit_utils/daac_converter.py | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index 18b6e20..4f3fe15 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -14,6 +14,7 @@ from spectral.io import envi from typing import List import json +import numpy as np from emit_utils.file_checks import envi_header @@ -227,7 +228,7 @@ def initialize_ummg(granule_name: str, creation_time: str, collection_name: str, collection_version: collection version Returns: - none + dictionary representation of ummg """ ummg = get_required_ummg() @@ -240,7 +241,22 @@ def initialize_ummg(granule_name: str, creation_time: str, collection_name: str, ummg['CollectionReference'] = { "ShortName": collection_name, "Version": collection_version - }, + } + return ummg + + + +class SerialEncoder(json.JSONEncoder): + """Encoder for json to help ensure json objects can be passed to the workflow manager. + """ + + def default(self, obj): + if isinstance(obj, np.integer): + return int(obj) + elif isinstance(obj, np.floating): + return float(obj) + else: + return super(SerialEncoder, self).default(obj) def dump_json(json_content: dict, filename: str): @@ -251,8 +267,8 @@ def dump_json(json_content: dict, filename: str): filename: output filename to write to """ - with open(filename, errors='ignore') as fout: - fout.write(json.dumps(json_content, indent=2, sort_keys=False)) + with open(filename, 'w', errors='ignore') as fout: + fout.write(json.dumps(json_content, indent=2, sort_keys=False, cls=SerialEncoder)) def add_boundary_ummg(ummg: dict, boundary_points: list): From 7f15dfe331f14e57554def4d3c46612adc5e1d24 Mon Sep 17 00:00:00 2001 From: pgbrodrick Date: Wed, 26 Jan 2022 21:54:22 -0800 Subject: [PATCH 03/47] changes to ummg based on daac upload attempt results --- emit_utils/daac_converter.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index 4f3fe15..f2255a6 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -219,7 +219,7 @@ def get_required_ummg(): return ummg -def initialize_ummg(granule_name: str, creation_time: str, collection_name: str, collection_version: str = "1.0"): +def initialize_ummg(granule_name: str, creation_time: str, collection_name: str, collection_version: str = "001"): """ Initialize a UMMG metadata output file Args: granule_name: granule UR tag @@ -287,16 +287,21 @@ def add_boundary_ummg(ummg: dict, boundary_points: list): hsd['HorizontalSpatialDomain']['Geometry']['GPolygons'][0]['Boundary']['Points'].append( {'Longitude': point[0], 'Latitude': point[1]}) + # For GPolygon, add the first point again to close out + hsd['HorizontalSpatialDomain']['Geometry']['GPolygons'][0]['Boundary']['Points'].append( + {'Longitude': boundary_points[0][0], 'Latitude': boundary_points[0][1]}) + ummg['HorizontalSpatialDomain'] = hsd return ummg -def add_data_file_ummg(ummg: dict, data_file_name: str, format: str ='netCDF-4'): +def add_data_file_ummg(ummg: dict, data_file_name: str, file_format: str ='NETCDF-4'): """ Add boundary points list to UMMG in correct format Args: ummg: existing UMMG to augment data_file_name: path to existing data file to add + file_format: description of file type Returns: dictionary representation of ummg with new data granule @@ -306,17 +311,16 @@ def add_data_file_ummg(ummg: dict, data_file_name: str, format: str ='netCDF-4') 'ArchiveAndDistributionInformation': [{ "Name": os.path.basename(data_file_name), "SizeInBytes": os.path.getsize(data_file_name), - "Format": format, + "Format": file_format, "Checksum": { 'Value': calc_checksum(data_file_name), - 'Algorithm': 'sha512' + 'Algorithm': 'SHA-512' } }] } return ummg - def write_ummg(output_filename: str, ummg: dict): """ Write UMMG file to disk From dc7b4e491f4dc88859ad6964efe6cf18e933b298 Mon Sep 17 00:00:00 2001 From: pgbrodrick Date: Wed, 26 Jan 2022 22:02:49 -0800 Subject: [PATCH 04/47] move datetime conversion to with the ummg initialization --- emit_utils/daac_converter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index f2255a6..0c4f987 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -219,7 +219,7 @@ def get_required_ummg(): return ummg -def initialize_ummg(granule_name: str, creation_time: str, collection_name: str, collection_version: str = "001"): +def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: str, collection_version: str = "001"): """ Initialize a UMMG metadata output file Args: granule_name: granule UR tag @@ -236,7 +236,7 @@ def initialize_ummg(granule_name: str, creation_time: str, collection_name: str, 'Version': '1.6.3'} ummg['Platforms'] = {'ShortName': 'ISS', 'Instruments': {'ShortName': 'EMIT'} } ummg['GranuleUR'] = granule_name - ummg['ProviderDates'].append({'Date': creation_time, 'Type': "Insert"}) + ummg['ProviderDates'].append({'Date': creation_time.strftime("%Y-%m-%dT%H:%M:%SZ"), 'Type': "Insert"}) ummg['AdditionalAttributes'] = [{'Name': 'SPATIAL_RESOLUTION', 'Values': ["60.0"]}] ummg['CollectionReference'] = { "ShortName": collection_name, From dab52bf55499d287a408f23d616e7efd1e4fbb2f Mon Sep 17 00:00:00 2001 From: pgbrodrick Date: Thu, 27 Jan 2022 08:47:59 -0800 Subject: [PATCH 05/47] spatial extent format update --- emit_utils/daac_converter.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index 0c4f987..124a860 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -245,7 +245,6 @@ def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: return ummg - class SerialEncoder(json.JSONEncoder): """Encoder for json to help ensure json objects can be passed to the workflow manager. """ @@ -282,16 +281,25 @@ def add_boundary_ummg(ummg: dict, boundary_points: list): dictionary representation of ummg """ - hsd = {"Geometry": {"GPolygons": [{"Boundary": {"Points": []}}]}} + + formatted_points_list = [] for point in boundary_points: - hsd['HorizontalSpatialDomain']['Geometry']['GPolygons'][0]['Boundary']['Points'].append( - {'Longitude': point[0], 'Latitude': point[1]}) + formatted_points_list.append({'Longitude': point[0], 'Latitude': point[1]}) # For GPolygon, add the first point again to close out - hsd['HorizontalSpatialDomain']['Geometry']['GPolygons'][0]['Boundary']['Points'].append( - {'Longitude': boundary_points[0][0], 'Latitude': boundary_points[0][1]}) + formatted_points_list.append({'Longitude': boundary_points[0][0], 'Latitude': boundary_points[0][1]}) + + hsd = {"HorizontalSpatialDomain": + [{"Geometry": + {"GPolygons": [ + {'Boundary': + {'Points': formatted_points_list}} + ]} + }] + } + - ummg['HorizontalSpatialDomain'] = hsd + ummg['SpatialExtent'] = hsd return ummg From 003655ab7997524fcc7c99a5b64d6a506ab77709 Mon Sep 17 00:00:00 2001 From: pgbrodrick Date: Thu, 27 Jan 2022 09:12:16 -0800 Subject: [PATCH 06/47] update data granule metadata --- emit_utils/daac_converter.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index 124a860..b683861 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -234,10 +234,12 @@ def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: ummg = get_required_ummg() ummg['MetadataSpecification'] = {'URL': 'https://cdn.earthdata.nasa.gov/umm/granule/v1.6.3', 'Name': 'UMM-G', 'Version': '1.6.3'} - ummg['Platforms'] = {'ShortName': 'ISS', 'Instruments': {'ShortName': 'EMIT'} } + + # + #ummg['Platforms'] = {'ShortName': 'ISS', 'Instruments': {'ShortName': 'EMIT'} } + #ummg['AdditionalAttributes'] = [{'Name': 'SPATIAL_RESOLUTION', 'Values': ["60.0"]}] ummg['GranuleUR'] = granule_name ummg['ProviderDates'].append({'Date': creation_time.strftime("%Y-%m-%dT%H:%M:%SZ"), 'Type': "Insert"}) - ummg['AdditionalAttributes'] = [{'Name': 'SPATIAL_RESOLUTION', 'Values': ["60.0"]}] ummg['CollectionReference'] = { "ShortName": collection_name, "Version": collection_version @@ -314,6 +316,11 @@ def add_data_file_ummg(ummg: dict, data_file_name: str, file_format: str ='NETCD Returns: dictionary representation of ummg with new data granule """ + prod_datetime_str = None + for subdict in ummg['ProviderDates']: + if subdict['Type'] == 'Insert': + prod_datetime_str = subdict['Date'] + break ummg['DataGranule'] = { 'ArchiveAndDistributionInformation': [{ @@ -326,6 +333,9 @@ def add_data_file_ummg(ummg: dict, data_file_name: str, file_format: str ='NETCD } }] } + if prod_datetime_str is not None: + ummg['DataGranule']['ProductionDateTime'] = prod_datetime_str + return ummg From 86d8a514be1c013353a39bbdd2c44034f4eb9088 Mon Sep 17 00:00:00 2001 From: pgbrodrick Date: Thu, 27 Jan 2022 09:15:10 -0800 Subject: [PATCH 07/47] add daynight flag --- emit_utils/daac_converter.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index b683861..7c62762 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -305,7 +305,7 @@ def add_boundary_ummg(ummg: dict, boundary_points: list): return ummg -def add_data_file_ummg(ummg: dict, data_file_name: str, file_format: str ='NETCDF-4'): +def add_data_file_ummg(ummg: dict, data_file_name: str, daynight: str, file_format: str ='NETCDF-4'): """ Add boundary points list to UMMG in correct format Args: @@ -323,6 +323,7 @@ def add_data_file_ummg(ummg: dict, data_file_name: str, file_format: str ='NETCD break ummg['DataGranule'] = { + 'DayNightFlag': daynight, 'ArchiveAndDistributionInformation': [{ "Name": os.path.basename(data_file_name), "SizeInBytes": os.path.getsize(data_file_name), From 0aeff2d92d5e3595e01188e7ed64f79b98eeab75 Mon Sep 17 00:00:00 2001 From: Philip G Brodrick Date: Thu, 27 Jan 2022 16:00:34 -0800 Subject: [PATCH 08/47] Update README.md --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8222203..605f619 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ # emit-utils -Welcome to the EMIT utils science data system repository. To understand how this repository is linked to the rest of the emit-sds repositories, please see [the repository guide](https://github.jpl.nasa.gov/emit-sds/emit-main/wiki/Repository-Guide). +_NOTE - at this time the EMIT repositories are not supporting Pull Requests from members outside of the EMIT-SDS Team. This is expected to change in March, and guidance on branches will be provided at that time. At present, public migration of this repository is a work-in-progress, and not all features are yet fully up to date. See the **develop** branch - set as default - for the latest code._ + +Welcome to the EMIT utils science data system repository. To understand how this repository is linked to the rest of the emit-sds repositories, please see [the repository guide](https://github.com/emit-sds/emit-main/wiki/Repository-Guide). + +The emit utils repository provides general convenience utilities used broadly throughout the emit-sds. From 3334001cecb4ad368c9a120c9193846b4652d280 Mon Sep 17 00:00:00 2001 From: Philip G Brodrick Date: Thu, 27 Jan 2022 16:01:40 -0800 Subject: [PATCH 09/47] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 605f619..7b8807e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# emit-utils +

emit-utils

_NOTE - at this time the EMIT repositories are not supporting Pull Requests from members outside of the EMIT-SDS Team. This is expected to change in March, and guidance on branches will be provided at that time. At present, public migration of this repository is a work-in-progress, and not all features are yet fully up to date. See the **develop** branch - set as default - for the latest code._ From ab412fb15db3a0c2ff5a74d69fd150cc3795843f Mon Sep 17 00:00:00 2001 From: Philip G Brodrick Date: Thu, 27 Jan 2022 16:02:03 -0800 Subject: [PATCH 10/47] Update README.md --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8222203..7b8807e 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ -# emit-utils +

emit-utils

-Welcome to the EMIT utils science data system repository. To understand how this repository is linked to the rest of the emit-sds repositories, please see [the repository guide](https://github.jpl.nasa.gov/emit-sds/emit-main/wiki/Repository-Guide). +_NOTE - at this time the EMIT repositories are not supporting Pull Requests from members outside of the EMIT-SDS Team. This is expected to change in March, and guidance on branches will be provided at that time. At present, public migration of this repository is a work-in-progress, and not all features are yet fully up to date. See the **develop** branch - set as default - for the latest code._ + +Welcome to the EMIT utils science data system repository. To understand how this repository is linked to the rest of the emit-sds repositories, please see [the repository guide](https://github.com/emit-sds/emit-main/wiki/Repository-Guide). + +The emit utils repository provides general convenience utilities used broadly throughout the emit-sds. From 58c553e2962431bc805a7ff617cf6c211eed913d Mon Sep 17 00:00:00 2001 From: Philip G Brodrick Date: Thu, 27 Jan 2022 16:03:48 -0800 Subject: [PATCH 11/47] Update README.md --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7b8807e..0e10778 100644 --- a/README.md +++ b/README.md @@ -4,4 +4,9 @@ _NOTE - at this time the EMIT repositories are not supporting Pull Requests from Welcome to the EMIT utils science data system repository. To understand how this repository is linked to the rest of the emit-sds repositories, please see [the repository guide](https://github.com/emit-sds/emit-main/wiki/Repository-Guide). -The emit utils repository provides general convenience utilities used broadly throughout the emit-sds. +The emit utils repository provides general convenience utilities used broadly throughout the emit-sds. This repository can be installed locally by: + +``` +git clone git@github.com:emit-sds/emit-utils.git +pip install --editable git@github.com:emit-sds/emit-utils.git +``` From 121e7e386af5cf1c4d4eacf7cb1096e91589a07d Mon Sep 17 00:00:00 2001 From: pgbrodrick Date: Thu, 27 Jan 2022 16:05:24 -0800 Subject: [PATCH 12/47] add license file --- LICENSE | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. From c761072bf3628e0431801a894c3b067f7d28b458 Mon Sep 17 00:00:00 2001 From: pgbrodrick Date: Thu, 27 Jan 2022 16:29:20 -0800 Subject: [PATCH 13/47] remove list outer layer for ummg spatial domain --- emit_utils/daac_converter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index 7c62762..c728f4e 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -292,12 +292,12 @@ def add_boundary_ummg(ummg: dict, boundary_points: list): formatted_points_list.append({'Longitude': boundary_points[0][0], 'Latitude': boundary_points[0][1]}) hsd = {"HorizontalSpatialDomain": - [{"Geometry": + {"Geometry": {"GPolygons": [ {'Boundary': {'Points': formatted_points_list}} ]} - }] + } } From 7d7d404a3e5a9ba622354aac1adb606474412e67 Mon Sep 17 00:00:00 2001 From: Winston Olson-Duvall Date: Mon, 31 Jan 2022 11:58:53 -0800 Subject: [PATCH 14/47] Change setup version to 0.4.0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 927eec6..e65e063 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ setup(name='emit_utils', packages=find_packages(), include_package_data=True, - version='0.2.0', + version='0.4.0', install_requires=[ 'gdal>=2.0', 'spectral>=0.21', From aa75861c7daf8e3c4fb9a22327355a38aacd9e7b Mon Sep 17 00:00:00 2001 From: Winston Olson-Duvall Date: Mon, 31 Jan 2022 11:59:55 -0800 Subject: [PATCH 15/47] Update changelog for v0.4.0 --- CHANGELOG.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 69a0dc5..7872260 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,15 +4,25 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [v0.4.0](https://github.jpl.nasa.gov/emit-sds/emit-utils/compare/v0.3.0...v0.4.0) + +> 31 January 2022 + +- Ummg file creation [`#6`](https://github.jpl.nasa.gov/emit-sds/emit-utils/pull/6) +- Change setup version to 0.4.0 [`7d7d404`](https://github.jpl.nasa.gov/emit-sds/emit-utils/commit/7d7d404a3e5a9ba622354aac1adb606474412e67) +- Resolve conflict [`88aa674`](https://github.jpl.nasa.gov/emit-sds/emit-utils/commit/88aa674c2adce357a61cae0a2e9fcf505f12e9d2) +- add license file [`121e7e3`](https://github.jpl.nasa.gov/emit-sds/emit-utils/commit/121e7e386af5cf1c4d4eacf7cb1096e91589a07d) + #### [v0.3.0](https://github.jpl.nasa.gov/emit-sds/emit-utils/compare/v0.2.0...v0.3.0) -> 29 December 2021 +> 20 January 2022 +- Merge develop for release 0.3.0 [`#5`](https://github.jpl.nasa.gov/emit-sds/emit-utils/pull/5) - Daac interface [`#4`](https://github.jpl.nasa.gov/emit-sds/emit-utils/pull/4) - Netcdf [`#3`](https://github.jpl.nasa.gov/emit-sds/emit-utils/pull/3) - adds netcdf converter basics, still needs a few updates [`36e4a58`](https://github.jpl.nasa.gov/emit-sds/emit-utils/commit/36e4a58dce35d88b3ffafb217d9243e39ed5b1ec) +- Add changelog [`5d4f786`](https://github.jpl.nasa.gov/emit-sds/emit-utils/commit/5d4f786868c3b3dcb5bdd78a932ef95b63177c9c) - Add requirements to setup file based on import statements. Add calc_checksum function that defaults to sha512 checksum, but can be augmented to include others. [`30677d8`](https://github.jpl.nasa.gov/emit-sds/emit-utils/commit/30677d8cf8bdda89f32cb23252826e95c100a72d) -- update elevation naming, add day/night checker [`bf99a31`](https://github.jpl.nasa.gov/emit-sds/emit-utils/commit/bf99a317184f79e6cc3478b04375177c757ce4b1) #### [v0.2.0](https://github.jpl.nasa.gov/emit-sds/emit-utils/compare/v0.1.0...v0.2.0) From b4695512a9276bf79f6e1435fb59e66c547f320e Mon Sep 17 00:00:00 2001 From: pgbrodrick Date: Tue, 8 Feb 2022 01:51:59 -0800 Subject: [PATCH 16/47] break out metadata specs for easy att use --- emit_utils/daac_converter.py | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index c728f4e..3e28a12 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -131,19 +131,15 @@ def makeDims(nc_ds: netCDF4.Dataset, primary_envi_file: str, glt_envi_file: str nc_ds.sync() -def makeGlobalAttr(nc_ds: netCDF4.Dataset, primary_envi_file: str, glt_envi_file: str = None): +def makeGlobalAttrBase(nc_ds: netCDF4.Dataset): """ - Set up global attributes that are universal. Required attributes that should be populated by individual PGEs - are flagged with None values + Set up global attributes that are universal, without any primary files. + Required attributes that should be populated by individual PGEs are flagged with None values Args: nc_ds: mutable netcdf dataset to be updated - primary_envi_file: envi dataset (bil, bip, or bsq format) that can be read for key metadata - glt_envi_file: envi dataset (bil, bip, or bsq format) that can be read for key metadata Returns: """ - primary_ds = envi.open(envi_header(primary_envi_file)) - # required and highly recommended nc_ds.ncei_template_version = "NCEI_NetCDF_Swath_Template_v2.0" # required by cheatsheet nc_ds.title = "EMIT L1B At-Sensor Calibrated Radiance and Geolocation Data Swath, 72km, V001" @@ -183,6 +179,26 @@ def makeGlobalAttr(nc_ds: netCDF4.Dataset, primary_envi_file: str, glt_envi_file #nc_ds.processing_level = "XXXX TO BE UPDATED" + nc_ds.sync() # flush + + + + +def makeGlobalAttr(nc_ds: netCDF4.Dataset, primary_envi_file: str, glt_envi_file: str = None): + """ + Set up global attributes that are universal. Required attributes that should be populated by individual PGEs + are flagged with None values + Args: + nc_ds: mutable netcdf dataset to be updated + primary_envi_file: envi dataset (bil, bip, or bsq format) that can be read for key metadata + glt_envi_file: envi dataset (bil, bip, or bsq format) that can be read for key metadata + Returns: + """ + + makeGlobalAttrBase(nc_ds) + + primary_ds = envi.open(envi_header(primary_envi_file)) + nc_ds.flight_line = os.path.basename(primary_envi_file)[:31] nc_ds.time_coverage_start = primary_ds.metadata['emit acquisition start time'] From 7a47a2a93405fe3c4e9a2bc06aa4a1aac4dd84c1 Mon Sep 17 00:00:00 2001 From: Winston Olson-Duvall Date: Wed, 9 Feb 2022 09:41:20 -0800 Subject: [PATCH 17/47] Increment version to 1.0.0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index e65e063..1839fb1 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ setup(name='emit_utils', packages=find_packages(), include_package_data=True, - version='0.4.0', + version='1.0.0', install_requires=[ 'gdal>=2.0', 'spectral>=0.21', From cd3058bbc12754a0e34f928d92bd67f53bf06f70 Mon Sep 17 00:00:00 2001 From: Winston Olson-Duvall Date: Wed, 9 Feb 2022 09:42:11 -0800 Subject: [PATCH 18/47] Update changelog --- CHANGELOG.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7872260..37840c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,14 +4,22 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +### [v1.0.0](https://github.jpl.nasa.gov/emit-sds/emit-utils/compare/v0.4.0...v1.0.0) + +> 9 February 2022 + +- break out metadata specs for easy att use [`b469551`](https://github.jpl.nasa.gov/emit-sds/emit-utils/commit/b4695512a9276bf79f6e1435fb59e66c547f320e) +- Increment version to 1.0.0 [`7a47a2a`](https://github.jpl.nasa.gov/emit-sds/emit-utils/commit/7a47a2a93405fe3c4e9a2bc06aa4a1aac4dd84c1) + #### [v0.4.0](https://github.jpl.nasa.gov/emit-sds/emit-utils/compare/v0.3.0...v0.4.0) > 31 January 2022 +- Merge develop into main for v0.4.0 [`#7`](https://github.jpl.nasa.gov/emit-sds/emit-utils/pull/7) - Ummg file creation [`#6`](https://github.jpl.nasa.gov/emit-sds/emit-utils/pull/6) +- Update changelog for v0.4.0 [`aa75861`](https://github.jpl.nasa.gov/emit-sds/emit-utils/commit/aa75861c7daf8e3c4fb9a22327355a38aacd9e7b) - Change setup version to 0.4.0 [`7d7d404`](https://github.jpl.nasa.gov/emit-sds/emit-utils/commit/7d7d404a3e5a9ba622354aac1adb606474412e67) - Resolve conflict [`88aa674`](https://github.jpl.nasa.gov/emit-sds/emit-utils/commit/88aa674c2adce357a61cae0a2e9fcf505f12e9d2) -- add license file [`121e7e3`](https://github.jpl.nasa.gov/emit-sds/emit-utils/commit/121e7e386af5cf1c4d4eacf7cb1096e91589a07d) #### [v0.3.0](https://github.jpl.nasa.gov/emit-sds/emit-utils/compare/v0.2.0...v0.3.0) From c34c7757423e084b0ac750e66e95e72f7a012465 Mon Sep 17 00:00:00 2001 From: Phil Brodrick Date: Fri, 1 Apr 2022 09:09:30 -0700 Subject: [PATCH 19/47] remove ipdb --- emit_utils/file_checks.py | 1 - 1 file changed, 1 deletion(-) diff --git a/emit_utils/file_checks.py b/emit_utils/file_checks.py index 1181057..bec96ab 100644 --- a/emit_utils/file_checks.py +++ b/emit_utils/file_checks.py @@ -38,7 +38,6 @@ def check_files_exist(file_list: np.array): anybad = False for file in file_list: if os.path.isfile(file) is False: - import ipdb; ipdb.set_trace() logging.error('File: {} does not exist'.format(file)) anybad = True From df67dd6812280c40941a15b386f1c2772e84d715 Mon Sep 17 00:00:00 2001 From: pgbrodrick Date: Fri, 1 Apr 2022 09:58:33 -0700 Subject: [PATCH 20/47] updates for geospatial info from glts --- emit_utils/daac_converter.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index 3e28a12..4c2a39f 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -53,7 +53,8 @@ def add_variable(nc_ds, nc_name, data_type, long_name, units, data, kargs): kargs['fill_value'] = NODATA nc_var = nc_ds.createVariable(nc_name, data_type, **kargs) - nc_var.long_name = long_name + if long_name is not None: + nc_var.long_name = long_name if units is not None: nc_var.units = units @@ -142,7 +143,6 @@ def makeGlobalAttrBase(nc_ds: netCDF4.Dataset): # required and highly recommended nc_ds.ncei_template_version = "NCEI_NetCDF_Swath_Template_v2.0" # required by cheatsheet - nc_ds.title = "EMIT L1B At-Sensor Calibrated Radiance and Geolocation Data Swath, 72km, V001" nc_ds.summary = "The Earth Surface Mineral Dust Source Investigation (EMIT) is an Earth Ventures-Instrument (EVI-4) \ Mission that maps the surface mineralogy of arid dust source regions via imaging spectroscopy in the visible and \ short-wave infrared (VSWIR). Installed on the International Space Station (ISS), the EMIT instrument is a Dyson \ @@ -215,6 +215,10 @@ def makeGlobalAttr(nc_ds: netCDF4.Dataset, primary_envi_file: str, glt_envi_file nc_ds.southernmost_latitude = ul_lr[3] nc_ds.spatialResolution = res + gdal_ds = gdal.Open(glt_envi_file) + nc_ds.spatial_ref = gdal_ds.GetProjection() + nc_ds.geotransform = gdal_ds.GetGeoTransform() + nc_ds.day_night_flag = primary_ds.metadata['emit acquisition daynight'] nc_ds.sync() # flush From 6a7861f66193e84eb98348a521c762689ec74295 Mon Sep 17 00:00:00 2001 From: pgbrodrick Date: Fri, 1 Apr 2022 10:22:03 -0700 Subject: [PATCH 21/47] nc fpa dims nomenclature update --- emit_utils/daac_converter.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index 4c2a39f..2938a52 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -118,9 +118,9 @@ def makeDims(nc_ds: netCDF4.Dataset, primary_envi_file: str, glt_envi_file: str """ primary_ds = envi.open(envi_header(primary_envi_file)) - nc_ds.createDimension('number_of_scans', int(primary_ds.metadata['lines'])) - nc_ds.createDimension('pixels_per_scan', int(primary_ds.metadata['samples'])) - nc_ds.createDimension('number_of_bands', int(primary_ds.metadata['bands'])) + nc_ds.createDimension('downtrack', int(primary_ds.metadata['lines'])) + nc_ds.createDimension('crosstrack', int(primary_ds.metadata['samples'])) + nc_ds.createDimension('bands', int(primary_ds.metadata['bands'])) # Geographical Dimensions if glt_envi_file is not None: From 25523abc478fd9281a87908d3a756160f8e8a046 Mon Sep 17 00:00:00 2001 From: pgbrodrick Date: Fri, 1 Apr 2022 10:25:02 -0700 Subject: [PATCH 22/47] lingering scan references --- emit_utils/daac_converter.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index 2938a52..9fe4992 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -78,13 +78,13 @@ def add_loc(nc_ds, loc_envi_file): """ loc = envi.open(envi_header(loc_envi_file)).open_memmap(interleave='bip') add_variable(nc_ds, "location/lat", "d", "Longitude (WGS-84)", "degrees east", loc[..., 0].copy(), - {"dimensions": ("number_of_scans", "pixels_per_scan")} ) + {"dimensions": ("downtrack", "crosstrack")} ) add_variable(nc_ds, "location/lon", "d", "Latitude (WGS-84)", "degrees north", loc[..., 1].copy(), - {"dimensions": ("number_of_scans", "pixels_per_scan")} ) + {"dimensions": ("downtrack", "crosstrack")} ) add_variable(nc_ds, "location/elev", "d", "Surface Elevation", "m", loc[..., 2].copy(), - {"dimensions": ("number_of_scans", "pixels_per_scan")} ) + {"dimensions": ("downtrack", "crosstrack")} ) nc_ds.sync() From 82f590d1c125b66198b69549b3e23375cbe9928c Mon Sep 17 00:00:00 2001 From: pgbrodrick Date: Fri, 1 Apr 2022 11:33:04 -0700 Subject: [PATCH 23/47] add glt compression --- emit_utils/daac_converter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index 9fe4992..07e1836 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -99,10 +99,10 @@ def add_glt(nc_ds, glt_envi_file): """ glt = envi.open(envi_header(glt_envi_file)).open_memmap(interleave='bip') add_variable(nc_ds, "location/glt_x", "i4", "GLT Sample Lookup", "pixel location", - glt[..., 0].copy(), {"dimensions": ("ortho_y", "ortho_x")}) + glt[..., 0].copy(), {"dimensions": ("ortho_y", "ortho_x"), "zlib": True, "complevel": 9}) add_variable(nc_ds, "location/glt_y", "i4", "GLT Line Lookup", "pixel location", - glt[..., 1].copy(), {"dimensions": ("ortho_y", "ortho_x")}) + glt[..., 1].copy(), {"dimensions": ("ortho_y", "ortho_x"), "zlib": True, "complevel": 9}) nc_ds.sync() From 2dfc286c0cafb38daf404d295c1c0845d6cd2641 Mon Sep 17 00:00:00 2001 From: pgbrodrick Date: Thu, 12 May 2022 12:16:13 -0700 Subject: [PATCH 24/47] notes for to-dos and some updates --- emit_utils/daac_converter.py | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index 07e1836..3018f0c 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -5,6 +5,25 @@ Nimrod Carmon, nimrod.carmon@jpl.nasa.gov """ + +""" +#TODO - UMMG updates +TemporalExtent - tbd +Platforms - attempt added +extend add_files (for multiples) +related_urls: + - Download Software: github + - Algorithm Documentation : ATBD + - Project Home Page: EMIT website + - Users's Guide : User Guide +PGEVersionClass +Additional Attributes: + - Data Product Version + - Software Build Version +CloudCover +NativeProjectionNames +""" + import hashlib import netCDF4 import os @@ -203,7 +222,8 @@ def makeGlobalAttr(nc_ds: netCDF4.Dataset, primary_envi_file: str, glt_envi_file nc_ds.time_coverage_start = primary_ds.metadata['emit acquisition start time'] nc_ds.time_coverage_end = primary_ds.metadata['emit acquisition stop time'] - nc_ds.product_version = primary_ds.metadata['emit software build version'] + nc_ds.software_build_version = primary_ds.metadata['emit software build version'] + nc_ds.product_version = primary_ds.metadata['emit data product version'] nc_ds.history = "PGE Input files: " + ", ".join(primary_ds.metadata['emit pge input files']) # only include spatial information if provided (may not be available for all PGEs) @@ -255,8 +275,8 @@ def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: ummg['MetadataSpecification'] = {'URL': 'https://cdn.earthdata.nasa.gov/umm/granule/v1.6.3', 'Name': 'UMM-G', 'Version': '1.6.3'} - # - #ummg['Platforms'] = {'ShortName': 'ISS', 'Instruments': {'ShortName': 'EMIT'} } + + ummg['Platforms'] = {'ShortName': 'ISS', 'Instruments': {'ShortName': 'EMIT'} } #ummg['AdditionalAttributes'] = [{'Name': 'SPATIAL_RESOLUTION', 'Values': ["60.0"]}] ummg['GranuleUR'] = granule_name ummg['ProviderDates'].append({'Date': creation_time.strftime("%Y-%m-%dT%H:%M:%SZ"), 'Type': "Insert"}) From daf7e437b6e2c265f907152b32edc9fd862f153b Mon Sep 17 00:00:00 2001 From: pgbrodrick Date: Thu, 12 May 2022 13:22:22 -0700 Subject: [PATCH 25/47] change add_data_file_ummg to plural, accept multiple files as list --- emit_utils/daac_converter.py | 62 +++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index 3018f0c..ab495e8 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -9,18 +9,29 @@ """ #TODO - UMMG updates TemporalExtent - tbd -Platforms - attempt added -extend add_files (for multiples) +Platforms - implemented, test to see if it breaks +extend add_files (for multiples) - Phil to do +Winston - extend calls in main + + related_urls: - - Download Software: github - - Algorithm Documentation : ATBD - - Project Home Page: EMIT website - - Users's Guide : User Guide -PGEVersionClass + - Download Software: github # specific to Level + - Algorithm Documentation : ATBD # specific to Level + - Project Home Page: EMIT website # general + - Users's Guide : User Guide # specific to level + +Phil - add function to add link to granule +Phil - add project home page to initialize +Winston - add calls to emit-main + +PGEVersionClass - Winston to do pass in from config Additional Attributes: - - Data Product Version - - Software Build Version -CloudCover + - Data Product Version - modify initiali_ummg call in main to reference config - prepend 0 + +Phil add name/value pair additional attrubute possibility + - Software Build Version - pass in padded 6 digit number, add to initial_ummg (Winston to add call to main) + +CloudCover - L2A PGE adds to cloudcover percentage to database from mask (phil to do). cloudcover as optional argument to initialize (phil to do). Add to emit-main calls (Winston to do) NativeProjectionNames """ @@ -279,7 +290,9 @@ def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: ummg['Platforms'] = {'ShortName': 'ISS', 'Instruments': {'ShortName': 'EMIT'} } #ummg['AdditionalAttributes'] = [{'Name': 'SPATIAL_RESOLUTION', 'Values': ["60.0"]}] ummg['GranuleUR'] = granule_name - ummg['ProviderDates'].append({'Date': creation_time.strftime("%Y-%m-%dT%H:%M:%SZ"), 'Type': "Insert"}) + + # Removing on advice of LPDAAC, if this causes a failure on ingestion, re-add, and DAAC will update + #ummg['ProviderDates'].append({'Date': creation_time.strftime("%Y-%m-%dT%H:%M:%SZ"), 'Type': "Insert"}) ummg['CollectionReference'] = { "ShortName": collection_name, "Version": collection_version @@ -345,12 +358,12 @@ def add_boundary_ummg(ummg: dict, boundary_points: list): return ummg -def add_data_file_ummg(ummg: dict, data_file_name: str, daynight: str, file_format: str ='NETCDF-4'): +def add_data_files_ummg(ummg: dict, data_file_names: list, daynight: str, file_format: str ='NETCDF-4'): """ Add boundary points list to UMMG in correct format Args: ummg: existing UMMG to augment - data_file_name: path to existing data file to add + data_file_names: list of paths to existing data files to add file_format: description of file type Returns: @@ -362,18 +375,23 @@ def add_data_file_ummg(ummg: dict, data_file_name: str, daynight: str, file_form prod_datetime_str = subdict['Date'] break + archive_info = [] + for filename in data_file_names: + archive_info.append({ + "Name": os.path.basename(filename), + "SizeInBytes": os.path.getsize(filename), + "Format": file_format, + "Checksum": { + 'Value': calc_checksum(filename), + 'Algorithm': 'SHA-512' + } + }) + ummg['DataGranule'] = { 'DayNightFlag': daynight, - 'ArchiveAndDistributionInformation': [{ - "Name": os.path.basename(data_file_name), - "SizeInBytes": os.path.getsize(data_file_name), - "Format": file_format, - "Checksum": { - 'Value': calc_checksum(data_file_name), - 'Algorithm': 'SHA-512' - } - }] + 'ArchiveAndDistributionInformation': archive_info } + if prod_datetime_str is not None: ummg['DataGranule']['ProductionDateTime'] = prod_datetime_str From 6f4d222358d49df9c56374d576b8347571ed777b Mon Sep 17 00:00:00 2001 From: pgbrodrick Date: Thu, 12 May 2022 13:31:31 -0700 Subject: [PATCH 26/47] extend data file addition to allow different file formats --- emit_utils/daac_converter.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index ab495e8..21e2c4d 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -10,7 +10,7 @@ #TODO - UMMG updates TemporalExtent - tbd Platforms - implemented, test to see if it breaks -extend add_files (for multiples) - Phil to do +X extend add_files (for multiples) - Phil to do Winston - extend calls in main @@ -358,17 +358,22 @@ def add_boundary_ummg(ummg: dict, boundary_points: list): return ummg -def add_data_files_ummg(ummg: dict, data_file_names: list, daynight: str, file_format: str ='NETCDF-4'): +def add_data_files_ummg(ummg: dict, data_file_names: list, daynight: str, file_formats: list =['NETCDF-4']): """ Add boundary points list to UMMG in correct format Args: ummg: existing UMMG to augment data_file_names: list of paths to existing data files to add - file_format: description of file type + file_formats: description of file types Returns: dictionary representation of ummg with new data granule """ + + if len(data_file_names) != len(file_formats): + err = f'Length of data_file_names must match length of file_formats. Currentely lengths are: {len(data_file_names)} and {len(file_formats)}' + raise AttributeError(err) + prod_datetime_str = None for subdict in ummg['ProviderDates']: if subdict['Type'] == 'Insert': @@ -376,11 +381,11 @@ def add_data_files_ummg(ummg: dict, data_file_names: list, daynight: str, file_f break archive_info = [] - for filename in data_file_names: + for filename, fileformat in data_file_names, file_formats: archive_info.append({ "Name": os.path.basename(filename), "SizeInBytes": os.path.getsize(filename), - "Format": file_format, + "Format": fileformat, "Checksum": { 'Value': calc_checksum(filename), 'Algorithm': 'SHA-512' From a46dbccd207a837182a258079adf81c4a2123552 Mon Sep 17 00:00:00 2001 From: pgbrodrick Date: Thu, 12 May 2022 13:52:42 -0700 Subject: [PATCH 27/47] add general related urls, and function to support adding additional ones --- emit_utils/daac_converter.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index 21e2c4d..8631b4c 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -20,8 +20,8 @@ - Project Home Page: EMIT website # general - Users's Guide : User Guide # specific to level -Phil - add function to add link to granule -Phil - add project home page to initialize +X Phil - add function to add link to granule +X Phil - add project home page to initialize Winston - add calls to emit-main PGEVersionClass - Winston to do pass in from config @@ -291,6 +291,8 @@ def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: #ummg['AdditionalAttributes'] = [{'Name': 'SPATIAL_RESOLUTION', 'Values': ["60.0"]}] ummg['GranuleUR'] = granule_name + ummg['RelatedUrls'] = [{'URL': 'https://earth.jpl.nasa.gov/emit/', 'Type': 'PROJECT HOME PAGE', 'Description': 'Link to the EMIT Project Website.'}] + # Removing on advice of LPDAAC, if this causes a failure on ingestion, re-add, and DAAC will update #ummg['ProviderDates'].append({'Date': creation_time.strftime("%Y-%m-%dT%H:%M:%SZ"), 'Type': "Insert"}) ummg['CollectionReference'] = { @@ -300,6 +302,25 @@ def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: return ummg +def add_related_url(ummg: dict, url: str, url_type: str, description: str) -> dict: + """Add an element to the related urls field. Should follow the naming convention here: + https://wiki.earthdata.nasa.gov/pages/viewpage.action?pageId=138875957 + (list of keywords here: https://gcmd.earthdata.nasa.gov/kms/concepts/concept_scheme/rucontenttype?format=csv) + + Args: + ummg (dict): ummg to modify + url (str): URL to add + url_type (str): Type of URL being added + description (str): Description of URL being added + + Returns: + dict: modified ummg + """ + + ummg['RelatedUrls'].append({'URL': url, 'Type': url_type, 'Description': description}) + return ummg + + class SerialEncoder(json.JSONEncoder): """Encoder for json to help ensure json objects can be passed to the workflow manager. """ From ff35157fb8a598e4b5a254c289661e20365ec79d Mon Sep 17 00:00:00 2001 From: pgbrodrick Date: Thu, 12 May 2022 14:06:55 -0700 Subject: [PATCH 28/47] add software build version to ummg init --- emit_utils/daac_converter.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index 8631b4c..72433ff 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -270,7 +270,7 @@ def get_required_ummg(): return ummg -def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: str, collection_version: str = "001"): +def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: str, collection_version: str, software_build_version: str): """ Initialize a UMMG metadata output file Args: granule_name: granule UR tag @@ -288,7 +288,6 @@ def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: ummg['Platforms'] = {'ShortName': 'ISS', 'Instruments': {'ShortName': 'EMIT'} } - #ummg['AdditionalAttributes'] = [{'Name': 'SPATIAL_RESOLUTION', 'Values': ["60.0"]}] ummg['GranuleUR'] = granule_name ummg['RelatedUrls'] = [{'URL': 'https://earth.jpl.nasa.gov/emit/', 'Type': 'PROJECT HOME PAGE', 'Description': 'Link to the EMIT Project Website.'}] @@ -297,8 +296,11 @@ def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: #ummg['ProviderDates'].append({'Date': creation_time.strftime("%Y-%m-%dT%H:%M:%SZ"), 'Type': "Insert"}) ummg['CollectionReference'] = { "ShortName": collection_name, - "Version": collection_version + "Version": str(collection_version) } + + ummg['AdditionalAttributes'] = [{'Name': 'SOFTWARE_BUILD_VERSION', 'Values': [str(software_build_version)]}] + #ummg['AdditionalAttributes'].append({'Name': 'SPATIAL_RESOLUTION', 'Values': ["60.0"]}) return ummg From e1d40dfd04eb1fc9278728a79e2e3dc3a9a110ca Mon Sep 17 00:00:00 2001 From: pgbrodrick Date: Thu, 12 May 2022 14:07:29 -0700 Subject: [PATCH 29/47] add software build version to ummg init doc --- emit_utils/daac_converter.py | 1 + 1 file changed, 1 insertion(+) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index 72433ff..9e48eb0 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -277,6 +277,7 @@ def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: creation_time: creation timestamp collection_name: short name of collection reference collection_version: collection version + software_build_version: version of software build Returns: dictionary representation of ummg From 7fd64c6ce63b1c92bcb915509b7c5ae436607931 Mon Sep 17 00:00:00 2001 From: pgbrodrick Date: Thu, 12 May 2022 15:18:36 -0700 Subject: [PATCH 30/47] update ummg init to include PGEVersionClass --- emit_utils/daac_converter.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index 9e48eb0..cfd5716 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -11,7 +11,7 @@ TemporalExtent - tbd Platforms - implemented, test to see if it breaks X extend add_files (for multiples) - Phil to do -Winston - extend calls in main +X Winston - extend calls in main related_urls: @@ -26,10 +26,10 @@ PGEVersionClass - Winston to do pass in from config Additional Attributes: - - Data Product Version - modify initiali_ummg call in main to reference config - prepend 0 +X - Data Product Version - modify initiali_ummg call in main to reference config - prepend 0 Phil add name/value pair additional attrubute possibility - - Software Build Version - pass in padded 6 digit number, add to initial_ummg (Winston to add call to main) +X - Software Build Version - pass in padded 6 digit number, add to initial_ummg (Winston to add call to main) CloudCover - L2A PGE adds to cloudcover percentage to database from mask (phil to do). cloudcover as optional argument to initialize (phil to do). Add to emit-main calls (Winston to do) NativeProjectionNames @@ -270,7 +270,7 @@ def get_required_ummg(): return ummg -def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: str, collection_version: str, software_build_version: str): +def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: str, collection_version: str, software_build_version: str, pge_name_version: str): """ Initialize a UMMG metadata output file Args: granule_name: granule UR tag @@ -278,6 +278,7 @@ def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: collection_name: short name of collection reference collection_version: collection version software_build_version: version of software build + pge_name_version: coupled PGE name and version from the build configuration Returns: dictionary representation of ummg @@ -302,6 +303,9 @@ def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: ummg['AdditionalAttributes'] = [{'Name': 'SOFTWARE_BUILD_VERSION', 'Values': [str(software_build_version)]}] #ummg['AdditionalAttributes'].append({'Name': 'SPATIAL_RESOLUTION', 'Values': ["60.0"]}) + + ummg['PGEVersionClass'] = pge_name_version + return ummg From 6bc4b13e6261b7fc0156ca78ed92939c960a7935 Mon Sep 17 00:00:00 2001 From: pgbrodrick Date: Thu, 12 May 2022 15:23:16 -0700 Subject: [PATCH 31/47] split name and version int independent entries --- emit_utils/daac_converter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index cfd5716..62a25e0 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -270,7 +270,7 @@ def get_required_ummg(): return ummg -def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: str, collection_version: str, software_build_version: str, pge_name_version: str): +def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: str, collection_version: str, software_build_version: str, pge_name: str, pge_version: str): """ Initialize a UMMG metadata output file Args: granule_name: granule UR tag @@ -304,7 +304,7 @@ def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: ummg['AdditionalAttributes'] = [{'Name': 'SOFTWARE_BUILD_VERSION', 'Values': [str(software_build_version)]}] #ummg['AdditionalAttributes'].append({'Name': 'SPATIAL_RESOLUTION', 'Values': ["60.0"]}) - ummg['PGEVersionClass'] = pge_name_version + ummg['PGEVersionClass'] = {'PGE Name': pge_name, 'PGE Version': pge_version} return ummg From 5d9f855fa70a5e45abf01e9ced9c2b736acf86e6 Mon Sep 17 00:00:00 2001 From: pgbrodrick Date: Thu, 12 May 2022 15:30:34 -0700 Subject: [PATCH 32/47] update related urls function to have optional subtype and make description optional --- emit_utils/daac_converter.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index 62a25e0..727b722 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -15,16 +15,17 @@ related_urls: - - Download Software: github # specific to Level - - Algorithm Documentation : ATBD # specific to Level - - Project Home Page: EMIT website # general - - Users's Guide : User Guide # specific to level + - DOWNLOAD SOFTWARE: github # specific to Level + - VIEW RELATED INFORMATION / ALGORITHM DOCUMENTATION : ATBD # specific to Level + X - PROJECT HOME PAGE: EMIT website # general + - VIEW RELATED INFORMATION / USERS'S GUIDE : User Guide # specific to level X Phil - add function to add link to granule X Phil - add project home page to initialize Winston - add calls to emit-main PGEVersionClass - Winston to do pass in from config + X - Phil to add to initialize Additional Attributes: X - Data Product Version - modify initiali_ummg call in main to reference config - prepend 0 @@ -309,7 +310,7 @@ def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: return ummg -def add_related_url(ummg: dict, url: str, url_type: str, description: str) -> dict: +def add_related_url(ummg: dict, url: str, url_type: str, description: str = None, url_subtype: str = None) -> dict: """Add an element to the related urls field. Should follow the naming convention here: https://wiki.earthdata.nasa.gov/pages/viewpage.action?pageId=138875957 (list of keywords here: https://gcmd.earthdata.nasa.gov/kms/concepts/concept_scheme/rucontenttype?format=csv) @@ -319,12 +320,20 @@ def add_related_url(ummg: dict, url: str, url_type: str, description: str) -> di url (str): URL to add url_type (str): Type of URL being added description (str): Description of URL being added + url_subtype (str): SubType of URL being added Returns: dict: modified ummg """ - ummg['RelatedUrls'].append({'URL': url, 'Type': url_type, 'Description': description}) + output_dict = {'URL': url, 'Type': url_type, 'Description': description} + if description is not None: + output_dict['Description'] = description + + if url_subtype is not None: + output_dict['Subtype'] = url_subtype + + ummg['RelatedUrls'].append(output_dict) return ummg From 9da1baa28a11298c40387564c9830068cb8253e6 Mon Sep 17 00:00:00 2001 From: pgbrodrick Date: Thu, 12 May 2022 15:32:49 -0700 Subject: [PATCH 33/47] add cloud percentage check --- emit_utils/file_checks.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/emit_utils/file_checks.py b/emit_utils/file_checks.py index bec96ab..15387fe 100644 --- a/emit_utils/file_checks.py +++ b/emit_utils/file_checks.py @@ -10,6 +10,25 @@ import numpy as np from spectral.io import envi + +def check_cloudfraction(mask_file: str, mask_band=7) -> float: + """ + Determines the cloud fraction from a mask file + + Args: + mask_file (str): mask file (EMIT style) + mask_band (int, optional): Band number to estimate clouds from. + + Returns: + float: cloud fraction + """ + ds = envi.open(envi_header(mask_file)) + clouds = ds.open_memmap(interleave='bip').open_memmap()[...,mask_band] + + fraction = np.sum(clouds > 0) / np.product(clouds.shape) + return int(np.round(fraction)) + + def check_daynight(obs_file: str, zenith_band=4): """ Determine if an acquisition is from daytime or nighttime From 5a994af888ba6e98e1c3ad0ccc6892a08fecbaec Mon Sep 17 00:00:00 2001 From: pgbrodrick Date: Thu, 12 May 2022 16:04:41 -0700 Subject: [PATCH 34/47] add ug, atbd, and cloud cover to ummg init --- emit_utils/daac_converter.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index 727b722..b803a68 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -16,9 +16,9 @@ related_urls: - DOWNLOAD SOFTWARE: github # specific to Level - - VIEW RELATED INFORMATION / ALGORITHM DOCUMENTATION : ATBD # specific to Level + X - VIEW RELATED INFORMATION / ALGORITHM DOCUMENTATION : ATBD # specific to Level X - PROJECT HOME PAGE: EMIT website # general - - VIEW RELATED INFORMATION / USERS'S GUIDE : User Guide # specific to level + X - VIEW RELATED INFORMATION / USERS'S GUIDE : User Guide # specific to level X Phil - add function to add link to granule X Phil - add project home page to initialize @@ -271,7 +271,7 @@ def get_required_ummg(): return ummg -def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: str, collection_version: str, software_build_version: str, pge_name: str, pge_version: str): +def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: str, collection_version: str, software_build_version: str, pge_name: str, pge_version: str, cloud_fraction: str): """ Initialize a UMMG metadata output file Args: granule_name: granule UR tag @@ -294,6 +294,8 @@ def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: ummg['GranuleUR'] = granule_name ummg['RelatedUrls'] = [{'URL': 'https://earth.jpl.nasa.gov/emit/', 'Type': 'PROJECT HOME PAGE', 'Description': 'Link to the EMIT Project Website.'}] + ummg = add_related_url('https://github.com/emit-sds/emit-documentation', 'VIEW RELATED INFORMATION', 'Link to Algorithm Theoretical Basis Documents', 'ALGORITHM DOCUMENTATION') + ummg = add_related_url('https://github.com/emit-sds/emit-documentation', 'VIEW RELATED INFORMATION', 'Link to Data User\'s Guide', 'USER\'s GUIDE') # Removing on advice of LPDAAC, if this causes a failure on ingestion, re-add, and DAAC will update #ummg['ProviderDates'].append({'Date': creation_time.strftime("%Y-%m-%dT%H:%M:%SZ"), 'Type': "Insert"}) @@ -306,6 +308,7 @@ def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: #ummg['AdditionalAttributes'].append({'Name': 'SPATIAL_RESOLUTION', 'Values': ["60.0"]}) ummg['PGEVersionClass'] = {'PGE Name': pge_name, 'PGE Version': pge_version} + ummg['CloudCover'] = str(cloud_fraction) return ummg From 4679230a99aa1690b3842559909f9be69830ffb0 Mon Sep 17 00:00:00 2001 From: pgbrodrick Date: Thu, 12 May 2022 16:12:42 -0700 Subject: [PATCH 35/47] make cloud fraction optional --- emit_utils/daac_converter.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index b803a68..bd4c62e 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -271,7 +271,7 @@ def get_required_ummg(): return ummg -def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: str, collection_version: str, software_build_version: str, pge_name: str, pge_version: str, cloud_fraction: str): +def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: str, collection_version: str, software_build_version: str, pge_name: str, pge_version: str, cloud_fraction: str = None): """ Initialize a UMMG metadata output file Args: granule_name: granule UR tag @@ -279,7 +279,9 @@ def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: collection_name: short name of collection reference collection_version: collection version software_build_version: version of software build - pge_name_version: coupled PGE name and version from the build configuration + pge_name: PGE name from build configuration + pge_version: PGE version from build configuration + cloud_fraction: rounded fraction of cloudcover if applicable Returns: dictionary representation of ummg @@ -308,7 +310,9 @@ def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: #ummg['AdditionalAttributes'].append({'Name': 'SPATIAL_RESOLUTION', 'Values': ["60.0"]}) ummg['PGEVersionClass'] = {'PGE Name': pge_name, 'PGE Version': pge_version} - ummg['CloudCover'] = str(cloud_fraction) + + if cloud_fraction is not None: + ummg['CloudCover'] = str(cloud_fraction) return ummg From 7fd81a58fcda172b3abb9f45f11424e8405dfbd9 Mon Sep 17 00:00:00 2001 From: pgbrodrick Date: Thu, 12 May 2022 16:15:44 -0700 Subject: [PATCH 36/47] updated todos --- emit_utils/daac_converter.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index bd4c62e..b57e33d 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -15,16 +15,16 @@ related_urls: - - DOWNLOAD SOFTWARE: github # specific to Level + X - DOWNLOAD SOFTWARE: github # specific to Level X - VIEW RELATED INFORMATION / ALGORITHM DOCUMENTATION : ATBD # specific to Level X - PROJECT HOME PAGE: EMIT website # general X - VIEW RELATED INFORMATION / USERS'S GUIDE : User Guide # specific to level X Phil - add function to add link to granule X Phil - add project home page to initialize -Winston - add calls to emit-main +X Winston - add calls to emit-main -PGEVersionClass - Winston to do pass in from config +X PGEVersionClass - Winston to do pass in from config X - Phil to add to initialize Additional Attributes: X - Data Product Version - modify initiali_ummg call in main to reference config - prepend 0 @@ -32,8 +32,8 @@ Phil add name/value pair additional attrubute possibility X - Software Build Version - pass in padded 6 digit number, add to initial_ummg (Winston to add call to main) -CloudCover - L2A PGE adds to cloudcover percentage to database from mask (phil to do). cloudcover as optional argument to initialize (phil to do). Add to emit-main calls (Winston to do) -NativeProjectionNames +X CloudCover - L2A PGE adds to cloudcover percentage to database from mask (phil to do). cloudcover as optional argument to initialize (phil to do). Add to emit-main calls (Winston to do) +X NativeProjectionNames """ import hashlib From 427161230870104db01288379557bcd8b4c20398 Mon Sep 17 00:00:00 2001 From: Winston Olson-Duvall Date: Sun, 29 May 2022 11:39:16 -0700 Subject: [PATCH 37/47] Fix add_related_url --- emit_utils/daac_converter.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index b57e33d..80e0f60 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -296,8 +296,10 @@ def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: ummg['GranuleUR'] = granule_name ummg['RelatedUrls'] = [{'URL': 'https://earth.jpl.nasa.gov/emit/', 'Type': 'PROJECT HOME PAGE', 'Description': 'Link to the EMIT Project Website.'}] - ummg = add_related_url('https://github.com/emit-sds/emit-documentation', 'VIEW RELATED INFORMATION', 'Link to Algorithm Theoretical Basis Documents', 'ALGORITHM DOCUMENTATION') - ummg = add_related_url('https://github.com/emit-sds/emit-documentation', 'VIEW RELATED INFORMATION', 'Link to Data User\'s Guide', 'USER\'s GUIDE') + ummg = add_related_url(ummg, 'https://github.com/emit-sds/emit-documentation', 'VIEW RELATED INFORMATION', + description='Link to Algorithm Theoretical Basis Documents', url_subtype='ALGORITHM DOCUMENTATION') + ummg = add_related_url(ummg, 'https://github.com/emit-sds/emit-documentation', 'VIEW RELATED INFORMATION', + description='Link to Data User\'s Guide', url_subtype='USER\'s GUIDE') # Removing on advice of LPDAAC, if this causes a failure on ingestion, re-add, and DAAC will update #ummg['ProviderDates'].append({'Date': creation_time.strftime("%Y-%m-%dT%H:%M:%SZ"), 'Type': "Insert"}) @@ -333,7 +335,7 @@ def add_related_url(ummg: dict, url: str, url_type: str, description: str = None dict: modified ummg """ - output_dict = {'URL': url, 'Type': url_type, 'Description': description} + output_dict = {'URL': url, 'Type': url_type} if description is not None: output_dict['Description'] = description From 78f91b93f1b8dd0c00293f6f351f27718a6c81c1 Mon Sep 17 00:00:00 2001 From: pgbrodrick Date: Sun, 29 May 2022 15:28:47 -0700 Subject: [PATCH 38/47] bugfix to return cloud fraction as rounded int (percentage) --- emit_utils/file_checks.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/emit_utils/file_checks.py b/emit_utils/file_checks.py index 15387fe..92b7daf 100644 --- a/emit_utils/file_checks.py +++ b/emit_utils/file_checks.py @@ -20,12 +20,12 @@ def check_cloudfraction(mask_file: str, mask_band=7) -> float: mask_band (int, optional): Band number to estimate clouds from. Returns: - float: cloud fraction + float: cloud fraction as rounded percent (0-100) """ ds = envi.open(envi_header(mask_file)) clouds = ds.open_memmap(interleave='bip').open_memmap()[...,mask_band] - fraction = np.sum(clouds > 0) / np.product(clouds.shape) + fraction = np.sum(clouds > 0) * 100 / np.product(clouds.shape) return int(np.round(fraction)) From 50c458698050318a3634f8ad792a36d6c39934cd Mon Sep 17 00:00:00 2001 From: Winston Olson-Duvall Date: Wed, 1 Jun 2022 09:47:58 -0700 Subject: [PATCH 39/47] Make platforms and insruments lists. Fix PGE key names. --- emit_utils/daac_converter.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index 80e0f60..2b4481c 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -292,14 +292,14 @@ def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: 'Version': '1.6.3'} - ummg['Platforms'] = {'ShortName': 'ISS', 'Instruments': {'ShortName': 'EMIT'} } + ummg['Platforms'] = [{'ShortName': 'ISS', 'Instruments': [{'ShortName': 'EMIT'}]}] ummg['GranuleUR'] = granule_name ummg['RelatedUrls'] = [{'URL': 'https://earth.jpl.nasa.gov/emit/', 'Type': 'PROJECT HOME PAGE', 'Description': 'Link to the EMIT Project Website.'}] ummg = add_related_url(ummg, 'https://github.com/emit-sds/emit-documentation', 'VIEW RELATED INFORMATION', description='Link to Algorithm Theoretical Basis Documents', url_subtype='ALGORITHM DOCUMENTATION') ummg = add_related_url(ummg, 'https://github.com/emit-sds/emit-documentation', 'VIEW RELATED INFORMATION', - description='Link to Data User\'s Guide', url_subtype='USER\'s GUIDE') + description='Link to Data User\'s Guide', url_subtype='USER\'S GUIDE') # Removing on advice of LPDAAC, if this causes a failure on ingestion, re-add, and DAAC will update #ummg['ProviderDates'].append({'Date': creation_time.strftime("%Y-%m-%dT%H:%M:%SZ"), 'Type': "Insert"}) @@ -311,7 +311,7 @@ def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: ummg['AdditionalAttributes'] = [{'Name': 'SOFTWARE_BUILD_VERSION', 'Values': [str(software_build_version)]}] #ummg['AdditionalAttributes'].append({'Name': 'SPATIAL_RESOLUTION', 'Values': ["60.0"]}) - ummg['PGEVersionClass'] = {'PGE Name': pge_name, 'PGE Version': pge_version} + ummg['PGEVersionClass'] = {'PGEName': pge_name, 'PGEVersion': pge_version} if cloud_fraction is not None: ummg['CloudCover'] = str(cloud_fraction) @@ -427,7 +427,7 @@ def add_data_files_ummg(ummg: dict, data_file_names: list, daynight: str, file_f break archive_info = [] - for filename, fileformat in data_file_names, file_formats: + for filename, fileformat in zip(data_file_names, file_formats): archive_info.append({ "Name": os.path.basename(filename), "SizeInBytes": os.path.getsize(filename), From 4bef2185434f50db6fd0efbb5e9f8ce3f6409710 Mon Sep 17 00:00:00 2001 From: Winston Olson-Duvall Date: Wed, 1 Jun 2022 13:03:09 -0700 Subject: [PATCH 40/47] Use ProviderDate type 'Update' - this field is required for ingest --- emit_utils/daac_converter.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index 2b4481c..ad50bc8 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -301,8 +301,9 @@ def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: ummg = add_related_url(ummg, 'https://github.com/emit-sds/emit-documentation', 'VIEW RELATED INFORMATION', description='Link to Data User\'s Guide', url_subtype='USER\'S GUIDE') - # Removing on advice of LPDAAC, if this causes a failure on ingestion, re-add, and DAAC will update - #ummg['ProviderDates'].append({'Date': creation_time.strftime("%Y-%m-%dT%H:%M:%SZ"), 'Type': "Insert"}) + # Use ProviderDate type "Update" per DAAC's request. This field is required for ingest. Use this for data granule + # ProductionDateTime field too + ummg['ProviderDates'].append({'Date': creation_time.strftime("%Y-%m-%dT%H:%M:%SZ"), 'Type': "Update"}) ummg['CollectionReference'] = { "ShortName": collection_name, "Version": str(collection_version) @@ -422,7 +423,7 @@ def add_data_files_ummg(ummg: dict, data_file_names: list, daynight: str, file_f prod_datetime_str = None for subdict in ummg['ProviderDates']: - if subdict['Type'] == 'Insert': + if subdict['Type'] == 'Update': prod_datetime_str = subdict['Date'] break From f3f6802ba7c0227515eaac639cff1e91e8e575ef Mon Sep 17 00:00:00 2001 From: Winston Olson-Duvall Date: Wed, 1 Jun 2022 13:42:46 -0700 Subject: [PATCH 41/47] Switch ProviderDates type back to 'Insert' since it seems to be required. --- emit_utils/daac_converter.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index ad50bc8..d21dafb 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -301,9 +301,8 @@ def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: ummg = add_related_url(ummg, 'https://github.com/emit-sds/emit-documentation', 'VIEW RELATED INFORMATION', description='Link to Data User\'s Guide', url_subtype='USER\'S GUIDE') - # Use ProviderDate type "Update" per DAAC's request. This field is required for ingest. Use this for data granule - # ProductionDateTime field too - ummg['ProviderDates'].append({'Date': creation_time.strftime("%Y-%m-%dT%H:%M:%SZ"), 'Type': "Update"}) + # Use ProviderDate type "Insert" seems to be required. Use this for data granule ProductionDateTime field too. + ummg['ProviderDates'].append({'Date': creation_time.strftime("%Y-%m-%dT%H:%M:%SZ"), 'Type': "Insert"}) ummg['CollectionReference'] = { "ShortName": collection_name, "Version": str(collection_version) @@ -423,7 +422,7 @@ def add_data_files_ummg(ummg: dict, data_file_names: list, daynight: str, file_f prod_datetime_str = None for subdict in ummg['ProviderDates']: - if subdict['Type'] == 'Update': + if subdict['Type'] == 'Insert': prod_datetime_str = subdict['Date'] break From d3710f10caa8aa172d9a2ecc76ae07696171ad8f Mon Sep 17 00:00:00 2001 From: Winston Olson-Duvall Date: Wed, 1 Jun 2022 14:30:52 -0700 Subject: [PATCH 42/47] Tweak instrument name per DAAC to 'EMIT Imaging Spectrometer' --- emit_utils/daac_converter.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index d21dafb..b09bde9 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -292,7 +292,7 @@ def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: 'Version': '1.6.3'} - ummg['Platforms'] = [{'ShortName': 'ISS', 'Instruments': [{'ShortName': 'EMIT'}]}] + ummg['Platforms'] = [{'ShortName': 'ISS', 'Instruments': [{'ShortName': 'EMIT Imaging Spectrometer'}]}] ummg['GranuleUR'] = granule_name ummg['RelatedUrls'] = [{'URL': 'https://earth.jpl.nasa.gov/emit/', 'Type': 'PROJECT HOME PAGE', 'Description': 'Link to the EMIT Project Website.'}] @@ -302,7 +302,7 @@ def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: description='Link to Data User\'s Guide', url_subtype='USER\'S GUIDE') # Use ProviderDate type "Insert" seems to be required. Use this for data granule ProductionDateTime field too. - ummg['ProviderDates'].append({'Date': creation_time.strftime("%Y-%m-%dT%H:%M:%SZ"), 'Type': "Insert"}) + ummg['ProviderDates'].append({'Date': creation_time.strftime("%Y-%m-%dT%H:%M:%SZ"), 'Type': "Update"}) ummg['CollectionReference'] = { "ShortName": collection_name, "Version": str(collection_version) @@ -422,7 +422,7 @@ def add_data_files_ummg(ummg: dict, data_file_names: list, daynight: str, file_f prod_datetime_str = None for subdict in ummg['ProviderDates']: - if subdict['Type'] == 'Insert': + if subdict['Type'] == 'Update': prod_datetime_str = subdict['Date'] break From 283e6f60c1e7df436fc6cf077341ae625dd03696 Mon Sep 17 00:00:00 2001 From: Winston Olson-Duvall Date: Wed, 1 Jun 2022 14:32:11 -0700 Subject: [PATCH 43/47] Tweak comment --- emit_utils/daac_converter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index b09bde9..aea30c7 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -301,7 +301,7 @@ def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: ummg = add_related_url(ummg, 'https://github.com/emit-sds/emit-documentation', 'VIEW RELATED INFORMATION', description='Link to Data User\'s Guide', url_subtype='USER\'S GUIDE') - # Use ProviderDate type "Insert" seems to be required. Use this for data granule ProductionDateTime field too. + # Use ProviderDate type "Update" per DAAC. Use this for data granule ProductionDateTime field too. ummg['ProviderDates'].append({'Date': creation_time.strftime("%Y-%m-%dT%H:%M:%SZ"), 'Type': "Update"}) ummg['CollectionReference'] = { "ShortName": collection_name, From 3a6c1ea57242ed83ea6d081574690297e3977d14 Mon Sep 17 00:00:00 2001 From: Winston Olson-Duvall Date: Thu, 2 Jun 2022 08:57:06 -0700 Subject: [PATCH 44/47] Convert cloud_fraction to int for ummg --- emit_utils/daac_converter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emit_utils/daac_converter.py b/emit_utils/daac_converter.py index aea30c7..2253442 100644 --- a/emit_utils/daac_converter.py +++ b/emit_utils/daac_converter.py @@ -314,7 +314,7 @@ def initialize_ummg(granule_name: str, creation_time: datetime, collection_name: ummg['PGEVersionClass'] = {'PGEName': pge_name, 'PGEVersion': pge_version} if cloud_fraction is not None: - ummg['CloudCover'] = str(cloud_fraction) + ummg['CloudCover'] = int(cloud_fraction) return ummg From 75e212416cf14406d647be6bfdce1bc850bb01c3 Mon Sep 17 00:00:00 2001 From: Phil Brodrick Date: Mon, 6 Jun 2022 10:26:48 -0700 Subject: [PATCH 45/47] update cloud_fraction syntax error --- emit_utils/file_checks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emit_utils/file_checks.py b/emit_utils/file_checks.py index 92b7daf..da8befd 100644 --- a/emit_utils/file_checks.py +++ b/emit_utils/file_checks.py @@ -23,7 +23,7 @@ def check_cloudfraction(mask_file: str, mask_band=7) -> float: float: cloud fraction as rounded percent (0-100) """ ds = envi.open(envi_header(mask_file)) - clouds = ds.open_memmap(interleave='bip').open_memmap()[...,mask_band] + clouds = ds.open_memmap(interleave='bip')[...,mask_band] fraction = np.sum(clouds > 0) * 100 / np.product(clouds.shape) return int(np.round(fraction)) From 873afbc875070303d1e8593b78f9b7b36790e866 Mon Sep 17 00:00:00 2001 From: Winston Olson-Duvall Date: Mon, 6 Jun 2022 10:57:59 -0700 Subject: [PATCH 46/47] Update version to 1.1.0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 1839fb1..cc8bcc9 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ setup(name='emit_utils', packages=find_packages(), include_package_data=True, - version='1.0.0', + version='1.1.0', install_requires=[ 'gdal>=2.0', 'spectral>=0.21', From 23a56f5bf5a9947992cf6d046b65f6ac96d95361 Mon Sep 17 00:00:00 2001 From: Winston Olson-Duvall Date: Mon, 6 Jun 2022 10:58:48 -0700 Subject: [PATCH 47/47] Update change log --- CHANGELOG.md | 61 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 37840c4..f95499c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,48 +4,59 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). -### [v1.0.0](https://github.jpl.nasa.gov/emit-sds/emit-utils/compare/v0.4.0...v1.0.0) +#### [v1.1.0](https://github.com/emit-sds/emit-utils/compare/v1.0.0...v1.1.0) + +> 6 June 2022 + +- Ummg updates [`#1`](https://github.com/emit-sds/emit-utils/pull/1) +- change add_data_file_ummg to plural, accept multiple files as list [`daf7e43`](https://github.com/emit-sds/emit-utils/commit/daf7e437b6e2c265f907152b32edc9fd862f153b) +- notes for to-dos and some updates [`2dfc286`](https://github.com/emit-sds/emit-utils/commit/2dfc286c0cafb38daf404d295c1c0845d6cd2641) +- add general related urls, and function to support adding additional ones [`a46dbcc`](https://github.com/emit-sds/emit-utils/commit/a46dbccd207a837182a258079adf81c4a2123552) + +### [v1.0.0](https://github.com/emit-sds/emit-utils/compare/v0.4.0...v1.0.0) > 9 February 2022 -- break out metadata specs for easy att use [`b469551`](https://github.jpl.nasa.gov/emit-sds/emit-utils/commit/b4695512a9276bf79f6e1435fb59e66c547f320e) -- Increment version to 1.0.0 [`7a47a2a`](https://github.jpl.nasa.gov/emit-sds/emit-utils/commit/7a47a2a93405fe3c4e9a2bc06aa4a1aac4dd84c1) +- Merge develop to main for 1.0.0 [`#8`](https://github.com/emit-sds/emit-utils/pull/8) +- break out metadata specs for easy att use [`b469551`](https://github.com/emit-sds/emit-utils/commit/b4695512a9276bf79f6e1435fb59e66c547f320e) +- Update changelog [`cd3058b`](https://github.com/emit-sds/emit-utils/commit/cd3058bbc12754a0e34f928d92bd67f53bf06f70) +- Increment version to 1.0.0 [`7a47a2a`](https://github.com/emit-sds/emit-utils/commit/7a47a2a93405fe3c4e9a2bc06aa4a1aac4dd84c1) -#### [v0.4.0](https://github.jpl.nasa.gov/emit-sds/emit-utils/compare/v0.3.0...v0.4.0) +#### [v0.4.0](https://github.com/emit-sds/emit-utils/compare/v0.3.0...v0.4.0) > 31 January 2022 -- Merge develop into main for v0.4.0 [`#7`](https://github.jpl.nasa.gov/emit-sds/emit-utils/pull/7) -- Ummg file creation [`#6`](https://github.jpl.nasa.gov/emit-sds/emit-utils/pull/6) -- Update changelog for v0.4.0 [`aa75861`](https://github.jpl.nasa.gov/emit-sds/emit-utils/commit/aa75861c7daf8e3c4fb9a22327355a38aacd9e7b) -- Change setup version to 0.4.0 [`7d7d404`](https://github.jpl.nasa.gov/emit-sds/emit-utils/commit/7d7d404a3e5a9ba622354aac1adb606474412e67) -- Resolve conflict [`88aa674`](https://github.jpl.nasa.gov/emit-sds/emit-utils/commit/88aa674c2adce357a61cae0a2e9fcf505f12e9d2) +- Merge develop into main for v0.4.0 [`#7`](https://github.com/emit-sds/emit-utils/pull/7) +- Ummg file creation [`#6`](https://github.com/emit-sds/emit-utils/pull/6) +- Update changelog for v0.4.0 [`aa75861`](https://github.com/emit-sds/emit-utils/commit/aa75861c7daf8e3c4fb9a22327355a38aacd9e7b) +- Change setup version to 0.4.0 [`7d7d404`](https://github.com/emit-sds/emit-utils/commit/7d7d404a3e5a9ba622354aac1adb606474412e67) +- Resolve conflict [`88aa674`](https://github.com/emit-sds/emit-utils/commit/88aa674c2adce357a61cae0a2e9fcf505f12e9d2) -#### [v0.3.0](https://github.jpl.nasa.gov/emit-sds/emit-utils/compare/v0.2.0...v0.3.0) +#### [v0.3.0](https://github.com/emit-sds/emit-utils/compare/v0.2.0...v0.3.0) > 20 January 2022 -- Merge develop for release 0.3.0 [`#5`](https://github.jpl.nasa.gov/emit-sds/emit-utils/pull/5) -- Daac interface [`#4`](https://github.jpl.nasa.gov/emit-sds/emit-utils/pull/4) -- Netcdf [`#3`](https://github.jpl.nasa.gov/emit-sds/emit-utils/pull/3) -- adds netcdf converter basics, still needs a few updates [`36e4a58`](https://github.jpl.nasa.gov/emit-sds/emit-utils/commit/36e4a58dce35d88b3ffafb217d9243e39ed5b1ec) -- Add changelog [`5d4f786`](https://github.jpl.nasa.gov/emit-sds/emit-utils/commit/5d4f786868c3b3dcb5bdd78a932ef95b63177c9c) -- Add requirements to setup file based on import statements. Add calc_checksum function that defaults to sha512 checksum, but can be augmented to include others. [`30677d8`](https://github.jpl.nasa.gov/emit-sds/emit-utils/commit/30677d8cf8bdda89f32cb23252826e95c100a72d) +- Merge develop for release 0.3.0 [`#5`](https://github.com/emit-sds/emit-utils/pull/5) +- Daac interface [`#4`](https://github.com/emit-sds/emit-utils/pull/4) +- Netcdf [`#3`](https://github.com/emit-sds/emit-utils/pull/3) +- adds netcdf converter basics, still needs a few updates [`36e4a58`](https://github.com/emit-sds/emit-utils/commit/36e4a58dce35d88b3ffafb217d9243e39ed5b1ec) +- Add changelog [`5d4f786`](https://github.com/emit-sds/emit-utils/commit/5d4f786868c3b3dcb5bdd78a932ef95b63177c9c) +- Add requirements to setup file based on import statements. Add calc_checksum function that defaults to sha512 checksum, but can be augmented to include others. [`30677d8`](https://github.com/emit-sds/emit-utils/commit/30677d8cf8bdda89f32cb23252826e95c100a72d) -#### [v0.2.0](https://github.jpl.nasa.gov/emit-sds/emit-utils/compare/v0.1.0...v0.2.0) +#### [v0.2.0](https://github.com/emit-sds/emit-utils/compare/v0.1.0...v0.2.0) > 25 October 2021 -- Merge develop for version 0.2.0. [`#2`](https://github.jpl.nasa.gov/emit-sds/emit-utils/pull/2) -- update gdal imports, add safe envi header reference [`b3b9f66`](https://github.jpl.nasa.gov/emit-sds/emit-utils/commit/b3b9f663e23ebbebc8e6b183f9bd90c3a20639f5) -- Increment version to 0.2.0 [`3a5859f`](https://github.jpl.nasa.gov/emit-sds/emit-utils/commit/3a5859fac439dfc8bc968b1e072535b69861843f) -- Update readme. [`ca6b5af`](https://github.jpl.nasa.gov/emit-sds/emit-utils/commit/ca6b5af3df2229cd78b6dba2885fc38b496a7604) +- Merge develop for version 0.2.0. [`#2`](https://github.com/emit-sds/emit-utils/pull/2) +- update gdal imports, add safe envi header reference [`b3b9f66`](https://github.com/emit-sds/emit-utils/commit/b3b9f663e23ebbebc8e6b183f9bd90c3a20639f5) +- Increment version to 0.2.0 [`3a5859f`](https://github.com/emit-sds/emit-utils/commit/3a5859fac439dfc8bc968b1e072535b69861843f) +- Update readme. [`ca6b5af`](https://github.com/emit-sds/emit-utils/commit/ca6b5af3df2229cd78b6dba2885fc38b496a7604) #### v0.1.0 > 26 January 2021 -- Merge develop to main for v0.1.0 release [`#1`](https://github.jpl.nasa.gov/emit-sds/emit-utils/pull/1) -- added install file, basic file checking, started multi-raster functions [`5fd1b47`](https://github.jpl.nasa.gov/emit-sds/emit-utils/commit/5fd1b4784a21cc948be410565ca5e525dfbf0c7f) -- add igm map space lookups [`f5f2250`](https://github.jpl.nasa.gov/emit-sds/emit-utils/commit/f5f2250a9ab6faa3bba44718f3d13509b84a9439) -- input type changes to file checks for ease, extra multi-raster info return options [`707d038`](https://github.jpl.nasa.gov/emit-sds/emit-utils/commit/707d03868cb1b5ad0473350a268a158577cee20c) +- Merge develop to main for v0.1.0 release [`#1`](https://github.com/emit-sds/emit-utils/pull/1) +- added install file, basic file checking, started multi-raster functions [`5fd1b47`](https://github.com/emit-sds/emit-utils/commit/5fd1b4784a21cc948be410565ca5e525dfbf0c7f) +- add igm map space lookups [`f5f2250`](https://github.com/emit-sds/emit-utils/commit/f5f2250a9ab6faa3bba44718f3d13509b84a9439) +- input type changes to file checks for ease, extra multi-raster info return options [`707d038`](https://github.com/emit-sds/emit-utils/commit/707d03868cb1b5ad0473350a268a158577cee20c)