From a7c5f9da18c7bb682b96f49c68b9ad3e8ddb8ebd Mon Sep 17 00:00:00 2001 From: Christine Kim <125395064+chkim-usgs@users.noreply.github.com> Date: Fri, 10 Jan 2025 13:06:33 -0500 Subject: [PATCH] Web spice isis (#48) * Add lsk to doubleEtToSclk * Add target for search in getTargetStates * Web spice ISIS changes * Fix log bug --- CMakeLists.txt | 3 ++ SpiceQL/src/query.cpp | 2 +- SpiceQL/src/spice_types.cpp | 5 ++- SpiceQL/src/utils.cpp | 2 +- fastapi/app/main.py | 73 ++++++++++++++++++++++++++++++++++--- 5 files changed, 76 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c468de1..f4ee248 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,8 +88,10 @@ if(SPICEQL_BUILD_LIB) ${CMAKE_CURRENT_SOURCE_DIR}/SpiceQL/db/apollo17.json ${CMAKE_CURRENT_SOURCE_DIR}/SpiceQL/db/base.json ${CMAKE_CURRENT_SOURCE_DIR}/SpiceQL/db/cassini.json + ${CMAKE_CURRENT_SOURCE_DIR}/SpiceQL/db/chandrayaan1.json ${CMAKE_CURRENT_SOURCE_DIR}/SpiceQL/db/clem1.json ${CMAKE_CURRENT_SOURCE_DIR}/SpiceQL/db/galileo.json + ${CMAKE_CURRENT_SOURCE_DIR}/SpiceQL/db/hayabusa.json ${CMAKE_CURRENT_SOURCE_DIR}/SpiceQL/db/hayabusa2.json ${CMAKE_CURRENT_SOURCE_DIR}/SpiceQL/db/juno.json ${CMAKE_CURRENT_SOURCE_DIR}/SpiceQL/db/kaguya.json @@ -102,6 +104,7 @@ if(SPICEQL_BUILD_LIB) ${CMAKE_CURRENT_SOURCE_DIR}/SpiceQL/db/mgs.json ${CMAKE_CURRENT_SOURCE_DIR}/SpiceQL/db/mro.json ${CMAKE_CURRENT_SOURCE_DIR}/SpiceQL/db/msl.json + ${CMAKE_CURRENT_SOURCE_DIR}/SpiceQL/db/newhorizons.json ${CMAKE_CURRENT_SOURCE_DIR}/SpiceQL/db/odyssey.json ${CMAKE_CURRENT_SOURCE_DIR}/SpiceQL/db/smart1.json ${CMAKE_CURRENT_SOURCE_DIR}/SpiceQL/db/tgo.json diff --git a/SpiceQL/src/query.cpp b/SpiceQL/src/query.cpp index efa3c50..0eadd64 100644 --- a/SpiceQL/src/query.cpp +++ b/SpiceQL/src/query.cpp @@ -142,7 +142,7 @@ namespace SpiceQL { for (json::json_pointer &ptr : kptrs) { SPDLOG_TRACE("Getting Latest Kernels from: {}", ptr.to_string()); - SPDLOG_TRACE("JSON: {}", kernels[ptr]); + SPDLOG_TRACE("JSON: {}", kernels[ptr].dump()); vector<vector<string>> kvect = json2DArrayTo2DVector(kernels[ptr]); vector<vector<string>> newLatest; diff --git a/SpiceQL/src/spice_types.cpp b/SpiceQL/src/spice_types.cpp index 1b56137..8100fac 100644 --- a/SpiceQL/src/spice_types.cpp +++ b/SpiceQL/src/spice_types.cpp @@ -279,12 +279,15 @@ namespace SpiceQL { string doubleEtToSclk(int frameCode, double et, string mission, bool searchKernels) { Config missionConf; + json lsks; json sclks; if (searchKernels) { - sclks = Inventory::search_for_kernelset(mission, {"lsk", "fk", "sclk"}); + lsks = Inventory::search_for_kernelset("base", {"lsk"}); + sclks = Inventory::search_for_kernelset(mission, {"fk", "sclk"}); } + KernelSet lskSet(lsks); KernelSet sclkSet(sclks); SpiceChar sclk[100]; diff --git a/SpiceQL/src/utils.cpp b/SpiceQL/src/utils.cpp index bff4df2..7d3c561 100644 --- a/SpiceQL/src/utils.cpp +++ b/SpiceQL/src/utils.cpp @@ -211,7 +211,7 @@ namespace SpiceQL { json ephemKernels = {}; if (searchKernels) { - ephemKernels = Inventory::search_for_kernelsets({mission, observer, "base"}, {"sclk", "ck", "spk", "pck", "tspk", "fk", "lsk", "fk"}, ets.front(), ets.back(), ckQuality, spkQuality); + ephemKernels = Inventory::search_for_kernelsets({mission, target, observer, "base"}, {"sclk", "ck", "spk", "pck", "tspk", "fk", "lsk", "fk"}, ets.front(), ets.back(), ckQuality, spkQuality); SPDLOG_DEBUG("{} Kernels : {}", mission, ephemKernels.dump(4)); } diff --git a/fastapi/app/main.py b/fastapi/app/main.py index 854ef05..471ce70 100644 --- a/fastapi/app/main.py +++ b/fastapi/app/main.py @@ -1,8 +1,8 @@ """Module providing SpiceQL endpoints""" from ast import literal_eval -from typing import Any -from fastapi import FastAPI +from typing import Annotated, Any +from fastapi import FastAPI, Query from pydantic import BaseModel, Field from starlette.responses import RedirectResponse import numpy as np @@ -28,14 +28,27 @@ class ResponseModel(BaseModel): statusCode: int body: ResultModel | ErrorModel +class TargetStatesRequestModel(BaseModel): + target: str + observer: str + frame: str + abcorr: str + mission: str + ets: Annotated[list[float], Query()] | float | str | None = None + startEts: float | None = None + exposureDuration: float | None = None + numOfExposures: int | None = None + ckQuality: str = "predicted" + spkQuality: str = "predicted" + # Create FastAPI instance app = FastAPI() @app.get("/") async def message(): try: - data_dir_exists = os.path.exists(pyspiceql.getDataDirectory()) - return {"data_content": os.listdir(pyspiceql.getDataDirectory()), + data_dir_exists = os.path.exists(pyspiceql.getDataDirectory()) + return {"data_content": os.listdir(pyspiceql.getDataDirectory()), "data_dir_exists": data_dir_exists, "is_healthy": data_dir_exists} except Exception as e: @@ -61,10 +74,17 @@ async def getTargetStates( if ets is not None: if isinstance(ets, str): ets = literal_eval(ets) + else: + # getTargetStates requires an iterable ets. If not iterable, make it a list. + try: + iter(ets) + except TypeError: + ets = [ets] else: if all(v is not None for v in [startEts, exposureDuration, numOfExposures]): stopEts = (exposureDuration * numOfExposures) + startEts etsNpArray = np.arange(startEts, stopEts, exposureDuration) + # If ets is a single value, np.arange yields an empty array ets = list(etsNpArray) else: raise Exception("Verify that a startEts, exposureDuration, and numOfExposures are being passed correctly.") @@ -75,6 +95,46 @@ async def getTargetStates( body = ErrorModel(error=str(e)) return ResponseModel(statusCode=500, body=body) + +@app.post("/getTargetStates") +async def getTargetStates(params: TargetStatesRequestModel): + target = params.target + observer = params.observer + frame = params.frame + abcorr = params.abcorr + mission = params.mission + ets = params.ets + startEts = params.startEts + exposureDuration = params.exposureDuration + numOfExposures = params.numOfExposures + ckQuality = params.ckQuality + spkQuality = params.spkQuality + try: + if ets is not None: + if isinstance(ets, str): + ets = literal_eval(ets) + else: + # getTargetStates requires an iterable ets. If not iterable, make it a list. + try: + iter(ets) + except TypeError: + ets = [ets] + else: + if all(v is not None for v in [startEts, exposureDuration, numOfExposures]): + stopEts = (exposureDuration * numOfExposures) + startEts + etsNpArray = np.arange(startEts, stopEts, exposureDuration) + # If ets is a single value, np.arange yields an empty array + ets = list(etsNpArray) + else: + raise Exception("Verify that startEts, exposureDuration, and numOfExposures are being passed correctly.") + result = pyspiceql.getTargetStates(ets, target, observer, frame, abcorr, mission, ckQuality, spkQuality, SEARCH_KERNELS_BOOL) + body = ResultModel(result=result) + return ResponseModel(statusCode=200, body=body) + except Exception as e: + body = ErrorModel(error=str(e)) + return ResponseModel(statusCode=500, body=body) + + @app.get("/getTargetOrientations") async def getTargetOrientations( toFrame: int, @@ -95,13 +155,14 @@ async def getTargetOrientations( etsNpArray = np.arange(startEts, stopEts, exposureDuration) ets = list(etsNpArray) else: - raise Exception("Verify that a startEts, exposureDuration, and numOfExposures are being passed correctly.") + raise Exception("Verify that startEts, exposureDuration, and numOfExposures are being passed correctly.") result = pyspiceql.getTargetOrientations(ets, toFrame, refFrame, mission, ckQuality, SEARCH_KERNELS_BOOL) body = ResultModel(result=result) return ResponseModel(statusCode=200, body=body) except Exception as e: body = ErrorModel(error=str(e)) return ResponseModel(statusCode=500, body=body) + @app.get("/strSclkToEt") async def strSclkToEt( @@ -132,7 +193,7 @@ async def doubleSclkToEt( @app.get("/doubleEtToSclk") -async def strSclkToEt( +async def doubleEtToSclk( frameCode: int, et: float, mission: str): -- GitLab