|
5 | 5 | from typing import Any |
6 | 6 |
|
7 | 7 | import numpy as np |
| 8 | +import pyarrow as pa |
8 | 9 | import pyarrow.compute as pc |
9 | 10 | import pyarrow.dataset as ds |
10 | 11 | import pyarrow.parquet as pq |
|
16 | 17 | from .arrow_utils import parse_item |
17 | 18 | from .dynamic_class import DynamicClass |
18 | 19 |
|
| 20 | + |
| 21 | +def rotate_gal_pyarrow(ra, dec, rot_ra, rot_dec, rot_x_ang=0): |
| 22 | + """ |
| 23 | + Rotate ra, dec in degrees to new coordinate |
| 24 | + given three rotation angles |
| 25 | + """ |
| 26 | + |
| 27 | + # --- Degrees to radians --- |
| 28 | + k = math.pi / 180.0 |
| 29 | + ra_r = pc.multiply(ra, k) |
| 30 | + dec_r = pc.multiply(dec, k) |
| 31 | + phi_r = rot_ra * k # scalar |
| 32 | + theta_r = rot_dec * k # scalar |
| 33 | + |
| 34 | + # --- Step 1: (RA, Dec) → Cartesian --- |
| 35 | + x = pc.multiply(pc.cos(dec_r), pc.cos(ra_r)) |
| 36 | + y = pc.multiply(pc.cos(dec_r), pc.sin(ra_r)) |
| 37 | + z = pc.sin(dec_r) |
| 38 | + |
| 39 | + # --- Step 2a: rot_z(-phi) --- |
| 40 | + cp, sp = math.cos(-phi_r), math.sin(-phi_r) |
| 41 | + x1 = pc.subtract(pc.multiply(pc.scalar(cp), x), pc.multiply(pc.scalar(sp), y)) |
| 42 | + y1 = pc.add(pc.multiply(pc.scalar(sp), x), pc.multiply(pc.scalar(cp), y)) |
| 43 | + z1 = z |
| 44 | + |
| 45 | + # --- Step 2b: rot_y(theta) --- |
| 46 | + ct, st = math.cos(theta_r), math.sin(theta_r) |
| 47 | + x2 = pc.add(pc.multiply(pc.scalar(ct), x1), pc.multiply(pc.scalar(st), z1)) |
| 48 | + y2 = y1 |
| 49 | + z2 = pc.subtract(pc.multiply(pc.scalar(ct), z1), pc.multiply(pc.scalar(st), x1)) |
| 50 | + |
| 51 | + # --- Step 2c: Optional rot_x --- |
| 52 | + if rot_x_ang != 0: |
| 53 | + cx = math.cos(rot_x_ang * k) |
| 54 | + sx = math.sin(rot_x_ang * k) |
| 55 | + x3 = x2 |
| 56 | + y3 = pc.subtract(pc.multiply(pc.scalar(cx), y2), pc.multiply(pc.scalar(sx), z2)) |
| 57 | + z3 = pc.add(pc.multiply(pc.scalar(sx), y2), pc.multiply(pc.scalar(cx), z2)) |
| 58 | + else: |
| 59 | + x3, y3, z3 = x2, y2, z2 |
| 60 | + |
| 61 | + # --- Step 3: Cartesian → (RA, Dec) --- |
| 62 | + ra_deg = pc.multiply(pc.atan2(y3, x3), 180 / math.pi) |
| 63 | + new_ra = pc.if_else( |
| 64 | + pc.less(ra_deg, 0), |
| 65 | + pc.add(ra_deg, 360), |
| 66 | + ra_deg |
| 67 | + ) |
| 68 | + new_dec = pc.multiply(pc.asin(pc.min_element_wise(pc.max_element_wise(z3, -1.0), 1.0)), 180/math.pi) |
| 69 | + |
| 70 | + return new_ra, new_dec |
| 71 | + |
| 72 | + |
19 | 73 | COLUMNS = [ |
20 | 74 | "galaxy_id", |
21 | 75 | "ra", |
|
140 | 194 | PROJECTIONS_CARDINAL = [ |
141 | 195 | { |
142 | 196 | # "Roman_K213": pc.field("k213"), |
143 | | - "shift_ra": pc.add(pc.field("ra"), -60.), |
144 | | - "shift_dec": pc.multiply(pc.field("dec"), -1.), |
| 197 | + #"shift_ra": pc.add(pc.field("ra"), -60.), |
| 198 | + #"shift_dec": pc.multiply(pc.field("dec"), -1.), |
145 | 199 | "Ellipticity1": pc.field("Ellipticity_1"), |
146 | 200 | "Ellipticity2": pc.field("Ellipticity_2"), |
147 | 201 | "mag_y_euclid_nisp": pc.field("Euclid_Y"), |
|
214 | 268 |
|
215 | 269 | PROJECTIONS_FLAGSHIP = [ |
216 | 270 | { |
217 | | - "ra": pc.if_else( |
218 | | - pc.greater(pc.add(pc.field("ra_mag_gal"), pc.scalar(180)), pc.scalar(360)), |
219 | | - pc.subtract(pc.field("ra_mag_gal"), pc.scalar(180)), |
220 | | - pc.add(pc.field("ra_mag_gal"), pc.scalar(180)) |
221 | | - ), |
222 | | - "dec": pc.multiply(pc.scalar(-1), pc.field("dec_mag_gal")), |
| 271 | + #"ra": pc.if_else( |
| 272 | + # pc.greater(pc.add(pc.field("ra_mag_gal"), pc.scalar(180)), pc.scalar(360)), |
| 273 | + # pc.subtract(pc.field("ra_mag_gal"), pc.scalar(180)), |
| 274 | + # pc.add(pc.field("ra_mag_gal"), pc.scalar(180)) |
| 275 | + # ), |
| 276 | + #"dec": pc.multiply(pc.scalar(-1), pc.field("dec_mag_gal")), |
223 | 277 | "redshift": pc.field("observed_redshift_gal"), |
224 | 278 | "mag_u_lsst": pc.subtract( |
225 | 279 | pc.multiply(pc.scalar(-2.5), pc.log10(pc.field("lsst_u_el_model3_ext"))), pc.scalar(48.6) |
@@ -307,7 +361,16 @@ class RailReducer(Configurable, DynamicClass): |
307 | 361 | output catalog |
308 | 362 | """ |
309 | 363 |
|
310 | | - config_options: dict[str, StageParameter] = {} |
| 364 | + config_options: dict[str, StageParameter] = dict( |
| 365 | + rotation_angle=StageParameter( |
| 366 | + list, [0.0, 0.0, 0.0], fmt="%s", |
| 367 | + msg="Three rotation angles, applied to RA, DEC, and around the line of sight axis", |
| 368 | + ), |
| 369 | + flip_dec=StageParameter( |
| 370 | + float, False, fmt="%f", |
| 371 | + msg="Shortcut to flip sign of Dec. If True, multiply Dec by -1. Excecuted BEFORE the rotator", |
| 372 | + ), |
| 373 | + ) |
311 | 374 | sub_classes: dict[str, type[DynamicClass]] = {} |
312 | 375 |
|
313 | 376 | def __init__(self, **kwargs: Any): |
@@ -343,7 +406,12 @@ def run( |
343 | 406 | class RomanRubinReducer(RailReducer): |
344 | 407 | """Class to reduce the 'roman_rubin' simulation input files for pz analysis""" |
345 | 408 |
|
346 | | - config_options: dict[str, StageParameter] = dict( |
| 409 | + #config_options: dict[str, StageParameter] = dict( |
| 410 | + # name=StageParameter(str, None, fmt="%s", required=True, msg="Reducer Name"), |
| 411 | + # cuts=StageParameter(dict, {}, fmt="%s", msg="Selections"), |
| 412 | + #) |
| 413 | + config_options = RailReducer.config_options.copy() |
| 414 | + config_options.update( |
347 | 415 | name=StageParameter(str, None, fmt="%s", required=True, msg="Reducer Name"), |
348 | 416 | cuts=StageParameter(dict, {}, fmt="%s", msg="Selections"), |
349 | 417 | ) |
@@ -430,7 +498,12 @@ class CardinalReducer(RailReducer): |
430 | 498 | preprocessing stage was performed to put them into pyarrow parquet |
431 | 499 | """ |
432 | 500 |
|
433 | | - config_options: dict[str, StageParameter] = dict( |
| 501 | + #config_options: dict[str, StageParameter] = dict( |
| 502 | + # name=StageParameter(str, None, fmt="%s", required=True, msg="Reducer Name"), |
| 503 | + # cuts=StageParameter(dict, {}, fmt="%s", msg="Selections"), |
| 504 | + #) |
| 505 | + config_options = RailReducer.config_options.copy() |
| 506 | + config_options.update( |
434 | 507 | name=StageParameter(str, None, fmt="%s", required=True, msg="Reducer Name"), |
435 | 508 | cuts=StageParameter(dict, {}, fmt="%s", msg="Selections"), |
436 | 509 | ) |
@@ -479,6 +552,16 @@ def run( |
479 | 552 | ), |
480 | 553 | ) |
481 | 554 |
|
| 555 | + rot_ra, rot_dec, rot_x = self.config.rotation_angle |
| 556 | + ra = pc.field("ra") |
| 557 | + if self.config.flip_dec == True: |
| 558 | + dec = pc.multiply(pc.scalar(-1), pc.field("dec")) |
| 559 | + else: |
| 560 | + dec = pc.field("dec") |
| 561 | + new_ra, new_dec = rotate_gal_pyarrow(ra, dec, float(rot_ra), float(rot_dec), rot_x_ang=float(rot_x)) |
| 562 | + PROJECTIONS_CARDINAL[0]['shift_ra'] = new_ra |
| 563 | + PROJECTIONS_CARDINAL[0]['shift_dec'] = new_dec |
| 564 | + |
482 | 565 | column_projection = {k: pc.field(k) for k in COLUMNS_CARDINAL} |
483 | 566 | projection = column_projection |
484 | 567 | project_nodes = [] |
@@ -514,7 +597,12 @@ def run( |
514 | 597 | class FlagshipReducer(RailReducer): |
515 | 598 | """Class to reduce the 'flagship' simulation input files for pz analysis""" |
516 | 599 |
|
517 | | - config_options: dict[str, StageParameter] = dict( |
| 600 | + #config_options: dict[str, StageParameter] = dict( |
| 601 | + # name=StageParameter(str, None, fmt="%s", required=True, msg="Reducer Name"), |
| 602 | + # cuts=StageParameter(dict, {}, fmt="%s", msg="Selections"), |
| 603 | + #) |
| 604 | + config_options = RailReducer.config_options.copy() |
| 605 | + config_options.update( |
518 | 606 | name=StageParameter(str, None, fmt="%s", required=True, msg="Reducer Name"), |
519 | 607 | cuts=StageParameter(dict, {}, fmt="%s", msg="Selections"), |
520 | 608 | ) |
@@ -559,6 +647,17 @@ def run( |
559 | 647 | ), |
560 | 648 | ) |
561 | 649 |
|
| 650 | + # add ra, dec projections with rotation |
| 651 | + rot_ra, rot_dec, rot_x = self.config.rotation_angle |
| 652 | + ra = pc.field("ra_mag_gal") |
| 653 | + if self.config.flip_dec == True: |
| 654 | + dec = pc.multiply(pc.scalar(-1), pc.field("dec_mag_gal")) |
| 655 | + else: |
| 656 | + dec = pc.field("dec_mag_gal") |
| 657 | + new_ra, new_dec = rotate_gal_pyarrow(ra, dec, float(rot_ra), float(rot_dec), rot_x_ang=float(rot_x)) |
| 658 | + PROJECTIONS_FLAGSHIP[0]['ra'] = new_ra |
| 659 | + PROJECTIONS_FLAGSHIP[0]['dec'] = new_dec |
| 660 | + |
562 | 661 | column_projection = {k: pc.field(k) for k in COLUMNS_FLAGSHIP} |
563 | 662 | projection = column_projection |
564 | 663 | project_nodes = [] |
@@ -594,7 +693,12 @@ def run( |
594 | 693 | class ComCamReducer(RailReducer): |
595 | 694 | """Class to reduce the 'com_cam' input files for pz analysis""" |
596 | 695 |
|
597 | | - config_options: dict[str, StageParameter] = dict( |
| 696 | + #config_options: dict[str, StageParameter] = dict( |
| 697 | + # name=StageParameter(str, None, fmt="%s", required=True, msg="Reducer Name"), |
| 698 | + # cuts=StageParameter(dict, {}, fmt="%s", msg="Selections"), |
| 699 | + #) |
| 700 | + config_options = RailReducer.config_options.copy() |
| 701 | + config_options.update( |
598 | 702 | name=StageParameter(str, None, fmt="%s", required=True, msg="Reducer Name"), |
599 | 703 | cuts=StageParameter(dict, {}, fmt="%s", msg="Selections"), |
600 | 704 | ) |
@@ -679,7 +783,12 @@ def run( |
679 | 783 | class DP1Reducer(RailReducer): |
680 | 784 | """Class to reduce the 'DP1' input files for pz analysis""" |
681 | 785 |
|
682 | | - config_options: dict[str, StageParameter] = dict( |
| 786 | + #config_options: dict[str, StageParameter] = dict( |
| 787 | + # name=StageParameter(str, None, fmt="%s", required=True, msg="Reducer Name"), |
| 788 | + # cuts=StageParameter(dict, {}, fmt="%s", msg="Selections"), |
| 789 | + #) |
| 790 | + config_options = RailReducer.config_options.copy() |
| 791 | + config_options.update( |
683 | 792 | name=StageParameter(str, None, fmt="%s", required=True, msg="Reducer Name"), |
684 | 793 | cuts=StageParameter(dict, {}, fmt="%s", msg="Selections"), |
685 | 794 | ) |
|
0 commit comments