# How are DIAObjects created?

**URL:** <https://www.rubin.community/t/how-are-diaobjects-created/11257>\
**Category:** Support\
**Created:** [November 11, 2025, 2:21pm UTC](https://www.rubin.community/t/how-are-diaobjects-created/11257 "2025-11-11T14:21:04Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![deppep](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/deppep/32/3217_2.png) [@deppep](https://www.rubin.community/u/deppep)\
**Post date:** [November 11, 2025, 2:21pm UTC](https://www.rubin.community/t/how-are-diaobjects-created/11257/1 "2025-11-11T14:21:05Z")

</div>

Hello,

I’m trying to understand the exact algorithm used for creating the [DiaObject](https://sdm-schemas.lsst.io/dp1.html#DiaObject) table. According to the [DP1 paper](https://rtn-095.lsst.io/):

> The DiaObject catalog contains the astrophysical objects that DiaSources are associated with (i.e., the “DiaObjects”). The DiaObject catalog only contains non-Solar System Objects; Solar System Objects are instead recorded in the SSObject catalog (see below for a description of the SSObject catalog). When a DiaSource is identified, the DiaObject and SSObject catalogs are searched for objects to associate it with. If no association is found, a new DiaObject is created and the DiaSource is associated to it.

Based on this description, my interpretation of the algorithm is:

```python
for source in diaSources_sorted_by_time:
    # Search for compatible DiaObjects within spatial tolerance
    candidate_objects = find_objects_within_cone(
        center=source.centroid, 
        radius=source.positional_error
    )
    
    if candidate_objects is empty:
        # No match found: create new DiaObject
        create_new_diaobject(source.id)
    else:
        # Multiple matches: associate with closest object
        source.diaObjectId = min(candidate_objects, key=distance_to_source)

```

This however is only my interpretation. I can’t find further details. In particular, I’d like to know:

1. What matching criteria are used to determine if an existing object is “compatible” with a source, exactly?
2. When multiple objects match a source, which object is selected? Is it purely nearest-neighbor by (error-weighted?) angular distance? Are other factors considered?
3. Do you expect the same strategy to be used for future data releases?

Thank you!

---

<div class="post-metadata">

**Author:** ![isullivan](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/isullivan/32/1866_2.png) [@isullivan](https://www.rubin.community/u/isullivan)\
**Post date:** [November 11, 2025, 7:23pm UTC](https://www.rubin.community/t/how-are-diaobjects-created/11257/2 "2025-11-11T19:23:00Z")

</div>

The algorithm for creating new DiaObjects is different in Alert Production [AP] and for the Data Releases [DRP]. In DRP we have all of the DiaSources available at the same time, and perform an N-way match to all of the DiaSources within the same spatial patch similar to your interpretation (code is [here](https://github.com/lsst/pipe_tasks/blob/main/python/lsst/pipe/tasks/simpleAssociation.py)). In AP, we use the “optimistic pattern matcher B” from section 2.3 of [https://arxiv.org/pdf/0710.3618](https://arxiv.org/pdf/0710.3618)  
To your specific questions:

1. Association is purely based on separation, though quality cuts are used to exclude DiaSources.

2. Yes, when there are multiple matching objects to a source, the closest one is picked. In the future we intend to include a list of the next closest objects so that users can re-associate for their science.

3. I expect the association strategy to change significantly in future data releases. In particular, we intend to move to a probabilistic matcher for cases where sources are close to two objects, so that the associated object is chosen by e.g. flux instead of just separation.

---

<div class="post-metadata">

**Author:** ![deppep](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/deppep/32/3217_2.png) [@deppep](https://www.rubin.community/u/deppep)\
**Post date:** [November 11, 2025, 9:03pm UTC](https://www.rubin.community/t/how-are-diaobjects-created/11257/3 "2025-11-11T21:03:35Z")

</div>

As always, thank you for your clear and precise answers, Ian! Till next time… 🙂

---

<div class="post-metadata">

**Author:** ![deppep](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/deppep/32/3217_2.png) [@deppep](https://www.rubin.community/u/deppep)\
**Post date:** [January 26, 2026, 4:29pm UTC](https://www.rubin.community/t/how-are-diaobjects-created/11257/4 "2026-01-26T16:29:43Z")

</div>

Dear Ian,

I’m looking further into this. I am curious about how the [tolerance](https://github.com/lsst/pipe_tasks/blob/957465b338503d1418be8873e6f0df6e99e6ee41/python/lsst/pipe/tasks/simpleAssociation.py#L134) parameter was set for the search with DP1 data, which to my understanding should determine the radius of the cone search for matches. Where can I find this value? Was it set to the [default 1 arcsec value](https://github.com/lsst/pipe_tasks/blob/957465b338503d1418be8873e6f0df6e99e6ee41/python/lsst/pipe/tasks/simpleAssociation.py#L45)?

Thank you,  
Peppe

---

<div class="post-metadata">

**Author:** ![isullivan](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/isullivan/32/1866_2.png) [@isullivan](https://www.rubin.community/u/isullivan)\
**Post date:** [January 26, 2026, 6:11pm UTC](https://www.rubin.community/t/how-are-diaobjects-created/11257/5 "2026-01-26T18:11:02Z")

</div>

For DP1 the tolerance was left at the default value of 1 arcsecond. The final config is always saved in the butler, so you can check the values by logging in to the DP1 RSP and querying the butler:

```auto
butler = dafButler.Butler("DP1")

association_config = butler.get("associateDiaSource_config", collections="LSSTComCam/DP1")
print(association_config)
{'saveLogOutput': True, 'associator': {'tolerance': 1.0, 'nside': 262144}, 'solarSystemAssociator': {'maxDistArcSeconds': 1.0, 'maxPixelMargin': 100}, 'doAddDiaObjectCoords': True, 'doWriteEmptyTables': False, 'doSolarSystemAssociation': True, 'doUseSchema': False, 'schemaDir': '${SDM_SCHEMAS_DIR}/yml', 'schemaFile': 'lsstcam.yaml', 'idGenerator': {'release_id': 4, 'n_releases': 64, 'packer': {'bands': None, 'n_bands': 0, 'n_tracts': None, 'n_patches': None}}, 'connections': {'diaSourceTables': 'dia_source_detector', 'ssObjectTableRefs': 'preloaded_DRP_SsObjects', 'skyMap': 'skyMap', 'finalVisitSummaryRefs': 'visit_summary', 'assocDiaSourceTable': 'dia_source_patch', 'associatedSsSources': 'ss_source_associated', 'unassociatedSsObjects': 'ss_object_unassociated', 'diaObjectTable': 'dia_object_pre_calc', 'coaddName': 'deep', 'warpTypeSuffix': '', 'fakesType': ''}}

```
