Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ephemeris service #11

Merged
merged 62 commits into from
Aug 27, 2024
Merged

Ephemeris service #11

merged 62 commits into from
Aug 27, 2024

Conversation

szilac
Copy link
Collaborator

@szilac szilac commented Jul 23, 2024

Change Description

The branch contains the full ephemeris service component. ephemeris_client.py controls the various interfaces. The outputs are uniformized. Each QueryResult returns a dataclass object or a QueryResult list.

Fixed issues:
--> closes #6
--> closes #7
--> closes #8
--> closes #10

New Feature Checklist

  • Now it is a complete ephemeris service. One can call the ephemeris_client.py with args and control the different interfaces, like JPL Horizons, Miriade, custom data loader
  • All of the relevant methods contains save_data options (default: False)

Documentation Change Checklist

  • Updated most of the docstring

szilac added 30 commits July 9, 2024 12:48
	modified:   src/forcedphot/horizons_interface.py
	deleted:    src/forcedphot/data/targets.csv
	modified:   src/forcedphot/local_dataclasses.py
	modified:   tests/forcedphot/conftest.py
	modified:   src/forcedphot/horizons_interface.py
	modified:   tests/forcedphot/test_horizons_interface.py
	modified:   src/forcedphot/horizons_interface.py
	modified:   src/forcedphot/local_dataclasses.py
	modified:   tests/forcedphot/conftest.py
	deleted:    tests/forcedphot/test_example_module.py
	modified:   tests/forcedphot/test_horizons_interface.py
	modified:   local_dataclasses.py
…eryResult dataclass now.

	modified:   src/forcedphot/horizons_interface.py
	modified:   src/forcedphot/ephemeris/horizons_interface.py
	modified:   tests/forcedphot/ephemeris/test_ephemeris_client.py
@szilac szilac marked this pull request as ready for review July 23, 2024 16:49
@mschwamb mschwamb requested review from mkelley and akoumjian July 23, 2024 17:14
@mschwamb
Copy link
Member

I think data directory should go under tests

@mschwamb
Copy link
Member

Discussion from the telecon is that ecsv handling is going to be updated

Copy link
Collaborator

@mkelley mkelley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some initial comments. I will review more later.

src/forcedphot/ephemeris/local_dataclasses.py Outdated Show resolved Hide resolved
src/forcedphot/ephemeris/local_dataclasses.py Outdated Show resolved Hide resolved
src/forcedphot/ephemeris/horizons_interface.py Outdated Show resolved Hide resolved
src/forcedphot/ephemeris/data_loader.py Outdated Show resolved Hide resolved
src/forcedphot/ephemeris/horizons_interface.py Outdated Show resolved Hide resolved
src/forcedphot/ephemeris/horizons_interface.py Outdated Show resolved Hide resolved
akoumjian
akoumjian previously approved these changes Jul 30, 2024
Copy link
Collaborator

@akoumjian akoumjian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @mkelley about being explicit regarding time scale on every Time initialization, as well as documenting what scale we use in serialization since the scale does not survive the serialization process. Non-blocking suggestions from my side.

Comment on lines +137 to +154
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)}")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This kind of looks like a unit test.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, a little bit. I was just verifying that the module was working.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we have it, why not put these files into the test data directory and make it a unit test?


def query_single(
self,
service: str,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would personally prefer service as a keyword argument. That way the client can use its own logic to intelligently choose which service to use, but it can be forced to use a particular downstream service.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have changed the service part. Now the default is horizons and can be overridden with --service keyword.

List of query results.
"""
if service.lower() == "horizons":
return HorizonsInterface.query_ephemeris_from_csv(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason the _from_csv can't live on the generic client? If the CSV input format is identical, I would probably make it the job of the generic client to handle parsing the csv and loading it into the format for the query.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can change it that way if you think it would be better, but I prefer to have all the functions for a particular service in one place.
However, it is true that the code fragment is the same in both services...

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be cleaner to have one place where the csv is parsed and that the pluggable backends take as input the pre-parsed data, but not a blocker.

	renamed:    src/forcedphot/ephemeris/local_dataclasses.py -> src/forcedphot/ephemeris/data_model.py
	modified:   src/forcedphot/ephemeris/ephemeris_client.py
	modified:   src/forcedphot/ephemeris/horizons_interface.py
	modified:   src/forcedphot/ephemeris/miriade_interface.py
	renamed:    src/forcedphot/data/targets.csv -> tests/forcedphot/ephemeris/data/targets.csv
	modified:   tests/forcedphot/ephemeris/test_data_loader.py
	modified:   tests/forcedphot/ephemeris/test_ephemeris_client.py
	modified:   tests/forcedphot/ephemeris/test_horizons_interface.py
	modified:   tests/forcedphot/ephemeris/test_miriade_interface.py
	modified:   src/forcedphot/ephemeris/horizons_interface.py
	modified:   src/forcedphot/ephemeris/miriade_interface.py
	modified:   tests/forcedphot/ephemeris/test_ephemeris_client.py
	modified:   tests/forcedphot/ephemeris/test_horizons_interface.py
Copy link
Collaborator

@mkelley mkelley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I learned a couple tricks reviewing your code 👍🏻

src/forcedphot/ephemeris/miriade_interface.py Outdated Show resolved Hide resolved
src/forcedphot/ephemeris/miriade_interface.py Outdated Show resolved Hide resolved
szilac added 6 commits August 13, 2024 16:25
	modified:   src/forcedphot/ephemeris/data_model.py
	modified:   src/forcedphot/ephemeris/horizons_interface.py
	modified:   src/forcedphot/ephemeris/miriade_interface.py
	modified:   tests/forcedphot/ephemeris/test_data_loader.py
	modified:   tests/forcedphot/ephemeris/test_horizons_interface.py
	modified:   tests/forcedphot/ephemeris/test_miriade_interface.py
	modified:   src/forcedphot/ephemeris/miriade_interface.py
	modified:   tests/forcedphot/ephemeris/test_horizons_interface.py
	modified:   tests/forcedphot/ephemeris/test_miriade_interface.py
@mschwamb mschwamb requested review from mkelley and akoumjian August 13, 2024 17:20
@mschwamb
Copy link
Member

@akoumjian Are you happy to approve?

@mschwamb mschwamb requested a review from talister August 26, 2024 10:02
@mschwamb
Copy link
Member

@talister can you review if @akoumjian by your morning Tuesday? It would be good to get this part into the repo

Copy link
Collaborator

@talister talister left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me. I've highlighted where you may want to refactor the logging into a base logging configuration file later once more modules are written but this is OK now.
Similarly the argument parser for the EphemerisClient could do with more examples in the help of the specific format of some of the entries or embedding the default value into the help text, but since this client won't be used by end users directly, it's more appropriate that this is applied to the user-facing part of the system.

Load ephemeris data from multiple ECSV files and return them as a list of EphemerisData objects.
"""

# Set up logging
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is OK for now but we may want consider splitting the base logging configuration into a separate file (e.g. this brief demo) more modules are written

Copy link
Collaborator

@akoumjian akoumjian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of suggestions remain, but none are blocking.

Comment on lines +137 to +154
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)}")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we have it, why not put these files into the test data directory and make it a unit test?

List of query results.
"""
if service.lower() == "horizons":
return HorizonsInterface.query_ephemeris_from_csv(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be cleaner to have one place where the csv is parsed and that the pluggable backends take as input the pre-parsed data, but not a blocker.

@mschwamb mschwamb merged commit b19efc8 into main Aug 27, 2024
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants