Skip to content

Conversation

@maxinelasp
Copy link
Contributor

Change Summary

This addresses #2518 and includes some fixes described in that ticket.

Overview

  1. Since the SPICE transform calls take so much time, the code now transforms to J2000 as a hub for data and then goes from there to each frame to reduce the number of dynamic rotations
  2. Switching out apply_along_axis for more efficient numpy calls

This showed about a 20% improvement.

@maxinelasp maxinelasp self-assigned this Jan 6, 2026
Copy link
Contributor

@subagonsouth subagonsouth left a comment

Choose a reason for hiding this comment

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

Glad that you got some improvement. I suspect that the you could get another modest bump based on one of my comments.

I'd be interested to hear what you tried for multi-processing. I have some vague ideas about how we might be able to implement something that would get the spice multi-processing to work. I am thinking along the lines of running each of the transforms from J2000 -> DYNAMIC_FRAME in a separate process.


# Nominally, this is expected to create MAGO data. However, if the configuration
# setting for always_output_mago is set to False, it will create MAGI data.
l1d_norm.rotate_frame(ValidFrames.J2000)
Copy link
Contributor

Choose a reason for hiding this comment

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

I know that it isn't quite a clean, but I think you would see another incremental speed up by first rotating to the SRF frame, storing that data and then going to J2000 before doing the rest as you are.

As implemented, you are not taking advantage of the fixed rotation code you added for going direct from MAGI/MAGO to SRF.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's because actually, at this point in the process, the frame is DSRF, not MAGO. Internally, the code spins from MAGO/MAGI -> SRF -> DSRF as part of processing, so that fixed rotation code is being used as part of l1d_norm generation.

Copy link
Contributor

Choose a reason for hiding this comment

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

I see. Ok, so there is still some room for optimization.

  • You could store the SRF values the first time that transform occurs.
  • You could try to avoid doing the SRF -> DSRF. That transform traverses two dynamic frame transforms: SRF -> J2000 and then J2000 -> DSRF.

I will approve so you can get this optimization released but it might be worth capturing this additional possibility in a ticket.

xr.Dataset
The resulting dataset.
"""
l1d_copy = deepcopy(l1d_input)
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this deep copy of the MagL1d object copying lots of data other than the vectors that get rotated? It might be less expensive to just store the J2000 cordinates rather than copying the entire object.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The vast majority of the data in the classes is the vectors/timestamps. It is true that there is some unnecessary copying going on here, but... since there is a fair bit of logic about MAGO/MAGI and selecting which one to use inside each class, I am hesitant to pull that out and duplicate it here.

Comment on lines +300 to +307
if (
start_frame in (ValidFrames.MAGO, ValidFrames.MAGI)
and end_frame == ValidFrames.SRF
):
# Since Instrument -> spacecraft rotations are static, we can optimize
# by only passing one time into frame_transform.
single_mago_epoch = self.epoch_et[0]
single_magi_epoch = self.magi_epoch_et[0]
Copy link
Contributor

Choose a reason for hiding this comment

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

This logic looks good to me.

@maxinelasp
Copy link
Contributor Author

@subagonsouth

I'd be interested to hear what you tried for multi-processing. I have some vague ideas about how we might be able to implement something that would get the spice multi-processing to work. I am thinking along the lines of running each of the transforms from J2000 -> DYNAMIC_FRAME in a separate process.

That's basically what I did. I used the concurrent.futures framework to basically run each of the instances inside the for l1d, frame in product(input_datasets, output_frames): in parallel. Unfortunately, it repeatedly crashed with pxform/SPICE errors before completing any of the runs. I wasn't able to get it working.

Copy link
Contributor

@subagonsouth subagonsouth left a comment

Choose a reason for hiding this comment

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

Nice incremental speedup.

@subagonsouth
Copy link
Contributor

That's basically what I did. I used the concurrent.futures framework to basically run each of the instances inside the for l1d, frame in product(input_datasets, output_frames): in parallel. Unfortunately, it repeatedly crashed with pxform/SPICE errors before completing any of the runs. I wasn't able to get it working.

Interesting. Did you do any kernel furnishing as part of a setup for each process?

@maxinelasp
Copy link
Contributor Author

Interesting. Did you do any kernel furnishing as part of a setup for each process?

No, I didn't specifically furnish kernels

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants