Skip to content

Commit

Permalink
Merge pull request #19 from lsst-sssc/object_detection_controller
Browse files Browse the repository at this point in the history
Object detection controller
  • Loading branch information
szilac authored Nov 12, 2024
2 parents 578eec8 + de97609 commit 8fe0fc1
Show file tree
Hide file tree
Showing 15 changed files with 748 additions and 461 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ environments. If you have conda installed locally, you can run the following to
create and activate a new environment.

```
>> conda create env -n <env_name> python=3.10
>> conda create -n <env_name> python=3.10
>> conda activate <env_name>
```

Expand Down
20 changes: 0 additions & 20 deletions src/forcedphot/ephemeris/data_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,23 +132,3 @@ def load_multiple_ephemeris_files(file_paths: list[str]) -> list[EphemerisData]:
raise # Re-raise the exception to be caught by the calling function

return ephemeris_list


if __name__ == "__main__":
# Example usage
# file_path = "./Ceres_2024-01-01_00-00-00.000_2025-12-31_23-59-00.000.ecsv"
# try:
# ephemeris_data = DataLoader.load_ephemeris_from_ecsv(file_path)
# except Exception as e:
# print(f"Error: {str(e)}")

# Example of loading multiple files
file_paths = [
"./Ceres_2024-01-01_00-00-00.000_2025-12-31_23-59-00.000.ecsv",
"./Encke_2024-01-01_00-00-00.000_2024-06-30_23-59-00.000.ecsv",
]
try:
ephemeris_list = DataLoader.load_multiple_ephemeris_files(file_paths)
print(f"Loaded {len(ephemeris_list)} ephemeris files.")
except Exception as e:
print(f"Error: {str(e)}")
146 changes: 33 additions & 113 deletions src/forcedphot/ephemeris/ephemeris_client.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import argparse
import logging
from typing import Union

import pandas as pd
from astropy.time import Time

