Unverified Commit 396524c2 authored by Trent Hare's avatar Trent Hare Committed by GitHub
Browse files

Update to isd_generate.py to allow for a NAIF radius override (#486)

* Update to isd_generate.py to allow for a NAIF radius override

Based on this RFC, we want to change our Mars pipeline to use a sphere. https://astrodiscuss.usgs.gov/t/appl-rfc-use-iau-sphere-for-hirise-dtm-projects-in-socet-set/428



Currently ALE uses the Mars elliptical defaults from the NAIF kernels. This update allows the user to override the kernels and set a spherical radius for both semimajor and semiminor in the ISD.

This is not only needed for Mars. For triaxial bodies, the IAU recommends a best-fit sphere should also be set for map products. References (DOI) are listed in the updated help for the current IAU values.

* remove extra file write if new radius is sent

* update to allow ellipse, minor help update

Add --semimajor and --semiminor parameters. I tried nargs="+" for --radius but fought for too long with argparse to do all the checking (like checking it is float). I am fine with these options but happy to hear better ways to use argparse.

* Update isd_generate.py (#619)

add in PROJ like options for radius names ("-a", "-r", "--radius", "-b")

* Radius update with changes to address original PR and review comments (#620)

* Update isd_generate.py

add in PROJ like options for radius names ("-a", "-r", "--radius", "-b")

* Update isd_generate.py

updated required statement for --semimajor to catch if only --semiminor or -b is sent. Request that radius is sent in meters and updated some typos.

---------

Co-authored-by: default avatarAustin Sanders <arsanders@usgs.gov>

---------

Co-authored-by: default avatarAustin Sanders <arsanders@usgs.gov>
parent d8994dea
Loading
Loading
Loading
Loading
+55 −3
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@ import os
import pvl
from pathlib import Path, PurePath
import sys

import json
import ale
import brotli
import json
@@ -55,6 +55,34 @@ def main():
             "and the default strategy of replacing their final suffix with "
             ".json will be used to generate the output file paths."
    )
    parser.add_argument(
        "--semimajor", "-a", "-r", "--radius",
        required="--semiminor" in sys.argv or "-b" in sys.argv,
        type=float,
        default=None,
        help="Optional spherical radius (m) override.  Setting "
             " '--semimajor 3396190.0' "
             "will override both semi-major and semi-minor radius values with the same value.  "
             "An ellipsoid can be defined if '--semiminor' is also sent.  "
             "If not specified, the default radius values "
             "(e.g.; from NAIF kernels or the ISIS Cube) will be used.  "
             "When is a semimajor specification needed? Beyond a specialized need, it is common "
             "that planetary bodies are defined as a triaxial body.  "
             "In most of these cases, the IAU WGCCRE report recommends the use of a "
             "best-fit sphere for a derived map product.  "
             "For current IAU spherical recommendations see: "
             "https://doi.org/10.1007/s10569-017-9805-5 or "
             "http://voparis-vespa-crs.obspm.fr:8080/web/ ."
             "Make sure radius values are in meters (not kilometers)."
    )
    parser.add_argument(
        "--semiminor", "-b",
        type=float,
        default=None,
        help="Optional semi-minor radius (m) override. When using this parameter, you must also define the semi-major radius. For example: "
             " '--semimajor 3396190.0 --semiminor 3376200.0' "
             "will override the semi-major and semi-minor radii to define an ellipsoid.  "
    )
    parser.add_argument(
        "-v", "--verbose",
        action="store_true",
@@ -117,9 +145,17 @@ def main():
        except (KeyError, pvl.exceptions.LexerError):
            k = [args.kernel, ]

    if args.semimajor is None:
        radii = None
    else:
        if args.semiminor is None:  # set a sphere
          radii = [args.semimajor, args.semimajor]
        else:                       # set as ellipsoid
          radii = [args.semimajor, args.semiminor]

    if len(args.input) == 1:
        try:
            file_to_isd(args.input[0], args.out, kernels=k, log_level=log_level, compress=args.compress, only_isis_spice=args.only_isis_spice, only_naif_spice=args.only_naif_spice, local=args.local)
            file_to_isd(args.input[0], args.out, radii, kernels=k, log_level=log_level, compress=args.compress, only_isis_spice=args.only_isis_spice, only_naif_spice=args.only_naif_spice, local=args.local)
        except Exception as err:
            # Seriously, this just throws a generic Exception?
            sys.exit(f"File {args.input[0]}: {err}")
@@ -129,7 +165,8 @@ def main():
        ) as executor:
            futures = {
                executor.submit(
                    file_to_isd, f, **{"kernels": k, 
                    file_to_isd, f, **{"radii": radii,
                                       "kernels": k, 
                                       "log_level": log_level, 
                                       "only_isis_spice": args.only_isis_spice, 
                                       "only_naif_spice": args.only_naif_spice,
@@ -151,6 +188,7 @@ def main():
def file_to_isd(
    file: os.PathLike,
    out: os.PathLike = None,
    radii: list = None,
    kernels: list = None,
    log_level=logging.WARNING,
    compress=False,
@@ -196,6 +234,18 @@ def file_to_isd(
    else:
        usgscsm_str = ale.loads(file, props=props, verbose=log_level>logging.INFO, only_isis_spice=only_isis_spice, only_naif_spice=only_naif_spice)

    if radii is not None:
        # first convert to kilometers for ISD
        radii = [x / 1000.0 for x in radii] 
        
        usgscsm_json = json.loads(usgscsm_str)
        usgscsm_json["radii"]["semimajor"] = radii[0]
        usgscsm_json["radii"]["semiminor"] = radii[1]
        logger.info(f"Overriding radius to (km):")
        logger.info(usgscsm_json["radii"])
        usgscsm_str = json.dumps(usgscsm_json, indent=2)

    logger.info(f"Writing: {isd_file}")
    if compress:
        logger.info(f"Writing: {os.path.splitext(isd_file)[0] + '.br'}")
        compress_json(usgscsm_str, os.path.splitext(isd_file)[0] + '.br')
@@ -203,6 +253,7 @@ def file_to_isd(
        logger.info(f"Writing: {isd_file}")  
        isd_file.write_text(usgscsm_str)


    return

def compress_json(json_data, output_file):
@@ -257,3 +308,4 @@ if __name__ == "__main__":
        sys.exit(main())
    except ValueError as err:
        sys.exit(err)