Skip to content

Commit 4762513

Browse files
committed
add (dumb) type resolver
1 parent a6f9f88 commit 4762513

3 files changed

Lines changed: 62 additions & 12 deletions

File tree

app/crossmatch/engine.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,18 @@
4747
nc.dec AS new_dec,
4848
new_desig.design AS new_design,
4949
new_cz.cz AS new_cz,
50+
rec_nat.type_name AS new_type,
5051
l2.pgc AS existing_pgc,
5152
l2.ra AS existing_ra,
5253
l2.dec AS existing_dec,
5354
l2_desig.design AS existing_design,
54-
l2_cz.cz AS existing_cz
55+
l2_cz.cz AS existing_cz,
56+
l2_nat.type_name AS existing_type
5557
FROM batch b
5658
LEFT JOIN icrs.data nc ON b.id = nc.record_id
5759
LEFT JOIN designation.data new_desig ON b.id = new_desig.record_id
5860
LEFT JOIN cz.data new_cz ON b.id = new_cz.record_id
61+
LEFT JOIN nature.data rec_nat ON b.id = rec_nat.record_id
5962
LEFT JOIN layer2.icrs l2
6063
ON nc.record_id IS NOT NULL
6164
AND ST_DWithin(
@@ -65,6 +68,7 @@
6568
)
6669
LEFT JOIN layer2.designation l2_desig ON l2.pgc = l2_desig.pgc
6770
LEFT JOIN layer2.cz l2_cz ON l2.pgc = l2_cz.pgc
71+
LEFT JOIN layer2.nature l2_nat ON l2.pgc = l2_nat.pgc
6872
ORDER BY b.id ASC
6973
""")
7074

@@ -77,6 +81,7 @@ def _evidence_to_dict(evidence: RecordEvidence) -> dict:
7781
"record_pgc": evidence.record_pgc,
7882
"claimed_pgc_exists_in_layer2": evidence.claimed_pgc_exists_in_layer2,
7983
"record_redshift": evidence.record_redshift,
84+
"record_type_name": evidence.record_type_name,
8085
}
8186

8287

@@ -105,18 +110,21 @@ def _fetch_batch(
105110
new_dec = r["new_dec"]
106111
new_design = r["new_design"]
107112
new_cz = r["new_cz"]
113+
new_type = r.get("new_type")
108114
existing_pgc = r["existing_pgc"]
109115
existing_ra = r["existing_ra"]
110116
existing_dec = r["existing_dec"]
111117
existing_design = r["existing_design"]
112118
existing_cz = r["existing_cz"]
119+
existing_type = r.get("existing_type")
113120
last_id = new_id
114121
if new_id not in by_record:
115122
by_record[new_id] = {
116123
"new_ra": None,
117124
"new_dec": None,
118125
"new_design": None,
119126
"new_redshift": None,
127+
"new_type": None,
120128
"candidates": [],
121129
}
122130
rec_data = by_record[new_id]
@@ -127,9 +135,13 @@ def _fetch_batch(
127135
rec_data["new_design"] = new_design
128136
if new_cz is not None:
129137
rec_data["new_redshift"] = float(new_cz) / C_M_S
138+
if new_type is not None:
139+
rec_data["new_type"] = new_type
130140
if existing_pgc is not None and existing_ra is not None and existing_dec is not None:
131141
existing_redshift = float(existing_cz) / C_M_S if existing_cz is not None else None
132-
rec_data["candidates"].append((existing_ra, existing_dec, existing_pgc, existing_design, existing_redshift))
142+
rec_data["candidates"].append(
143+
(existing_ra, existing_dec, existing_pgc, existing_design, existing_redshift, existing_type)
144+
)
133145

134146
return by_record, last_id
135147

@@ -200,7 +212,7 @@ def _resolve_batch(
200212
global_pgcs = design_to_pgcs.get(record_designation, []) if record_designation is not None else []
201213
neighbors: list[Neighbor] = []
202214
if new_ra is not None and new_dec is not None:
203-
for existing_ra, existing_dec, pgc, existing_design, existing_redshift in candidates:
215+
for existing_ra, existing_dec, pgc, existing_design, existing_redshift, existing_type in candidates:
204216
dist = angular_distance_deg(new_ra, new_dec, existing_ra, existing_dec)
205217
if dist <= radius_deg:
206218
neighbors.append(
@@ -211,18 +223,21 @@ def _resolve_batch(
211223
distance_deg=dist,
212224
design=existing_design,
213225
redshift=existing_redshift,
226+
type_name=existing_type,
214227
),
215228
)
216229
record_pgc = record_pgc_by_id.get(record_id) if record_pgc_by_id else None
217230
claimed_pgc_exists = record_pgc is not None and record_pgc in existing_pgcs
218231
record_redshift = rec_data.get("new_redshift")
232+
record_type_name = rec_data.get("new_type")
219233
evidence = RecordEvidence(
220234
neighbors=neighbors,
221235
record_designation=record_designation,
222236
same_name_pgcs=global_pgcs or None,
223237
record_pgc=record_pgc,
224238
claimed_pgc_exists_in_layer2=claimed_pgc_exists,
225239
record_redshift=record_redshift,
240+
record_type_name=record_type_name,
226241
)
227242
result = resolver.resolve(evidence)
228243
results.append((record_id, result))

app/crossmatch/layered.py

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,9 @@ def pgc_resolver(
123123
def redshift_resolver(
124124
evidence: RecordEvidence,
125125
previous_result: PreliminaryCrossmatchStatus,
126-
redshift_tolerance: float,
126+
redshift_tolerance: float | None,
127127
) -> tuple[PreliminaryCrossmatchStatus, PendingReason | None]:
128-
if evidence.record_redshift is None:
128+
if redshift_tolerance is None or evidence.record_redshift is None:
129129
return previous_result, None
130130

131131
record_z = evidence.record_redshift
@@ -158,6 +158,37 @@ def redshift_resolver(
158158
return previous_result, None
159159

160160

161+
def object_type_resolver(
162+
evidence: RecordEvidence, previous_result: PreliminaryCrossmatchStatus
163+
) -> tuple[PreliminaryCrossmatchStatus, PendingReason | None]:
164+
if evidence.record_type_name is None:
165+
return previous_result, None
166+
167+
if isinstance(previous_result, PreliminaryCrossmatchStatusNew):
168+
return previous_result, None
169+
170+
record_type = evidence.record_type_name
171+
172+
if isinstance(previous_result, PreliminaryCrossmatchStatusExisting):
173+
neighbor = next((n for n in evidence.neighbors if n.pgc == previous_result.pgc), None)
174+
existing_type = neighbor.type_name if neighbor is not None else None
175+
176+
if existing_type is not None and record_type != existing_type:
177+
return previous_result, PendingReason.TYPE_MISMATCH
178+
179+
return previous_result, None
180+
181+
same_type_neighbors = [
182+
n
183+
for n in evidence.neighbors
184+
if n.pgc in previous_result.pgcs and record_type is not None and n.type_name == record_type
185+
]
186+
if len(same_type_neighbors) == 1:
187+
return PreliminaryCrossmatchStatusExisting(same_type_neighbors[0].pgc), None
188+
189+
return previous_result, None
190+
191+
161192
def _preliminary_to_final(results: PreliminaryCrossmatchStatus, pending_reason: PendingReason) -> CrossmatchResult:
162193
if isinstance(results, PreliminaryCrossmatchStatusNew):
163194
return CrossmatchResult(
@@ -210,13 +241,14 @@ def resolve(self, evidence: RecordEvidence) -> CrossmatchResult:
210241
if pending_reason is not None:
211242
return _preliminary_to_final(name_result, pending_reason)
212243

213-
if self._redshift_tolerance is None:
214-
final_result = name_result
215-
else:
216-
redshift_result, pending_reason = redshift_resolver(evidence, name_result, self._redshift_tolerance)
217-
if pending_reason is not None:
218-
return _preliminary_to_final(redshift_result, pending_reason)
219-
final_result = redshift_result
244+
redshift_result, pending_reason = redshift_resolver(evidence, name_result, self._redshift_tolerance)
245+
if pending_reason is not None:
246+
return _preliminary_to_final(redshift_result, pending_reason)
247+
248+
type_result, pending_reason = object_type_resolver(evidence, redshift_result)
249+
if pending_reason is not None:
250+
return _preliminary_to_final(type_result, pending_reason)
251+
final_result = type_result
220252

221253
if isinstance(final_result, PreliminaryCrossmatchStatusNew):
222254
return CrossmatchResult(status=CrossmatchStatus.NEW, triage_status=TriageStatus.RESOLVED)

app/crossmatch/models.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class Neighbor:
1010
distance_deg: float
1111
design: str | None = None
1212
redshift: float | None = None
13+
type_name: str | None = None
1314

1415

1516
@dataclass
@@ -20,6 +21,7 @@ class RecordEvidence:
2021
record_pgc: int | None = None
2122
claimed_pgc_exists_in_layer2: bool = False
2223
record_redshift: float | None = None
24+
record_type_name: str | None = None
2325

2426

2527
class CrossmatchStatus(enum.Enum):
@@ -48,6 +50,7 @@ class PendingReason(enum.Enum):
4850
SINGLE_IN_INNER_WITH_OUTER_NEIGHBORS = "SINGLE_IN_INNER_WITH_OUTER_NEIGHBORS"
4951
SINGLE_IN_OUTER_RADIUS_ONLY = "SINGLE_IN_OUTER_RADIUS_ONLY"
5052
REDSHIFT_MISMATCH = "REDSHIFT_MISMATCH"
53+
TYPE_MISMATCH = "TYPE_MISMATCH"
5154

5255

5356
@dataclass

0 commit comments

Comments
 (0)