from forcedphot.ephemeris.data_loader import DataLoader
Expand Down Expand Up @@ -100,15 +100,38 @@ def query_from_csv(
Returns:
List of query results.
"""
if service.lower() == "horizons":
return HorizonsInterface.query_ephemeris_from_csv(
csv_file, observer_location, save_data=save_data
)
elif service.lower() == "miriade":
return MiriadeInterface.query_ephemeris_from_csv(csv_file, observer_location, save_data=save_data)
else:
self.logger.error(f"Invalid service: {service}. Use 'horizons' or 'miriade'.")
return None
try:
results = []
df = pd.read_csv(csv_file)

for _index, row in df.iterrows():
query = QueryInput(
target=row.iloc[0],
target_type=row.iloc[1],
start=Time(row.iloc[2], format="iso", scale="utc"),
end=Time(row.iloc[3], format="iso", scale="utc"),
step=row.iloc[4],
)

query_result = self.query_single(
service,
query.target,
query.target_type,
query.start,
query.end,
query.step,
observer_location,
save_data=save_data,
)

if query_result is not None:
results.append(query_result)

return results

except Exception as e:
self.logger.error(f"An error occured during query for CSV file {csv_file}")
self.logger.error(f"Error details: {str(e)}")

def load_ephemeris_from_ecsv(self, ecsv_file: str) -> EphemerisData:
"""
Expand All @@ -133,106 +156,3 @@ def load_ephemeris_from_multi_ecsv(self, ecsv_files: list[str]) -> EphemerisData
List of EphemerisData: List of ephemeris data as a dataclass.
"""
return DataLoader.load_multiple_ephemeris_files(ecsv_files)


def main():
"""
Main function to handle command-line arguments and execute ephemeris queries.
This function parses command-line arguments to determine whether to perform a single
query or batch processing from a CSV file. It supports querying ephemeris data using
either the JPL Horizons or Miriade services.
Command-line Arguments:
--service (str): The service to use for querying ('horizons' or 'miriade') deafult is 'horizons'.
--csv (str): Path to the CSV file for batch processing (optional).
--ecsv (str): Path to the ECSV file for single query (optional) or
list of ECSV files for batch processing (optional).
--target (str): Target object for a single query (optional).
--target_type (str): Target object type for a single query (optional).
--start (str): Start time for a single query (optional).
--end (str): End time for a single query (optional).
--step (str): Time step for a single query (optional).
--location (str): Observer location code (default is 'X05').
--save_data (bool): Flag to save query results as ECSV files (default is False).
Behavior:
- If the --csv argument is provided, the function will process multiple queries from the specified
CSV file.
- If all single query parameters (--target, --target_type, --start, --end, --step) are provided,
the function will perform a single query.
- If neither a CSV file nor all single query parameters are provided, the function will display
an error message.
Example Usage:
python ephemeris_client.py --service horizons --csv queries.csv --save_data
python ephemeris_client.py --service miriade --target Ceres --target_type smallbody
--start 2023-01-01 --end 2023-01-02 --step 1h
python ephemeris_client.py --ecsv ceres_ephemeris.ecsv,vesta_ephemeris.ecsv
Returns:
result (list[EphemerisData]): List of ephemeris data as a dataclass.
"""
parser = argparse.ArgumentParser(
description="Query ephemeris data using Horizons or Miriade services or"
" load ephemeris data from existing ECSV."
)
parser.add_argument(
"--service", choices=["horizons", "miriade"], default="horizons", help="Service to use for querying"
)
parser.add_argument(
"--ecsv", help="Path to ECSV file (or a list separated with ,) containing ephemeris data"
)
parser.add_argument("--csv", help="Path to CSV file for batch processing")
parser.add_argument("--target", help="Target object for single query")
parser.add_argument("--target_type", help="Target object type for single query")
parser.add_argument("--start", help="Start time for single query")
parser.add_argument("--end", help="End time for single query")
parser.add_argument("--step", help="Time step for single query")
parser.add_argument(
"--location",
default=EphemerisClient.DEFAULT_OBSERVER_LOCATION,
help="Observer location code, default: Rubin(X05)",
)
parser.add_argument("--save_data", action="store_true", help="Save query results as ECSV files")

args = parser.parse_args()

client = EphemerisClient()

if args.csv:
results = client.query_from_csv(args.service, args.csv, args.location, args.save_data)
elif all([args.target, args.target_type, args.start, args.end, args.step]):
result = client.query_single(
args.service,
args.target,
args.target_type,
args.start,
args.end,
args.step,
args.location,
args.save_data,
)
results = [result] if result else []
elif args.ecsv:
ecsv_files = args.ecsv.split(",") # Assume multiple files are comma-separated
if len(ecsv_files) > 1:
results = client.load_ephemeris_from_multi_ecsv(ecsv_files)
else:
results = client.load_ephemeris_from_ecsv(args.ecsv)
else:
parser.error(
"Either provide a CSV file or all single query parameters"
" like target, target_type,start, end, step"
" or ECSV file containing ephemeris data"
)

if results:
print(f"Successfully queried {len(results)} object(s)")
return results
else:
print("No results obtained")


if __name__ == "__main__":
main()
100 changes: 11 additions & 89 deletions src/forcedphot/ephemeris/horizons_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

import astropy.units as u
import numpy as np
import pandas as pd
from astropy.table import Table, vstack
from astropy.time import Time
from astroquery.jplhorizons import Horizons
Expand Down Expand Up @@ -307,105 +306,28 @@ def query_single_range(self, query: QueryInput, save_data: bool = False) -> Quer

return None

@classmethod
def query_ephemeris_from_csv(
cls, csv_filename: str, observer_location=DEFAULT_OBSERVER_LOCATION, save_data: bool = False
):
"""
Query ephemeris for multiple celestial objects from JPL Horizons based on a CSV file and save
the data to CSV files.
Parameters
----------
csv_filename : str
The filename of the input CSV file containing target, start time, end time, and step.
observer_location : str, optional
The observer location code. Default is "X05" (Rubin location).
save_data : bool, optional
Whether to save the data to ECSV files. Default is False.
Returns
-------
List of QueryResult or None
The queried ephemeris data wrapped in a QueryResult object if successful,
or None if an error occurs. Also, the method saves the data to ECSV files.
Raises
------
Exception
If an error occurs during the ECSV processing or querying. The error is logged,
but not re-raised.
Notes
-----
- The input CSV file should have columns for target, start time, end time, and step.
- The method creates a separate ECSV file for each target in the input file.
- The method logs information about the query process and any errors that occur.
"""
try:
total_start_time = time.time()

# Create an empty list to store the results
results = []
# Read the CSV file
df = pd.read_csv(csv_filename)

# Create HorizonsInterface instance with the specified observer location
horizons_interface = cls(observer_location)

# Process each row in the CSV file
for _index, row in df.iterrows():
query = QueryInput(
target=row.iloc[0],
target_type=row.iloc[1],
start=Time(row.iloc[2], scale="utc"),
end=Time(row.iloc[3], scale="utc"),
step=row.iloc[4],
)

# Initialze the query
query_result = horizons_interface.query_single_range(query)

if query_result is not None:
# Append the result to the list
results.append(query_result)

if save_data:
horizons_interface.save_horizons_data_to_ecsv(query, query_result.ephemeris)

total_end_time = time.time()
cls.logger.info(
f"Total time taken for processing the ECSV file:"
f"{total_end_time - total_start_time:.2f} seconds."
)
return results

except Exception as e:
cls.logger.error(f"An error occurred during query for CSV file {csv_filename}")
cls.logger.error(f"Error details: {str(e)}")


# Example usage
if __name__ == "__main__":
HorizonsInterface.query_ephemeris_from_csv("./targets.csv", save_data=True)
# HorizonsInterface.query_ephemeris_from_csv("./targets.csv", save_data=True)

# Define the target query parameters
target_query = QueryInput(
target="Ceres",
target_type="smallbody",
start=Time("2024-01-01 00:00"),
end=Time("2025-11-30 23:59"),
step="1h",
)
# target_query = QueryInput(
# target="Ceres",
# target_type="smallbody",
# start=Time("2024-01-01 00:00"),
# end=Time("2025-11-30 23:59"),
# step="1h",
# )
# horizons = HorizonsInterface()
# result = horizons.query_single_range(query=target_query)

target_query = QueryInput(
target="Encke",
target_type="comet_name",
start=Time("2024-01-01 00:00"),
end=Time("2025-11-30 23:59"),
end=Time("2025-12-31 23:59"),
step="1h",
)
# horizons = HorizonsInterface()
# result = horizons.query_single_range(query=target_query, save_data=True)
horizons = HorizonsInterface()
result = horizons.query_single_range(query=target_query, save_data=False)
Loading

0 comments on commit 8fe0fc1

Please sign in to comment.