Internal API
This page is for developers working on Hebog. These modules are not a supported public interface and change without notice. The architecture overview explains how the layers fit together, and How Hebog finds sources explains the science.
The sections follow the order in which hebog.find_sources runs the stages.
Each stage module applies pure kernels from hebog.algorithms and
hebog.science with tiles, halos and executor batches, and
hebog.stages.composition runs the stages in order; its first section
documents it. hebog.science holds the
reviewed profile and configuration, the composition records and the
catalogue-row kernels; it imports no stage.
The stage sequence
hebog.stages.composition
The stage sequence find_sources runs, and the runner of each stage.
Each runner plans its stage's tile grid, opens the generation the stage
publishes and runs the stage through the caller's executor.
run_stages estimates the background and RMS and then calls
run_stages_from_background, which runs every later stage in order on
a published background and RMS; a caller that already holds one starts
there instead of estimating it again. The sequence returns the generations
and the records the terminal catalogues are built from, and builds no
catalogue: hebog.public_science does.
ADMITTED_TILE_CORE_PIXELS = 2048
module-attribute
Smallest tile core the scalability contract admits, in pixels.
BackgroundEstimate
dataclass
One image's published background and RMS and what they record.
usable_noise is whether any pixel has a usable local noise estimate,
and bright_regions how far the estimate refined around bright
candidates.
Source code in src/hebog/stages/composition.py
144 145 146 147 148 149 150 151 152 153 154 155 | |
PublishedStageRecords
dataclass
The records the stages published, from which the catalogues are built.
They are the inputs of the terminal composition,
hebog.public_science.build_configured_continuum_products, under the
same names, except that accepted_island_count is its
component_count.
Source code in src/hebog/stages/composition.py
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | |
PublishedStages
dataclass
What the stages after the background and RMS published.
The generations are named for the planes a later caller reads from
them: publication_source holds the support labels and the retained
mask, component_source the component labels, fit_source the
persistent measurement support, hierarchy_source the retained
scale support, and the two source generations the source labels and
the support each source owns.
Source code in src/hebog/stages/composition.py
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | |
StageSequenceResult
dataclass
The background and RMS generation and what the later stages published.
published is None when no pixel has a usable local noise
estimate: the sequence then stops after the background and RMS, and
rms_scientific_status is unavailable.
Source code in src/hebog/stages/composition.py
158 159 160 161 162 163 164 165 166 167 168 169 170 | |
detect_multiscale_products(source, background_rms_source, executor, work_directory, *, image_shape_yx, beam, review, generation_id, tile_core_pixels=ADMITTED_TILE_CORE_PIXELS)
Run the tiled detection pass and read its published planes.
The composition owns no plane at all: the pass publishes what a later pass reads by window, and reduces each scale feature's peak while its response is still on the task that evaluated it. Only the reconciled island records come back.
tile_core_pixels is the non-overlapping output core each task owns.
It defaults to the smallest core the scalability contract admits, and is
widened when the widest filter halo would exceed a quarter of it. Tile
geometry changes which task computes a value, never the value. One tile
per batch is already a coarse task at that core, so batching adds nothing
here.
Source code in src/hebog/stages/composition.py
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 | |
estimate_background_rms(source, metadata, config, executor, work_directory, *, beam, review, generation_id)
Run the exact candidate-owned bounded background/RMS stage.
The stage publishes the background and the RMS as tiled planes, and the generation is what comes back: every later pass reads it by window. The one fact the composition needs about the estimate is whether any pixel can use it, which is reduced while streaming rather than kept as a mask. The diagnostics also record how far it refined around bright candidates.
Source code in src/hebog/stages/composition.py
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | |
estimate_has_usable_noise(source, background_rms_source, metadata)
Return whether any pixel has a usable local noise estimate.
This is the one decision the estimate makes about itself, and the only thing the composition needs from it: a pixel is usable where the image is valid and the estimate is positive. The stage has already required, on the core that computed it, that the estimate is finite wherever the image is valid, or, when no coarse window held enough samples for a background, nowhere, so validity is the image's own and needs no second opinion. The answer is reduced one canonical tile row at a time, so neither the estimate nor a mask over it is ever held whole.
Raises:
| Type | Description |
|---|---|
ValueError
|
If the published rows do not cover the image. |
Source code in src/hebog/stages/composition.py
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 | |
publish_component_fits(source, background_rms_source, detection_source, component_source, executor, work_directory, *, image_shape_yx, beam, wcs_header_text, restoring_beam, config, review, component_count, generation_id, tile_core_pixels=ADMITTED_TILE_CORE_PIXELS)
Fit every measurement parent in its own context window.
Owners whose fit contexts touch need a joint model, so the contexts are reconciled first, a parent no joint fit can hold is split into its islands, and each fit parent is then measured inside the window holding it. The cores combine the persistent measurement support the parents contributed, and the connected features of that support are then grouped one window at a time.
Each parent also describes the direct components it owns, so the records
the association decision reads come from the residual the fits already
hold rather than from a second pass of per-component reads.
component_count is the topology's, and the records must describe
every one of those components.
Source code in src/hebog/stages/composition.py
898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 | |
publish_component_topology(support_source, detection_source, executor, work_directory, *, image_shape_yx, config, generation_id, tile_core_pixels=ADMITTED_TILE_CORE_PIXELS)
Deblend every parent in its own window and read the components.
Deblending needs a parent's complete support and nothing beyond it, so the object pass decides one parent per task and the cores write the component labels they own.
Source code in src/hebog/stages/composition.py
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 | |
publish_detection_islands(source, background_rms_source, publication_source, component_source, executor, *, image_shape_yx, beam, tile_core_pixels=ADMITTED_TILE_CORE_PIXELS)
Measure one catalogue row per island of the published retained mask.
The cores label their own mask and observe which owners its islands hold, the fragments reconcile into islands named by canonical first pixel, and one task per batch of islands measures their rows. Nothing is published: the island labels exist only inside these rounds.
Source code in src/hebog/stages/composition.py
713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 | |
publish_hierarchy_overlaps(detection_source, component_source, executor, work_directory, *, image_shape_yx, records, scale_detections, generation_id, tile_core_pixels=ADMITTED_TILE_CORE_PIXELS)
Reduce every pixel fact the source hierarchy decision needs.
The cores observe which components, features and retained support components meet, one task per feature derives its reviewed B3 influence, and one task per candidate pair decides whether two envelopes overlap. The decision that consumes the result holds no plane, and the component records reach both it and this pass already built.
Source code in src/hebog/stages/composition.py
843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 | |
publish_segment_rows(source, background_rms_source, detection_source, label_source, centroid_source, executor, work_directory, *, image_shape_yx, beam, wcs_header_text, restoring_beam, label_product_name, centroid_product_name, aperture_tie_policy, with_position_diagnostics, generation_id, sink_name, tile_core_pixels=ADMITTED_TILE_CORE_PIXELS)
Measure one catalogue row per segment, each in its own window.
The cores write the expanded apertures under the reviewed radius, they observe the bounds each segment and aperture occupies, and one task per batch of segments measures their rows, their local noise and their moment shapes. The aperture plane stays in the published generation: the rows carry what the catalogue needs from it, so the driver never holds it.
Source code in src/hebog/stages/composition.py
618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 | |
publish_source_planes(component_source, detection_source, scale_support_source, measurement_support_source, executor, work_directory, *, image_shape_yx, association, generation_id, tile_core_pixels=ADMITTED_TILE_CORE_PIXELS)
Publish the source labels and the persistent support they own.
The owners a source holds are a record map, so the cores write the labels from the shard that reaches them; the support a source owns spans tiles, so it is reconciled before each connected component divides its unseeded pixels between the sources that seed it.
Source code in src/hebog/stages/composition.py
767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 | |
publish_support_labels(detection_source, support_source, executor, work_directory, *, image_shape_yx, beam, detection_islands, config, review, generation_id, tile_core_pixels=ADMITTED_TILE_CORE_PIXELS)
Decide owner connectivity and publish the support pass's labels.
Two of the decisions here are scoped to an owner rather than to a tile, so they are taken once per owner from the window holding it and applied by the core that owns each pixel. The caller's island admission is applied in the same write, and the count of islands it accepted is the only thing that comes back: every plane stays in the generation, where the mask product and the object rounds read it by window.
Source code in src/hebog/stages/composition.py
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 | |
reduce_support_topology(detection_source, executor, work_directory, *, image_shape_yx, scale_orders, generation_id, tile_core_pixels=ADMITTED_TILE_CORE_PIXELS)
Reconcile adjacent-scale persistence and return its plane's store.
Persistence is not bounded by a halo: it is a record graph over the whole image. It is reconciled from compact per-core summaries and published as owned cores, and the generation is returned so the support rounds read it by window.
Source code in src/hebog/stages/composition.py
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 | |
restoring_beam_from_header(header)
Return the restoring beam a header states, in degrees.
A header without BPA states a beam at position angle zero.
Source code in src/hebog/stages/composition.py
173 174 175 176 177 178 179 180 181 182 | |
run_stages(source, metadata, executor, work_directory, *, config, wcs_header_text, restoring_beam, beam, review, generation_id)
Estimate the background and RMS, then run every later stage in order.
beam is the restoring beam in local pixel axes and review the
installed profile under the caller's thresholds. wcs_header_text is
the header text each task rebuilds the celestial WCS from, and
restoring_beam the beam that header states. Every stage writes its
planes to a generation below work_directory named by
generation_id, and later stages read them by window.
Source code in src/hebog/stages/composition.py
1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 | |
run_stages_from_background(source, background_rms_source, executor, work_directory, *, image_shape_yx, config, wcs_header_text, restoring_beam, beam, review, generation_id, multiscale_tile_core_pixels=ADMITTED_TILE_CORE_PIXELS, support_tile_core_pixels=ADMITTED_TILE_CORE_PIXELS)
Run every stage after the background and RMS, in order.
background_rms_source is a published background and RMS generation,
which every stage reads by window rather than estimating again.
multiscale_tile_core_pixels is the multiscale pass's core and
support_tile_core_pixels the core of every pass from the support
reduction on; both default to the smallest
core the scalability contract admits, as find_sources runs them, and
no core changes a product.
Source code in src/hebog/stages/composition.py
1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 | |
Configuration and the reviewed profile
hebog.config
Immutable scientific and execution configuration.
AdaptiveRmsConfig
dataclass
Fine-grid and deterministic blend policy around bright candidates.
Source code in src/hebog/config.py
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | |
__post_init__()
Require finite positive radii and a contained transition zone.
Source code in src/hebog/config.py
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | |
BackgroundRmsConfig
dataclass
Complete coarse, adaptive, interpolation, and memory policy.
Source code in src/hebog/config.py
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | |
__post_init__()
Validate automatic constant-map fallback and its memory bound.
Source code in src/hebog/config.py
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | |
CompactDeblendConfig
dataclass
Scientific cuts plus preferred and hard compact-work bounds.
Source code in src/hebog/config.py
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 | |
__post_init__()
Require explicit finite science cuts and bounded region costs.
Source code in src/hebog/config.py
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 | |
CompactGaussianFitConfig
dataclass
Explicit bounded nonlinear policy for one compact Gaussian fit.
Source code in src/hebog/config.py
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 | |
__post_init__()
Validate scientific parameter bounds and finite work limits.
Source code in src/hebog/config.py
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 | |
CompactMomentConfig
dataclass
Numerical availability policy for compact moment ellipses.
Source code in src/hebog/config.py
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 | |
__post_init__()
Require enough pixels for 2-D shape and a strict tolerance.
Source code in src/hebog/config.py
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 | |
DetectionStageConfig
dataclass
Scientific policies required by the compact-detection stage.
Source code in src/hebog/config.py
251 252 253 254 255 256 | |
ResidualMultiscaleDetectionConfig
dataclass
Promoted residual-B3 segmentation thresholds and topology rules.
Source code in src/hebog/config.py
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 | |
__post_init__()
Reject thresholds or topology outside the promoted policy.
Source code in src/hebog/config.py
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 | |
RmsGridConfig
dataclass
Window geometry and bounded-batch policy for one RMS grid.
Source code in src/hebog/config.py
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | |
__post_init__()
Require meaningful windows and an explicit positive batch bound.
Source code in src/hebog/config.py
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | |
RmsWindowStatisticsConfig
dataclass
Robust-statistics policy for one batch of bounded RMS windows.
Source code in src/hebog/config.py
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | |
__post_init__()
Require a finite clipping threshold and usable sample counts.
Source code in src/hebog/config.py
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | |
SourceFinderConfig
dataclass
Pipeline-neutral scientific thresholds for one image analysis.
Thresholds are explicit because a value appropriate for one survey,
image product, or pipeline stage is not a universal scientific default.
Island-size cuts are likewise explicit pixel counts; a compatibility
adapter may derive them from reviewed beam metadata before constructing
this scheduler-independent configuration.
background is estimated, Hebog's spatial background, or
zero, which subtracts nothing while the RMS is still estimated, as
PyBDSF's mean_map="zero" does; which one a workflow uses is that
workflow's adapter's choice, as are its filtering options. The residual
multiscale segmentation policy has its own explicit configuration because
its area and support rules use beam rather than pixel units.
continuum is the general source-association profile; compact is an
explicit component-level profile that is incomplete for extended emission.
A threshold or pixel count may be any real number or integer, a NumPy
scalar included, and is held as the Python float or int it
equals, so equal configurations serialize and hash alike.
SourceFinderConfig(5, 3, 7) SourceFinderConfig(detection_threshold_sigma=5.0, island_threshold_sigma=3.0, minimum_island_pixels=7, maximum_island_pixels=None, profile='continuum', background='estimated')
Source code in src/hebog/config.py
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | |
__post_init__()
Validate thresholds and pixel cuts, and hold plain values.
Source code in src/hebog/config.py
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | |
hebog.science.configuration
Current scientific configuration for installed source finding.
source_finder_configs()
Return the current source-finder scientific configuration.
Source code in src/hebog/science/configuration.py
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | |
hebog.science.profile
Minimal installed profile for the reviewed continuum science.
ContinuumCorrectionProfile
dataclass
Reviewed continuum correction settings used at runtime.
Source code in src/hebog/science/profile.py
23 24 25 26 27 | |
ContinuumDetectionProfile
dataclass
Threshold, scale, and valid-support settings used at runtime.
Source code in src/hebog/science/profile.py
13 14 15 16 17 18 19 20 | |
ContinuumScienceProfile
dataclass
Small phase-neutral projection of the historical review record.
Source code in src/hebog/science/profile.py
30 31 32 33 34 35 | |
configured_science_profile(profile, config)
Apply caller thresholds without mutating the installed profile.
Source code in src/hebog/science/profile.py
89 90 91 92 93 94 95 96 97 98 99 100 101 | |
load_continuum_science_profile(payload)
Project the reviewed JSON record onto fields used by source finding.
Source code in src/hebog/science/profile.py
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | |
Partition planning
hebog.algorithms.partitioning
Deterministic image partition planning.
plan_image_partitions(*, image_shape_yx, tile_core_shape_yx, halo_yx, partition_origin_yx=(0, 0))
Plan canonical row-major cores and clipped stage read halos.
Source code in src/hebog/algorithms/partitioning.py
8 9 10 11 12 13 14 15 16 17 18 19 20 21 | |
Background and RMS
hebog.algorithms.background
Robust serial background and RMS statistics for bounded window batches.
BackgroundRmsTile
dataclass
One bounded interpolated background and RMS output core.
Source code in src/hebog/algorithms/background.py
130 131 132 133 134 135 136 137 138 | |
PreparedRmsGrid
dataclass
Coarse samples filled once and ready for repeated interpolation.
Source code in src/hebog/algorithms/background.py
114 115 116 117 118 119 120 121 122 123 124 125 126 127 | |
fallback_cell_count
property
Return the number of unavailable cells filled from neighbours.
RmsGridBatchStatistics
dataclass
Small coarse statistics returned by one bounded window batch.
Source code in src/hebog/algorithms/background.py
92 93 94 95 96 97 98 | |
RmsGridGeometry
dataclass
Globally anchored coarse-grid geometry with edge-aligned windows.
Source code in src/hebog/algorithms/background.py
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | |
cell_count
property
Return the number of independently estimated window cells.
shape_yx
property
Return the coarse-grid shape in NumPy axis order.
RmsGridStatistics
dataclass
Canonical coarse background and RMS summaries for one image.
Source code in src/hebog/algorithms/background.py
101 102 103 104 105 106 107 108 109 110 111 | |
RmsWindowBatch
dataclass
One rectangular block of coarse cells sharing a bounded image read.
Source code in src/hebog/algorithms/background.py
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | |
cell_count
property
Return the number of windows evaluated in this batch.
shape_yx
property
Return the rectangular coarse-cell block shape.
RmsWindowBatchGroup
dataclass
Neighbouring window batches estimated from one read of their union.
Source code in src/hebog/algorithms/background.py
248 249 250 251 252 253 | |
RmsWindowStatistics
dataclass
Background and RMS estimates for a batch of independent windows.
Source code in src/hebog/algorithms/background.py
33 34 35 36 37 38 39 40 41 | |
assemble_rms_grid_statistics(grid, batch_results)
Assemble complete coarse summaries independently of completion order.
Source code in src/hebog/algorithms/background.py
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 | |
blend_adaptive_background_rms(coarse, adaptive, positions_yx, *, influence_radius_pixels, transition_width_pixels)
Blend cached fine estimates smoothly around bright candidates.
The background is blended both ways. The fine RMS only raises the coarse one: near a bright source it measures the raised noise of its artefacts, which a coarse window dilutes, and where it reads lower the coarse RMS stands. PyBDSF's adaptive small box likewise applies near a bright source only out to where it stops reading well above its large one. So a quieter region's noise, measured by a fine window that missed the protected sources there, never lowers the noise beside it.
Source code in src/hebog/algorithms/background.py
1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 | |
clean_cell_coverage(available, reach_yx)
Return the fraction of grid cells with a clean cell within reach.
A cell is covered when a clean cell lies within reach_yx cells of it
along each axis, itself included; the grid's edge clips the reach. An
empty grid covers nothing.
Source code in src/hebog/algorithms/background.py
718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 | |
estimate_rms_grid_batch(values, valid_pixels, grid, batch, config, *, protected_pixels=None)
Estimate a rectangular window block without loops over grid cells.
A fine-grid window that intersects protected_pixels is deliberately
unavailable as a whole. This prevents connected bright-source support
from contributing to either the background or RMS statistic while
retaining the established deterministic interpolation fallback.
Source code in src/hebog/algorithms/background.py
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 | |
estimate_rms_window_statistics(windows, valid_pixels, config)
Estimate robust background and RMS for a batch of 2-D windows.
Non-finite or explicitly invalid pixels do not contribute. A window with
too few retained samples, or whose clipped spread is no greater than its
noise floor, has NaN estimates and available=False so a later
interpolation stage can apply its documented fallback policy. An
available window therefore has a positive RMS.
The noise floor is the window's largest absolute valid value, taken before clipping, times single precision's machine epsilon (2**-23, about 1.2e-7): single precision's resolution at that value. Radio images are commonly made and stored in single precision, so a spread finer than that resolution beside the window's brightest pixel is below what such an image can be relied on to hold, and is not taken for noise. Samples of one value, whose spread is exactly zero, are the limit case; another is a window holding a noise-free source, whose tails' clipped spread lies near 1e-12 of its peak. A window of a noise-free source's far tails alone has a spread close to its own values, which no floor relative to them can tell from noise. Real noise falls under the floor only within a window whose brightest pixel is more than eight million times the noise, and that window then takes the fallback, as a window over a protected source does. The floor scales with the values, so the units and absolute level of an image do not change which windows it rejects.
The kernel runs on executor threads, so it emits no warning and never
touches the process's warning filters: an invalid or empty window is
ordinary input, reported through available.
Source code in src/hebog/algorithms/background.py
1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 | |
group_rms_window_batches(batches, *, read_side_pixels)
Group batches whose reads start in the same square of the image.
The squares are read_side_pixels wide from the image origin. A
group's read is the union of its batches' reads, which tile a
rectangle of the grid, so it is at most one batch read wider than the
square along each axis. Groups follow the raster order of their
squares, and batches keep their order within a group. The cells a
batch estimates come from its own windows only, so grouping changes
the reads and the tasks, never a statistic.
Source code in src/hebog/algorithms/background.py
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 | |
interpolate_prepared_rms_grid(grid, bounds, valid_pixels, *, extrapolate_rms=True)
Interpolate cached samples, optionally extending RMS edge values.
Fine noise cells have stochastic slopes, not a measured noise gradient beyond their centres. Constant edge extension preserves positive convex weights there. Background edge slopes span the extrapolation distance, not a possibly tiny gap between the final two window centres. Extended RMS follows the same secants but never falls below the edge cell: a noise level falling towards the image edge is held there, one rising is extended. At a corner the second axis' secant runs through samples the first has already extended, so a corner value can be lower than before the bound, but not below the corner cell.
Source code in src/hebog/algorithms/background.py
1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 | |
plan_rms_grid(*, image_shape_yx, window_shape_yx, step_yx)
Plan deterministic global RMS windows independent of tile geometry.
Source code in src/hebog/algorithms/background.py
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | |
plan_rms_window_batches(grid, *, maximum_cells)
Group coarse cells into bounded rectangular image-read batches.
Source code in src/hebog/algorithms/background.py
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | |
prepare_crowded_local_noise_rms_grid(statistics, coarse, *, maximum_noise_ratio, clean_cell_reach_yx)
Hold a crowded field's coarse RMS to its clean windows' noise.
In a field too crowded for its clean fine windows to reach most of its
cells, filling every cell from a few distant windows would copy their
noise across the field. A cell with a clean window within
clean_cell_reach_yx cells takes its nearest clean window's RMS, as
local noise does; beyond that reach the unprotected coarse RMS stands, as
PyBDSF's does, wherever it reads at most maximum_noise_ratio times
the nearest clean window's RMS. Above that, a coarse window holds
emission rather than noise, as over a source wider than one, and the
clean window's noise stands there, as local noise fills a source wider
than its reach. The background is filled from the clean windows, as any
filled grid's; a grid without a clean window stays unavailable.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
statistics
|
RmsGridStatistics
|
The local-noise grid's assembled window statistics. |
required |
coarse
|
PreparedRmsGrid
|
The prepared unprotected coarse grid of the same image. |
required |
maximum_noise_ratio
|
float
|
How many times the nearest clean window's RMS the coarse RMS may read and still stand. |
required |
clean_cell_reach_yx
|
tuple[int, int]
|
How many cells along each axis, either side of a cell, a clean window may lie and set its RMS. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the ratio is not finite or below 1, or the local noise grid is available and the coarse grid is not. |
Source code in src/hebog/algorithms/background.py
649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 | |
prepare_local_noise_rms_grid(statistics, coarse, *, minimum_coarse_fraction, clean_cell_reach_yx)
Fill a local-noise grid without letting a fill fall far below its noise.
Cells are filled from their nearest available cell, as
:func:prepare_rms_grid_for_interpolation fills any grid, except that a
filled cell with an available cell within clean_cell_reach_yx cells
of it never falls below minimum_coarse_fraction times a reference:
the coarse RMS at its centre, or the largest available cell in that
reach if that is smaller. Local noise blanks every window that touches
guarded source support, and beside a sharp step in the noise the nearest
clean window can lie on the quieter side, where its estimate would lower
the noise beside the step. A coarse window over extended emission
includes emission the clipping keeps, so where no clean window nearby
reads as high as the coarse RMS, the excess is not noise and the clean
windows set the reference; and a cell with no clean window in reach,
as inside a source wider than twice the reach, keeps its nearest fill,
because the coarse RMS alone is not a reference there. A cell that a
clean window measured keeps its own estimate, however low, since that
is what local noise measures. The background is filled as before, and
an unavailable grid stays unavailable.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
statistics
|
RmsGridStatistics
|
The local-noise grid's assembled window statistics. |
required |
coarse
|
PreparedRmsGrid
|
The prepared coarse grid of the same image, available. |
required |
minimum_coarse_fraction
|
float
|
The fraction of the reference below which a filled cell's RMS never falls, from 0, no floor, to 1. |
required |
clean_cell_reach_yx
|
tuple[int, int]
|
How many cells along each axis, either side of a filled cell, a clean cell may lie and still floor it and cap its reference. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the fraction is not finite or lies outside 0 to 1, a reach is not a non-negative integer, or the local-noise grid is available and the coarse grid is not. |
Source code in src/hebog/algorithms/background.py
742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 | |
prepare_refinement_rms_grid(statistics, coarse, *, fill_reach_pixels)
Fill a refinement grid without carrying its RMS beyond a reach.
Cells are filled from their nearest available cell, as
:func:prepare_rms_grid_for_interpolation fills any grid, except that a
cell whose nearest available cell's centre lies more than
fill_reach_pixels from its own has no fine RMS: it takes the coarse
RMS at its centre, so the coarse estimate stands there. A refinement grid
over a crowded field keeps few windows clear of protected sources, and
without the reach one of them would set the noise hundreds of pixels
from where it was measured, across any step in the noise between. The
background is filled as before, and an unavailable grid stays
unavailable.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
statistics
|
RmsGridStatistics
|
The refinement grid's assembled window statistics. |
required |
coarse
|
PreparedRmsGrid
|
The prepared coarse grid of the same image, available. |
required |
fill_reach_pixels
|
float
|
The farthest distance, in pixels between window centres, over which a clean window's RMS fills another cell; a cell exactly at it is filled. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the reach is negative or not finite, or the refinement grid is available and the coarse grid is not. |
Source code in src/hebog/algorithms/background.py
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 | |
prepare_rms_grid_for_interpolation(statistics)
Fill sparse cells once without recomputing window statistics.
Source code in src/hebog/algorithms/background.py
550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 | |
subset_prepared_rms_grid(grid, bounds)
Copy the bounded coarse summary needed to interpolate one tile.
Source code in src/hebog/algorithms/background.py
962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 | |
subset_rms_grid_geometry(grid, bounds)
Return only globally anchored cells bracketing one bounded region.
Source code in src/hebog/algorithms/background.py
932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 | |
hebog.stages.background
Bounded source and executor orchestration for background estimation.
AdaptiveRmsRegion
dataclass
One merged bright-candidate region and its local fine-grid cache.
Source code in src/hebog/stages/background.py
124 125 126 127 128 129 130 131 | |
AdaptiveRmsTileSummary
dataclass
One tile-local adaptive interpolant and its candidate positions.
Source code in src/hebog/stages/background.py
171 172 173 174 175 176 | |
BackgroundRmsGrids
dataclass
Prepared coarse and optional sparse adaptive interpolation caches.
largest_bright_region_read_pixels is the most pixels one task read
to estimate the fine grids around bright candidates, zero if none did.
Source code in src/hebog/stages/background.py
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | |
adaptive_estimated_cell_count
property
Return the total fine cells retained across local regions.
adaptive_protected_pixel_count
property
Return bounded source-support pixels seen across fine regions.
adaptive_protected_window_count
property
Return fine windows rejected for intersecting source support.
BackgroundRmsTileRequest
dataclass
Bounded interpolation summaries and blend metadata for one tile.
Source code in src/hebog/stages/background.py
179 180 181 182 183 184 185 186 187 188 189 | |
MultiscaleSourceProtection
dataclass
Caller-supplied beam and detection policy for fine-grid protection.
Source code in src/hebog/stages/background.py
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 | |
__post_init__()
Validate filter admission before any image or candidate exists.
Source code in src/hebog/stages/background.py
251 252 253 254 255 256 257 258 | |
estimate_background_rms_grids(source, image_shape_yx, config, executor, *, bright_candidate_positions_yx, source_protection_island_threshold_sigma=None, multiscale_protection=None)
Estimate cached global coarse and sparse adaptive RMS summaries.
Source code in src/hebog/stages/background.py
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 | |
estimate_background_rms_tile(source, request)
Read validity and interpolate one deterministic owned output core.
Source code in src/hebog/stages/background.py
1701 1702 1703 1704 1705 1706 1707 1708 | |
estimate_rms_grid(source, grid, config, executor)
Estimate one complete coarse grid through bounded executor batches.
One task estimates the batches whose reads start in one square of
_SOURCE_READ_SIDE_PIXELS, from one read.
Source code in src/hebog/stages/background.py
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 | |
interpolate_background_rms_tile(image_window, request)
Interpolate one owned core using an already-read source window.
Source code in src/hebog/stages/background.py
1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 | |
prepare_background_rms_tile_request(partition, grids, config)
Build one local interpolation request without global grid payloads.
Source code in src/hebog/stages/background.py
1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 | |
refine_background_rms_grids(source, coarse_grids, config, executor, *, bright_candidate_positions_yx, source_protection_island_threshold_sigma=None, multiscale_protection=None, protect_coarse_source_support=False, refine_local_noise=False)
Estimate sparse adaptive cells while reusing a prepared coarse grid.
Source code in src/hebog/stages/background.py
1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 | |
Detection and island topology
hebog.algorithms.detection
Pure bounded normalization and two-threshold detection kernels.
DetectionThresholdMasks
dataclass
Immutable island-membership and strict detection-seed masks.
Source code in src/hebog/algorithms/detection.py
15 16 17 18 19 20 21 22 | |
detect_high_significance_candidates(image, valid_pixels, background, rms, *, threshold_sigma)
Apply one strict threshold for adaptive-RMS candidate topology.
Source code in src/hebog/algorithms/detection.py
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | |
detect_threshold_masks(image, valid_pixels, background, rms, config)
Threshold one bounded image tile without persisting an SNR plane.
Island membership includes pixels exactly at the island threshold. Detection seeds require a value strictly above the detection threshold. This explicit asymmetry reproduces the reviewed initial compact-detection contract without introducing workflow defaults into the kernel.
Source code in src/hebog/algorithms/detection.py
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | |
normalize_residual(image, valid_pixels, background, rms)
Return immutable normalized residuals and scientific validity.
Source code in src/hebog/algorithms/detection.py
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | |
hebog.algorithms.labelling
Eight-connected local island labelling over deterministic tile cores.
LocalIslandSummary
dataclass
Small mergeable facts for one tile-local connected component.
Source code in src/hebog/algorithms/labelling.py
24 25 26 27 28 29 30 31 32 33 34 35 36 | |
LocalIslandTile
dataclass
One locally labelled core plus mergeable summaries and boundaries.
Source code in src/hebog/algorithms/labelling.py
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | |
compact_summary()
Drop the image-sized label core before scheduler reconciliation.
Source code in src/hebog/algorithms/labelling.py
67 68 69 70 71 72 73 | |
LocalIslandTileSummary
dataclass
Compact tile topology safe to return through an executor.
Source code in src/hebog/algorithms/labelling.py
49 50 51 52 53 54 55 | |
TileBoundaryLabels
dataclass
Local labels on four owned core boundaries for reconciliation.
Source code in src/hebog/algorithms/labelling.py
39 40 41 42 43 44 45 46 | |
label_detection_tile(masks, partition, *, image_shape_yx, response_jy_per_beam=None)
Label one owned core and reduce component properties without copies.
response_jy_per_beam is the optional filtered response the island was
detected on. When it is given, each summary also carries that plane's
per-island maximum, so a caller that needs the peak response of a feature
does not have to store the response plane for a later pass.
Source code in src/hebog/algorithms/labelling.py
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 | |
relabelled(labels, value_by_label, *, otherwise=None)
Return the value each pixel's label maps to, in one pass over them.
A pixel whose label maps to nothing keeps its value in otherwise, or
0 when none is given. Comparing the plane with each label in turn costs a
full pass per label, and a core holds thousands; this looks every pixel
up once, a block of rows at a time, so the lookup adds memory for one
block rather than for the plane.
Examples:
>>> relabelled(
... np.array([[0, 3], [5, 3]], dtype=np.int32), {3: 7, 5: 9}
... ).tolist()
[[0, 7], [9, 7]]
Source code in src/hebog/algorithms/labelling.py
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 | |
hebog.algorithms.reconciliation
Deterministic reconciliation of tile-local connected island labels.
DetectedIsland
dataclass
Canonical detection-stage topology before scientific measurement.
Source code in src/hebog/algorithms/reconciliation.py
23 24 25 26 27 28 29 30 31 32 33 34 35 | |
ReconciledIslands
dataclass
Stable accepted islands and per-tile mappings for mask publication.
Source code in src/hebog/algorithms/reconciliation.py
47 48 49 50 51 52 53 54 55 56 57 58 59 60 | |
mapping_for_tile(tile_id)
Return the exact mapping for one canonical tile.
Source code in src/hebog/algorithms/reconciliation.py
55 56 57 58 59 60 | |
TileLabelMapping
dataclass
Small mapping from one tile's local labels to accepted global labels.
Source code in src/hebog/algorithms/reconciliation.py
38 39 40 41 42 43 44 | |
apply_reconciled_labels(tile, reconciliation)
Map one local label core to immutable stable global labels.
Source code in src/hebog/algorithms/reconciliation.py
497 498 499 500 501 502 503 504 505 | |
apply_tile_label_mapping(tile, mapping)
Map one local core using only its small executor-safe mapping.
Source code in src/hebog/algorithms/reconciliation.py
508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 | |
reconcile_candidate_tiles(manifest, tiles)
Merge strict high-significance candidates without a size cut.
Source code in src/hebog/algorithms/reconciliation.py
484 485 486 487 488 489 490 491 492 493 494 | |
reconcile_island_tiles(manifest, tiles, config)
Merge source-detection fragments under the configured size policy.
Source code in src/hebog/algorithms/reconciliation.py
470 471 472 473 474 475 476 477 478 479 480 481 | |
hebog.stages.detection
Bounded compact-detection execution and Zarr product publication.
DetectionStageResult
dataclass
Published compact topology and bounded execution evidence.
Source code in src/hebog/stages/detection.py
96 97 98 99 100 101 102 103 104 105 106 | |
discover_adaptive_candidates(source, manifest, coarse_grids, config, executor)
Find deterministic global peaks for strict adaptive-RMS candidates.
Source code in src/hebog/stages/detection.py
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | |
run_detection_from_coarse_grids(source, manifest, coarse_grids, *, config, executor, sink, multiscale_protection=None, protect_coarse_source_support=False, refine_local_noise=False)
Run Phase 3 from one immutable Phase 2 coarse-grid result.
This boundary lets component benchmarks and future pipeline execution reuse an already-computed coarse background/RMS grid without changing the automatic adaptive-candidate or final product semantics.
Source code in src/hebog/stages/detection.py
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 | |
run_detection_stage(source, manifest, config, executor, sink, *, multiscale_protection=None, protect_coarse_source_support=False, refine_local_noise=False)
Run bounded compact detection and publish one complete generation.
The separate high-significance scan and final mask pass deliberately trade one extra bounded image read each for simple retry semantics and compact scheduler results. No normalized, label, background, RMS, or mask plane is gathered by the executor.
Source code in src/hebog/stages/detection.py
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 | |
Residual multiscale detection
hebog.algorithms.multiscale
Bounded one-tile serial kernels for Phase 5 multiscale science.
BeamShapePixels
dataclass
Elliptical restoring beam or noise correlation in pixel units.
Source code in src/hebog/algorithms/multiscale.py
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | |
__post_init__()
Require finite, positive, ordered beam axes.
Source code in src/hebog/algorithms/multiscale.py
44 45 46 47 48 49 50 51 52 53 54 55 56 | |
PreparedScaleInputs
dataclass
Validated physical residual and reused Phase 2 RMS products.
Source code in src/hebog/algorithms/multiscale.py
139 140 141 142 143 144 145 | |
ResidualAtrousPlan
dataclass
Bounded three-scale residual B3-spline à trous construction.
Source code in src/hebog/algorithms/multiscale.py
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | |
convolution_count_per_evaluation
property
Count sparse one-dimensional signal and support convolutions.
maximum_halo_pixels
property
Return the widest cumulative halo required by the transform.
scale_dilations_pixels
property
Return the frozen dyadic holes between B3 coefficients.
scale_halo_pixels
property
Return cumulative finite halos at each adjacent smoothing.
temporary_plane_count
property
Return the reviewed peak full-size scratch-plane count.
ResidualAtrousResult
dataclass
One-tile corrective transform with transient scale provenance.
Source code in src/hebog/algorithms/multiscale.py
196 197 198 199 200 201 202 203 204 205 206 207 | |
ResidualAtrousScale
dataclass
One cumulative B3-spline scale and calibrated coefficient noise.
Source code in src/hebog/algorithms/multiscale.py
148 149 150 151 152 153 154 155 156 157 | |
ResidualMultiscaleIslandDetection
dataclass
Seeded original-residual islands under the promoted scale policy.
Source code in src/hebog/algorithms/multiscale.py
219 220 221 222 223 224 225 226 227 228 | |
ScaleFilter
dataclass
One calibrated scale response built from shared smoothing kernels.
Source code in src/hebog/algorithms/multiscale.py
68 69 70 71 72 73 74 75 76 77 78 79 80 81 | |
ScaleFilterBank
dataclass
Canonical filter plans and bounded structural costs for one family.
Source code in src/hebog/algorithms/multiscale.py
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | |
convolution_count_per_evaluation
property
Return convolutions after shared wavelet smoothing reuse.
maximum_halo_pixels
property
Return the widest read-only halo required by any scale.
temporary_plane_count
property
Return the maximum simultaneous full-size temporary planes.
ScaleFilterBankResult
dataclass
Complete one-tile serial response with explicit bounded costs.
Source code in src/hebog/algorithms/multiscale.py
128 129 130 131 132 133 134 135 136 | |
ScaleFilterResponse
dataclass
One immutable physical response, local noise, and validity plane.
Source code in src/hebog/algorithms/multiscale.py
116 117 118 119 120 121 122 123 124 125 | |
ScaleSmoothingKernel
dataclass
One shared normalized Gaussian smoothing component.
Source code in src/hebog/algorithms/multiscale.py
59 60 61 62 63 64 65 | |
SignificantAtrousReconstruction
dataclass
Adjacent-scale positive signal and auditable scale detections.
Source code in src/hebog/algorithms/multiscale.py
210 211 212 213 214 215 216 | |
build_residual_atrous_plan(beam, *, noise_correlation=None)
Build the frozen three-scale separable B3-spline à trous plan.
Source code in src/hebog/algorithms/multiscale.py
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 | |
build_scale_filter_bank(beam, *, family, scales, truncation_sigma=4.0, noise_correlation=None)
Build calibrated matched or undecimated-wavelet filter plans.
Source code in src/hebog/algorithms/multiscale.py
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 | |
calibrated_scale_snrs(responses, *, minimum_support_fraction)
Return immutable calibrated SNR planes for aligned scale responses.
Source code in src/hebog/algorithms/multiscale.py
924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 | |
detect_residual_multiscale_islands(prepared_inputs, matched_filter, atrous_result, beam, config)
Seed and grow promoted islands on original residual pixels.
Source code in src/hebog/algorithms/multiscale.py
982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 | |
evaluate_residual_atrous(prepared_inputs, plan, *, minimum_support_fraction, accepted_compact_model=None, accepted_compact_mask=None)
Evaluate normalized adjacent B3 smoothings of a compact-clean residual.
Accepted compact emission may be subtracted through a model or excluded through a mask. The returned coefficients are detection provenance; final masks and measurements must continue to use the original residual pixels.
Source code in src/hebog/algorithms/multiscale.py
666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 | |
evaluate_scale_filter_bank(prepared_inputs, filter_bank, *, minimum_support_fraction)
Evaluate every configured scale from already prepared Phase 2 planes.
Source code in src/hebog/algorithms/multiscale.py
1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 | |
minimum_residual_island_pixels(beam, config)
Return the promoted one-beam residual-island area floor.
Source code in src/hebog/algorithms/multiscale.py
1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 | |
prepare_scale_filter_inputs(image, valid_pixels, background, rms)
Validate prepared Phase 2 products and form one physical residual.
Source code in src/hebog/algorithms/multiscale.py
594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 | |
reconstruct_denoised_atrous(result, *, significance_sigma)
Reconstruct brightness from coarse emission and signed coefficients.
This estimates image brightness, not a discovery significance or flux. Both coefficient signs are retained symmetrically. The coarse plane is essential: dropping it removes broad emission, while adding the complete detail sum to the original image sharpens noise instead of denoising it. Callers retain the original RMS and discovery thresholds for publication.
Source code in src/hebog/algorithms/multiscale.py
819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 | |
reconstruct_significant_atrous(result, *, detection_sigma, island_sigma, minimum_support_fraction)
Reconstruct positive coefficients persistent at adjacent scales.
Source code in src/hebog/algorithms/multiscale.py
855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 | |
residual_atrous_scale_halos_pixels()
Return cumulative radii for the frozen dyadic B3 sequence.
Source code in src/hebog/algorithms/multiscale.py
311 312 313 | |
scale_smoothing_halo_pixels(beam, *, width_beams, truncation_sigma)
Return one Gaussian filter radius without allocating its kernel.
Source code in src/hebog/algorithms/multiscale.py
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 | |
hebog.algorithms.multiscale_tiles
Reviewed stage halos and bounded multiscale tile evaluation.
MultiscaleDetectionTileEvidence
dataclass
Core-local fields that precede global topology reconciliation.
Source code in src/hebog/algorithms/multiscale_tiles.py
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | |
retained_array_bytes
property
Return exact owned ndarray payload retained for local topology.
MultiscaleFilterTileResult
dataclass
Core-only multiscale filter evidence from one bounded halo read.
Workspace evidence describes the complete read evaluation. Every array in the returned scientific records is an owned immutable core copy, so no result retains an image-sized or halo-sized input buffer.
Source code in src/hebog/algorithms/multiscale_tiles.py
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | |
retained_array_bytes
property
Return exact owned ndarray payload retained by this core result.
derive_multiscale_detection_tile_evidence(result, config)
Derive local masks and seeds before bounded global reconciliation.
No connected component is accepted here because support may cross any number of tile boundaries. Adjacent-scale membership and seed values are point-local; the stage reconciles their compact side/corner summaries.
Source code in src/hebog/algorithms/multiscale_tiles.py
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | |
evaluate_multiscale_filter_tile(prepared_read, *, partition, image_shape_yx, beam, minimum_support_fraction)
Evaluate the promoted filters on one read and return its owned core.
This is the bounded local-neighbourhood seam for multiscale detection. Connected support is deliberately not labelled here: callers reconcile core labels through the existing bounded edge and corner summaries.
Source code in src/hebog/algorithms/multiscale_tiles.py
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 | |
scale_filter_halo_pixels(beam)
Return the widest frozen multiscale filter halo without allocation.
Source code in src/hebog/algorithms/multiscale_tiles.py
157 158 159 160 161 162 | |
segment_association_halo_pixels(beam)
Return the frozen residual/reconstruction grouping radius.
Source code in src/hebog/algorithms/multiscale_tiles.py
165 166 167 | |
hebog.stages.multiscale
Bounded multiscale execution and atomic product publication.
MultiscaleStageConfig
dataclass
Reviewed residual science and coarse executor-batch limit.
Source code in src/hebog/stages/multiscale.py
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | |
__post_init__()
Reject an unbounded task before stage products are initialized.
Source code in src/hebog/stages/multiscale.py
82 83 84 85 86 87 88 89 90 91 | |
MultiscaleStageResult
dataclass
Published products, stable topology, and scalar execution evidence.
Source code in src/hebog/stages/multiscale.py
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | |
multiscale_product_names()
Return the canonical accepted multiscale product set.
Source code in src/hebog/stages/multiscale.py
200 201 202 | |
run_multiscale_stage(source, background_rms_source, manifest, *, config, executor, sink)
Reconcile bounded multiscale topology and publish accepted products.
The first pass returns only compact side/corner summaries. After global reconciliation, workers recompute the same bounded filters, apply stable label mappings, and write accepted core products. This deliberate second read avoids an image-sized persisted filter-response bank. No scientific array is returned through the executor.
Source code in src/hebog/stages/multiscale.py
844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 | |
hebog.stages.support
The global support reduction the tile-native support pass depends on.
ADR-008's pass C needs the adjacent-scale persistence of the multiscale features, which decides which recovered support may stay published, and no bounded halo can supply it. It is reconciled here from compact per-core summaries and written back as owned cores, so the composition reads it by window instead of computing it over whole planes.
SupportTopologyStageConfig
dataclass
Reviewed scale orders and the coarse executor-batch limit.
Source code in src/hebog/stages/support.py
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | |
__post_init__()
Reject an unbounded task before stage products are initialized.
Source code in src/hebog/stages/support.py
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | |
SupportTopologyStageResult
dataclass
The published persistence plane and scalar execution evidence.
Source code in src/hebog/stages/support.py
77 78 79 80 81 82 83 84 85 86 87 88 | |
run_support_topology_stage(detection_source, manifest, *, config, executor, sink)
Reconcile adjacent-scale persistence and publish its plane.
The first round returns only compact per-scale core summaries and the adjacent-scale label overlaps each core observes. After reconciliation the second round labels the same core masks again and writes the scale features corroborated at an adjacent scale. No scientific array is returned through the executor.
Source code in src/hebog/stages/support.py
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 | |
support_product_names()
Return the canonical published support product set.
Source code in src/hebog/stages/support.py
158 159 160 | |
Published support
hebog.algorithms.extended_measurement
Pure measurement kernels for irregular extended emission.
DetectedSegmentPosition
dataclass
Flux centroid and peak tied to one accepted detection segment.
Source code in src/hebog/algorithms/extended_measurement.py
1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 | |
SegmentWindow
dataclass
Where one measured window sits inside its image plane.
Measuring a segment over the whole plane costs image size for every segment. A window lets a caller pass only the pixels around one segment while keeping every reported position in the plane's pixel frame.
Source code in src/hebog/algorithms/extended_measurement.py
1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 | |
require_holds(shape_yx)
Reject a window that does not fit its plane.
Raises:
| Type | Description |
|---|---|
ValueError
|
If the origin is negative or the window leaves the plane. |
Source code in src/hebog/algorithms/extended_measurement.py
1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 | |
apply_owner_restores(original_labels, refined_labels, restored_owners)
Restore the original support of every owner cleanup splits or removes.
The decision is one boolean per owner, so a tile applies it to its own core without seeing the owner's whole window.
Source code in src/hebog/algorithms/extended_measurement.py
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 | |
assign_connected_source_support(source_labels, persistent, component)
Assign one connected support component to its nearest source seeds.
Every array covers the window that holds this component. Candidates are
the component's persistent pixels that no source seeds; the nearest
immutable source pixel owns each, and an exact distance tie goes to the
smaller source label, whose order follows the canonical source IDs.
source_labels is written in place and returned.
Source code in src/hebog/algorithms/extended_measurement.py
1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 | |
assign_nearest_seed_support(seed_labels, significant_support, valid_pixels, *, maximum_distance_pixels)
Give significant support the nearest seed pixel of its own component.
Positive input labels are the seeds and keep their pixels. A valid
significant pixel takes the label of the nearest seed pixel, by
straight-line distance, among the seeds of its own eight-connected
component of seeds and support, when that seed lies within
maximum_distance_pixels. Equal distances use the label whose first
row-major seed pixel comes first. The components are labelled here, so
the planes must hold every pixel of the support being partitioned.
Source code in src/hebog/algorithms/extended_measurement.py
1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 | |
assign_persistent_source_support(source_labels, persistent_multiscale_support, valid_pixels)
Assign connected persistent support to canonical source owners once.
Source labels are the already accepted catalogue-source partition. Exact persistent support connected to at least one source seed extends that source's measurement seed. Where support is connected to multiple sources, the nearest immutable source pixel owns it; exact distance ties use the smaller source label, whose ordering is derived from canonical source IDs. Disconnected, invalid, and non-persistent pixels cannot enter the result.
Source code in src/hebog/algorithms/extended_measurement.py
1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 | |
assign_seeded_multiscale_support(component_labels, significant_multiscale_support, valid_pixels, *, beam_major_fwhm_pixels, recovery_radius_beams=_MULTISCALE_RECOVERY_RADIUS_BEAMS, canonical_seed_references_yx=None)
Attach bounded multiscale support to its owner along its own pixels.
Positive input labels are authoritative direct-residual source identities and keep their pixels. Each other valid significant pixel takes the owner of the seed pixel nearest to it along an eight-connected path through valid significant pixels, in axial steps of one pixel and diagonal steps of the square root of two, when that path is no longer than the recovery radius. Equal lengths use the owner whose globally row-major seed reference appears first, independently of task-local label integers or completion order. Every pixel on such a shortest path takes the same owner, so each owner's support is connected through its own pixels, and a pixel its owner reaches only across unsupported or invalid pixels, or through another owner's, is not attached to it. Within four pixels, path length orders the offsets as straight-line distance does, so without such obstacles a pixel takes its straight-line nearest owner; only the reach can differ, a path off the axes and diagonals being the longer (2.41 pixels to an offset of one by two, against 2.24).
A pixel's owner depends only on the planes within the radius, so a tiled caller needs that halo and the global reference pixel of every owner present in its read.
Source code in src/hebog/algorithms/extended_measurement.py
897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 | |
clean_detected_segment_labels(component_labels)
Remove sub-beam protrusions while preserving segment identities.
A three-by-three binary opening is deliberately smaller than the sampled restoring beams supported by the source-finder contracts. It suppresses single-pixel flood-threshold excursions without growing, merging, or relabelling accepted emission.
Source code in src/hebog/algorithms/extended_measurement.py
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | |
expand_detected_segment_labels(component_labels, valid_pixels, *, radius_pixels)
Build unique nearest-segment apertures on observable pixels.
Expansion recovers original-pixel source wings omitted by the detection threshold. The input is one bounded measurement plane or tile. Where apertures overlap, each pixel belongs to its nearest accepted support, so close segments cannot double-count flux.
Source code in src/hebog/algorithms/extended_measurement.py
1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 | |
expand_source_measurement_labels(source_labels, valid_pixels, *, radius_pixels)
Expand source apertures with canonical source-identity tie breaking.
Source code in src/hebog/algorithms/extended_measurement.py
1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 | |
measure_segment_position_pixels(y_pixels, x_pixels, signal_jy_per_beam, *, plane_shape_yx)
Measure a signed-flux centroid and peak from support pixels alone.
The arrays hold one segment's support pixels in raster order, with coordinates in the plane's pixel frame. A segment too wide to read at once is measured from the pixels its cores return, and the result is the one a window holding the whole segment would give, bit for bit: every sum and the first maximum visit the same pixels in the same order.
Source code in src/hebog/algorithms/extended_measurement.py
1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 | |
multiscale_recovery_radius_pixels(beam_major_fwhm_pixels, *, recovery_radius_beams=_MULTISCALE_RECOVERY_RADIUS_BEAMS)
Return the reviewed coherent-support recovery radius in pixels.
Source code in src/hebog/algorithms/extended_measurement.py
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | |
nearest_source_seed_labels(seed_points_yx, seed_labels, candidate_points_yx)
Return the label of each candidate pixel's nearest source seed.
The points are (y, x) pixel coordinates in any one frame, and an
exact distance tie goes to the smaller source label, whose order follows
the canonical source IDs. One candidate's owner depends only on the
seeds, so a component too wide to read at once is assigned exactly by
each core that holds its candidates, from the seeds that can own them.
Raises:
| Type | Description |
|---|---|
ValueError
|
If there is no seed, or the arrays disagree. |
Source code in src/hebog/algorithms/extended_measurement.py
1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 | |
owner_support_needs_restore(published_window, kept_window, *, label_value)
Return whether cleanup removed one owner or split its publication.
Refinement may trim an owner's flood, but never remove it or split it.
An owner keeps its original support when refinement keeps none of its
pixels on its own evidence (kept_window, from
:func:refinement_kept_labels), such as a compact detection between the
detection threshold and the boundary floor whose footprint holds no full
opening element: pixels recovered only because another owner's opened
support lies near do not keep it. It keeps its original support too when
the pixels publication would give it (published_window, from
:func:published_owner_labels) are not one connected part.
The window must hold the owner's original, refined and published support
completely; connectivity cannot be decided from a part of it. Callers
that evaluate one owner per task use this decision, and the plane-wide
:func:restore_segment_owners applies it to every owner.
Source code in src/hebog/algorithms/extended_measurement.py
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | |
preserve_owner_publication_bridges(previous_window, refined_window, *, label_value)
Keep only the previous regions that connect one owner's support.
The window must hold the owner completely; connectivity cannot be decided from a part of it. A bridge is a previously published region touching two retained parts of the same owner. When the owner still falls apart, its whole previous support is restored, and a part that remains disconnected from the previous support is dropped rather than published separately. When refinement retained nothing of the owner, its whole previous support is restored too, so no published owner loses all of its support.
Source code in src/hebog/algorithms/extended_measurement.py
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 | |
publication_owner_windows(owner_labels)
Return each owner's label and the window holding its support.
Source code in src/hebog/algorithms/extended_measurement.py
453 454 455 456 457 458 459 460 461 462 463 464 465 466 | |
published_owner_labels(support_labels, measurement_labels, *, flood_labels)
Give each pixel of a support plane the owner measurement gives it.
A refined pixel of a flood is published for that flood's owner, which measurement gives it. A refined pixel outside every flood is published for its measurement owner only where it touches that owner's flood, one step from it, so an owner restored whole is published in one part. A pixel no owner measures is not published.
Recovery at the island threshold never keeps a pixel touching a flood outside it, as that pixel would be in the flood, so in the source finder no recovered pixel outside every flood is published; persistence alone can join one to its owner, with the pixels between.
Source code in src/hebog/algorithms/extended_measurement.py
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 | |
refine_multiscale_segment_labels(component_labels, combined_snr, significant_multiscale_support, *, beam_major_fwhm_pixels, core_minimum_neighbors=_MULTISCALE_CORE_MINIMUM_NEIGHBORS, boundary_minimum_snr=_MULTISCALE_BOUNDARY_MINIMUM_SNR, recovery_radius_beams=_MULTISCALE_RECOVERY_RADIUS_BEAMS, recovered_minimum_snr=None)
Refine segment support, restoring owners cleanup removes or splits.
The pixels publication gives each owner come from the whole-plane measurement ownership, so significant support must lie on valid pixels, as the published planes guarantee.
Source code in src/hebog/algorithms/extended_measurement.py
695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 | |
refine_multiscale_segment_support(component_labels, combined_snr, significant_multiscale_support, *, beam_major_fwhm_pixels, core_minimum_neighbors=_MULTISCALE_CORE_MINIMUM_NEIGHBORS, boundary_minimum_snr=_MULTISCALE_BOUNDARY_MINIMUM_SNR, recovery_radius_beams=_MULTISCALE_RECOVERY_RADIUS_BEAMS, recovered_minimum_snr=None)
Refine noisy flood boundaries with calibrated multiscale evidence.
Dense opened support remains without an additional significance test.
Sparse boundary pixels remain only at high combined S/N, while adjacent
significant à trous support may recover coherent emission omitted by the
original-pixel flood. When recovered_minimum_snr is supplied, recovered
support must also meet that original-pixel S/N floor. A recovered pixel
of an owner's own flood keeps that owner, as publication does; one
outside every flood inherits the nearest opened segment identity. This
preserves deterministic ownership without merging or relabelling sources.
Every decision here is bounded by the opening and recovery radii, so a
tile evaluates its own core exactly. Whether cleanup removed or split an
owner is not: :func:restore_segment_owners decides that per owner, and
:func:refine_multiscale_segment_labels composes the two.
Source code in src/hebog/algorithms/extended_measurement.py
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 | |
refine_persistent_publication_labels(component_labels, publication_labels, combined_snr, persistent_scale_support)
Publish connected owner support corroborated across adjacent scales.
Previously published low-confidence regions are retained only when they connect two retained parts of the same owner, or when nothing else of that owner is retained; no new threshold or ownership is introduced.
Source code in src/hebog/algorithms/extended_measurement.py
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 | |
refine_persistent_publication_support(component_labels, publication_labels, combined_snr, persistent_scale_support, *, published_owner_values=None)
Retain owner support corroborated across adjacent scales, per pixel.
Dense opened support and independently strong original-image boundaries remain unchanged. Sparse recovered pixels remain only when their exact scale feature participates in an adjacent-scale association.
Whether an owner is published anywhere decides whether its persistent
support is restored, which no bounded neighbourhood can answer. Tiled
callers pass published_owner_values, the owners published over the
whole image; a complete-plane call derives them.
Source code in src/hebog/algorithms/extended_measurement.py
486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 | |
refinement_kept_labels(component_labels, combined_snr, *, boundary_minimum_snr=_MULTISCALE_BOUNDARY_MINIMUM_SNR)
Return each owner's pixels refinement keeps on its own evidence.
These are its opened support and its pixels at the boundary floor. Both are bounded by the opening, so a tile evaluates its own core exactly.
Source code in src/hebog/algorithms/extended_measurement.py
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | |
restore_segment_owners(original_labels, refined_labels, *, published_labels, kept_labels)
Restore a direct owner only when cleanup would remove or split it.
Each owner is examined in the window holding its original and published support, instead of over the whole plane. Refinement recovers multiscale emission, so an owner can reach pixels its original support never covered, and those pixels decide whether cleanup split it. Every decision is taken before any owner is restored.
Source code in src/hebog/algorithms/extended_measurement.py
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 | |
segment_refinement_halo_pixels(beam_major_fwhm_pixels, *, recovery_radius_beams=_MULTISCALE_RECOVERY_RADIUS_BEAMS)
Return the halo covering refinement and persistence of the support.
Two reaches set it, and in each the radii add rather than compete.
Refinement recovers a pixel from opened support up to the recovery
radius r away, which it rounds up, and that opened support depends on
labels two pixels further: ceil(r) + 2. Persistence takes its dense
core from a 3x3 opening and a 3x3 count over the measurement labels,
three pixels, and measurement gives a pixel to a seed at most r
away, so at most floor(r) pixels along either axis:
floor(r) + 3. The two agree unless r is a whole number of
pixels, as it is at the default half-beam radius for any beam an even
number of pixels wide, where persistence needs one pixel more. The
second also covers refinement's own dense-core count, three pixels, when
the recovery radius is small.
Source code in src/hebog/algorithms/extended_measurement.py
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | |
hebog.algorithms.owner_connectivity
Owner connectivity decided from tile cores, exactly.
The support pass asks two questions of every owner that no bounded neighbourhood answers: whether cleanup splits its published support or removes it, and which earlier published regions bridge the parts of its persistent support, or replace it when none is left. Both are about the connected components of one label's pixels, and a component of one label connects only through pixels of that label, so the island reconciliation, which joins any two touching mask pixels, cannot answer them for owners that touch each other.
These functions answer them for an owner too wide to read at once. Each core
labels its own same-label components and keeps only their labels and the
component on each core-edge pixel; components join where they meet across
the edges of the cores that were observed; and the decisions are taken over
the joined components, exactly as
:func:~hebog.algorithms.extended_measurement.owner_support_needs_restore and
:func:~hebog.algorithms.extended_measurement.preserve_owner_publication_bridges
take them over a window holding the whole owner.
ComponentKey = tuple[str, int]
One core's tile identifier and a component number local to that core.
LabelComponentSummary
dataclass
One core's components, reduced to their labels and edge pixels.
labels[k - 1] is the label component k carries, and edges
holds the component on every pixel of the core's four edges, 0 where
there is none. That is all a join across cores needs.
Source code in src/hebog/algorithms/owner_connectivity.py
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | |
component_keys()
Name every component this core holds.
Source code in src/hebog/algorithms/owner_connectivity.py
58 59 60 61 62 63 | |
LabelComponents
dataclass
One core's same-label eight-connected components.
components numbers them from one: label by label in ascending order,
and in raster order within a label, so a core always numbers the same
plane the same way. labels[k - 1] is the label of component k.
Source code in src/hebog/algorithms/owner_connectivity.py
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | |
label_of()
Return a lookup from component number to label, 0 for none.
Source code in src/hebog/algorithms/owner_connectivity.py
93 94 95 | |
summary()
Return the labels and edge pixels, which is all a join needs.
Source code in src/hebog/algorithms/owner_connectivity.py
79 80 81 82 83 84 85 86 87 88 89 90 91 | |
OwnerBridgeCore
dataclass
What one core observed of the owners' bridge question, safe to return.
touching pairs the candidate and base components that touch inside
the core, and base_holding_previous names the base components holding
a previously published pixel of their owner.
Source code in src/hebog/algorithms/owner_connectivity.py
372 373 374 375 376 377 378 379 380 381 382 383 384 | |
OwnerBridgePlanes
dataclass
One core's base and candidate components for the owners it holds.
The base is each owner's persistent support; the candidates are its previously published pixels outside that support. They stay on the task that labelled them.
Source code in src/hebog/algorithms/owner_connectivity.py
359 360 361 362 363 364 365 366 367 368 369 | |
OwnerBridgeShare
dataclass
The components one core adds to their owners or clears from them.
Source code in src/hebog/algorithms/owner_connectivity.py
387 388 389 390 391 392 | |
apply_owner_bridges(final_core, planes, share)
Write one core's share of the bridge decisions, in place.
planes must be the ones this core observed, labelled from the same
planes with the same owners, so their component numbers are the ones the
decision names.
Source code in src/hebog/algorithms/owner_connectivity.py
628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 | |
decide_owner_bridges(cores)
Apply the owner bridge rule over joined components, owner by owner.
A candidate touching two parts of its owner's base bridges them. If the
base and its bridges are connected they are published; otherwise the
part holding the owner's earlier pixels is kept, with every candidate it
holds, and every other part is cleared. An owner with no base keeps all
of its candidates, which are then its whole earlier support. That is
:func:~hebog.algorithms.extended_measurement.preserve_owner_publication_bridges,
whose connected components here are the joined base and candidate
components and the touching pairs between them: two candidates never
touch, and neither do two base parts, or each would be one component.
Returns:
| Type | Description |
|---|---|
dict[str, OwnerBridgeShare]
|
Each core's share of the decisions, for the cores that change, and |
frozenset[int]
|
the owners whose support changes. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If an owner's earlier pixels lie in several parts that nothing reconnects, or it has no base and its earlier pixels are not one part, which the window rule refuses too. |
Source code in src/hebog/algorithms/owner_connectivity.py
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 | |
join_components(keys, touching)
Return every component's root once each touching pair is joined.
Two components share a root exactly when a chain of touching pairs links them; which member is the root does not matter, only that it is shared.
Source code in src/hebog/algorithms/owner_connectivity.py
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 | |
label_components(label_core, partition)
Label every same-label eight-connected component of one core.
Each label is labelled inside its own bounds, so the cost follows the labels' extents rather than the core times the number of labels.
Raises:
| Type | Description |
|---|---|
ValueError
|
If the plane is not the partition's core shape. |
Source code in src/hebog/algorithms/owner_connectivity.py
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | |
observe_owner_bridges(planes, previous_core)
Reduce one core's bridge components to what a decision needs.
Source code in src/hebog/algorithms/owner_connectivity.py
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 | |
owner_bridge_planes(persistent_core, previous_core, owners, partition)
Label one core's base and candidate components for chosen owners.
persistent_core is the persistent support the bridge rule refines
and previous_core the earlier publication, both over one core. An
owner's published pixel carries that owner or nothing in the persistent
plane, so its candidates are its published pixels the plane leaves empty.
Source code in src/hebog/algorithms/owner_connectivity.py
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 | |
owners_needing_restore(summaries, owners)
Return the owners whose pixels fall into several joined parts, or none.
The cores must hold every pixel of each owner asked about. An owner that
cleanup removed leaves no component in any core, so the caller names the
owners it asks about rather than the summaries naming them. This is
:func:~hebog.algorithms.extended_measurement.owner_support_needs_restore
for every owner at once.
Source code in src/hebog/algorithms/owner_connectivity.py
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 | |
touching_across_cores(first, second)
Return pairs of same-label components that touch across a core edge.
The first component of each pair comes from first and the second
from a neighbouring core of second, in any direction, so the pairs
between two planes are all found once and those within one plane twice.
Only the cores given are consulted: a core that holds none of the labels
need not be observed at all.
Source code in src/hebog/algorithms/owner_connectivity.py
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 | |
touching_within_core(first, second)
Return pairs of same-label components of two planes that touch.
Both planes cover one core, and a pixel touches its eight neighbours.
Source code in src/hebog/algorithms/owner_connectivity.py
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 | |
hebog.stages.publication
Owner-scoped and core-scoped rounds of the tile-native support pass.
ADR-008 splits the support pass because two of its steps are scoped to an owner rather than to a bounded neighbourhood: restoring an owner that cleanup would remove or whose publication it would split, and preserving the previously published regions that bridge two retained parts of one owner, or all of them when no part is retained. Each is decided once per owner, from the window holding that owner, and returns a record; the cores then apply those records and write the final labels and mask.
No admission bounds an owner's area, so an owner's window can be wider than
the read budget. Such an owner is never read whole: both of its questions are
about the connected components of its own pixels, so each core that its
window reaches labels its components, the components join across core edges,
and the decisions are taken over them
(:mod:hebog.algorithms.owner_connectivity), with exactly the answer the
window would give.
Every pixel quantity here is recomputed in the round that needs it rather than persisted, exactly as the detection pass recomputes its filters instead of storing a response bank.
PublicationStageConfig
dataclass
Reviewed support thresholds and the bounded task limits.
Source code in src/hebog/stages/publication.py
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | |
halo_pixels
property
Return the halo every pixel decision in this pass reads.
__post_init__()
Reject an unbounded task before stage products are initialized.
Source code in src/hebog/stages/publication.py
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | |
PublicationStageResult
dataclass
Published support products and scalar execution evidence.
Source code in src/hebog/stages/publication.py
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | |
publication_product_names()
Return the canonical published support product set.
Source code in src/hebog/stages/publication.py
276 277 278 | |
run_publication_stage(detection_source, support_source, manifest, *, detection_islands, config, executor, sink)
Decide owner connectivity, then publish the final support products.
Four rounds, in the order ADR-008 sets out: owners that cleanup would remove or whose publication it would split, the owners published anywhere, the label patches that bridge an owner's support or restore it when persistence keeps none, and the cores that apply all three with the caller's island admission. Only the last round writes.
An owner whose read exceeds maximum_batch_read_pixels is decided
from its cores instead of its window: one round labels its published
support in every core its window reaches, before the scan, and another
labels its base and candidate support, after it. The write round applies
each core's share of the decisions. wide_owner_count reports how many
owners took that path.
Source code in src/hebog/stages/publication.py
1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 | |
Components: deblending and fitting
hebog.algorithms.deblending
Deterministic bounded watershed deblending for compact islands.
CompactDeblendResult
dataclass
Bounded region topology, not measured sources or Gaussian fits.
Source code in src/hebog/algorithms/deblending.py
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | |
compact_summary()
Drop bounded region labels before returning through an executor.
Source code in src/hebog/algorithms/deblending.py
65 66 67 68 69 70 71 | |
CompactDeblendSummary
dataclass
Executor-safe compact region facts with no pixel label arrays.
Source code in src/hebog/algorithms/deblending.py
74 75 76 77 78 79 80 | |
CompactIslandPixels
dataclass
One admitted normalized island bounds region and exact membership.
Source code in src/hebog/algorithms/deblending.py
33 34 35 36 37 38 39 | |
DeblendedRegion
dataclass
One deterministic compact region for later scientific measurement.
Source code in src/hebog/algorithms/deblending.py
42 43 44 45 46 47 48 49 50 51 52 53 | |
deblend_compact_island(compact_island, config)
Split one admitted island into deterministic watershed regions.
The watershed floods the island's own intensity: every pixel belongs to the peak its steepest ascent reaches, and two peaks are judged at the pass between them, the highest level at which one connected part of the island holds both.
Source code in src/hebog/algorithms/deblending.py
502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 | |
hebog.algorithms.component_topology
Bounded component topology within connected detection islands.
DeblendedComponentTopology
dataclass
Component owners plus explicit bounded-deblending disposition.
Source code in src/hebog/algorithms/component_topology.py
29 30 31 32 33 34 35 36 | |
ParentComponentMembership
dataclass
One parent's deblended components, in that parent's own windows.
The labels are local to the parent, numbered from one in the order the
reviewed watershed produced them. A caller that deblends one parent per
task offsets them by the components every earlier parent produced, which
is what :func:deblend_component_topology does in one pass.
Source code in src/hebog/algorithms/component_topology.py
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | |
deblend_component_topology(normalized_residual, direct_component_labels, measurement_component_labels, valid_pixels, config)
Deblend admitted parents while preserving their complete support.
Direct connected islands remain the parent/support topology. Within each admitted parent, an intensity watershed defines Gaussian-component ownership: peaks split at the pass between them, and each component holds the pixels that rise to its own peak. Measurement pixels keep their original parent membership and are assigned to the nearest new direct seed with canonical tie-breaking. Parents above either hard compact-work bound remain one explicit deferred component; this bounded helper never drops their science.
Source code in src/hebog/algorithms/component_topology.py
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 | |
deblend_parent_components(normalized_window, direct_membership, measurement_membership, valid_window, *, parent_label, direct_bounds, measurement_bounds, image_shape_yx, first_pixel_yx, config)
Deblend one admitted parent inside the windows that hold it.
Every decision needs the parent's complete support and nothing beyond it, so one task can evaluate one parent exactly. A parent above either hard compact-work bound stays one explicit deferred component rather than losing its science, and so does a parent whose peak never reaches the detection threshold.
Source code in src/hebog/algorithms/component_topology.py
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 | |
parent_is_deferred(direct_bounds, direct_pixel_count, config)
Return whether a parent passes either hard compact-work bound.
Such a parent stays one explicit deferred component. That decision needs only the parent's bounds and size, and publishing it needs none of its pixels, so no task has to read a deferred parent's window.
Examples:
>>> bounds = CompactDeblendConfig(5.0, 2, 1.0, 7, 100, 250)
>>> parent_is_deferred(ImageBounds(0, 10, 0, 10), 60, bounds)
False
>>> parent_is_deferred(ImageBounds(0, 3, 0, 90), 60, bounds)
True
>>> parent_is_deferred(ImageBounds(0, 10, 0, 10), 101, bounds)
True
Source code in src/hebog/algorithms/component_topology.py
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | |
hebog.data_models.measurement
Compact scheduler-safe scientific measurement records.
CompactMeasurementGeometry
dataclass
Reviewed local solid angles and noise correlation for compact fits.
Source code in src/hebog/data_models/measurement.py
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | |
__post_init__()
Require explicit finite positive pixel and beam solid angles.
Source code in src/hebog/data_models/measurement.py
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | |
GaussianMomentInitializer
dataclass
Brightness-weighted pixel-space initializer for nonlinear fitting.
Source code in src/hebog/data_models/measurement.py
82 83 84 85 86 87 88 89 90 91 92 93 | |
MomentTarget
dataclass
Canonical island or deblended-region measurement identity.
Source code in src/hebog/data_models/measurement.py
61 62 63 64 65 66 67 68 | |
OwnedPixelPhotometry
dataclass
Finite owned-pixel photometry distinct from a fitted Gaussian.
Source code in src/hebog/data_models/measurement.py
71 72 73 74 75 76 77 78 79 | |
ShapeUnavailableMomentMeasurement
dataclass
Valid photometry whose pixel support cannot define a 2-D ellipse.
Source code in src/hebog/data_models/measurement.py
106 107 108 109 110 111 112 113 | |
UnavailableMomentMeasurement
dataclass
A target for which valid photometry cannot be reported.
Source code in src/hebog/data_models/measurement.py
116 117 118 119 120 121 122 123 124 125 | |
ValidMomentMeasurement
dataclass
Complete owned-pixel photometry and nonsingular shape initializer.
Source code in src/hebog/data_models/measurement.py
96 97 98 99 100 101 102 103 | |
hebog.algorithms.measurement
Readable vectorized moment oracle for exact compact memberships.
CompactMomentInput
Bases: Protocol
Structural exact-label input kept inside one coarse worker task.
Source code in src/hebog/algorithms/measurement.py
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | |
island
property
Return the reconciled parent island.
physical_residual
property
Return the bounded physical residual plane.
region_labels
property
Return exact zero-background deblended labels.
regions
property
Return canonical deblended-region summaries.
rms
property
Return the aligned bounded RMS plane.
valid_pixels
property
Return the aligned scientific-validity mask.
fitted_gaussian_integrated_flux_jy(*, amplitude_jy_per_beam, major_sigma_pixels, minor_sigma_pixels, geometry)
Convert one fitted Gaussian's infinite-plane area to integrated Jy.
Source code in src/hebog/algorithms/measurement.py
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | |
gaussian_beam_solid_angle_steradians(*, major_fwhm_degrees, minor_fwhm_degrees)
Return an elliptical Gaussian beam area from angular FWHM axes.
Source code in src/hebog/algorithms/measurement.py
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | |
measure_compact_moments(compact, geometry, config)
Measure one island and its exact regions without pixel-wise loops.
Source code in src/hebog/algorithms/measurement.py
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 | |
hebog.data_models.fitting
Compact scheduler-safe Gaussian fitting records.
FailedCompactGaussianFit
dataclass
An attempted fit that did not yield acceptable parameters.
Diagnostics are absent when numerical decomposition prevented a complete validated report; unknown work counts or residuals are not fabricated.
Source code in src/hebog/data_models/fitting.py
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | |
FittedGaussianPixelParameters
dataclass
One fitted Gaussian in global pixel coordinates and physical units.
Source code in src/hebog/data_models/fitting.py
14 15 16 17 18 19 20 21 22 23 24 | |
GaussianFitDiagnostics
dataclass
Bounded optimizer work and weighted-residual evidence.
Source code in src/hebog/data_models/fitting.py
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | |
GaussianFitUncertainty
dataclass
One-sigma position and flux covariance estimate for a fitted model.
Source code in src/hebog/data_models/fitting.py
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | |
shape_parameter_covariance = None
class-attribute
instance-attribute
Upper triangle for ordered major/minor sigma and angle in radians.
UnavailableCompactGaussianFit
dataclass
A region whose measurement cannot initialize the fit-all path.
Source code in src/hebog/data_models/fitting.py
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | |
ValidCompactGaussianFit
dataclass
A converged fit retaining its independent moment oracle.
Source code in src/hebog/data_models/fitting.py
103 104 105 106 107 108 109 110 111 112 | |
hebog.algorithms.fitting
Bounded joint compact Gaussian fitting with SciPy least squares.
MAXIMUM_JOINT_FIT_JACOBIAN_ELEMENTS = 1000000
module-attribute
Parameters times fitted pixels one joint fit admits.
MAXIMUM_JOINT_FIT_PARAMETERS = 96
module-attribute
Free parameters one joint fit admits: sixteen fixed-background ellipses.
fit_compact_gaussian_mixture(compact, moments, geometry, config, *, maximum_parameters=MAXIMUM_JOINT_FIT_PARAMETERS, maximum_jacobian_elements=MAXIMUM_JOINT_FIT_JACOBIAN_ELEMENTS)
Fit bounded neighbouring components jointly on original pixels.
This extends the existing free-ellipse solver, derivative, noise transform and covariance machinery. It does not add components or change detection. Callers supply one bounded parent plus context, excluding foreign owners. Work admission precedes allocation of the joint Jacobian. The background is fixed at the caller's independently estimated background map.
Source code in src/hebog/algorithms/fitting.py
1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 | |
joint_fit_admits(component_count, pixel_count, *, maximum_parameters=MAXIMUM_JOINT_FIT_PARAMETERS, maximum_jacobian_elements=MAXIMUM_JOINT_FIT_JACOBIAN_ELEMENTS)
Return whether one joint fit admits this many components and pixels.
The work is a Jacobian of six parameters per component by the fitted
pixels, refused before it is allocated. With owned-region pixel
support the fitted pixels are the components' own, so a caller that
counts those can apply this rule before any fit runs.
Source code in src/hebog/algorithms/fitting.py
1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 | |
hebog.algorithms.component_measurement
Bounded original-pixel Gaussian measurements for detected components.
ComponentGroupingEvidence
dataclass
Worker-local merge evidence, linear in the bounded group population.
Source code in src/hebog/algorithms/component_measurement.py
86 87 88 89 90 91 92 93 | |
ComponentMeasurements
dataclass
Fits retain detection labels; compact groups constrain association.
Source code in src/hebog/algorithms/component_measurement.py
96 97 98 99 100 101 102 103 104 105 106 107 108 109 | |
FitParentMeasurement
dataclass
One fit parent's bounded measurement outputs.
Every field is a record, so a caller that measures one fit parent per
task returns nothing that grows with the parent's area. The persistent
measurement support a measured parent contributes is not among them:
:func:fit_parent_measurement_support derives it from the planes in
support_bounds, so whoever writes the plane can derive it again.
Source code in src/hebog/algorithms/component_measurement.py
1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 | |
SupportFeatureGroups
dataclass
Extended groups and evidence one support feature contributed.
Source code in src/hebog/algorithms/component_measurement.py
783 784 785 786 787 788 | |
compact_window_is_admitted(window, *, maximum_bounds_pixels)
Return whether the reviewed compact bound admits one window.
A fit parent or support feature whose window the bound refuses is ADR-008 T3 work: the parent is deferred rather than fitted on truncated pixels, and the feature is left ungrouped, so neither window is read.
Source code in src/hebog/algorithms/component_measurement.py
796 797 798 799 800 801 802 803 804 805 806 807 | |
fit_parent_margin_pixels(fit_config, atrous_plan)
Return the context a fit parent reads beyond its own support.
Source code in src/hebog/algorithms/component_measurement.py
1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 | |
fit_parent_measurement_support(residual_window, rms_window, valid_window, fit_parent_window, *, parent_index, atrous_plan, minimum_support_fraction, detection_sigma, island_sigma, minimum_pixels)
Return the persistent measurement support one measured parent adds.
The windows are the parent's own read, its support plus the reviewed
context margin. The support depends on these planes and the reviewed
thresholds only, never on the parent's fit, so a core that holds part of
the window derives exactly what the measuring task would have returned.
Callers combine parents with a boolean OR, and call this only for a
parent that :func:measure_fit_parent_components did not defer.
Source code in src/hebog/algorithms/component_measurement.py
1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 | |
group_support_feature_components(residual_window, rms_window, valid_window, measurement_window, feature_window, fits, protected_labels, wcs, beam, atrous_plan, *, bounds, detection_sigma, island_sigma, minimum_pixels, minimum_support_fraction)
Group the components one connected support feature holds.
Both remaining cross-parent steps label the accumulated measurement
support with the same connectivity, so they share this work unit and one
read of its window. fits and protected_labels need only cover the
components whose measurement labels reach this window.
Source code in src/hebog/algorithms/component_measurement.py
1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 | |
measure_component_models(residual, rms, valid, direct_labels, measurement_labels, wcs, beam, moment_config, fit_config, *, detection_sigma, island_sigma, minimum_pixels, maximum_bounds_pixels, atrous_plan, minimum_support_fraction)
Fit each bounded connected measurement parent with original pixels.
No full-image fit matrix is constructed. Foreground owners outside a parent's window are excluded; negative background-context pixels remain in the fit. Positive exact seed pixels initialize the existing moment oracle only. Published ownership is never replaced by these fit masks.
Source code in src/hebog/algorithms/component_measurement.py
1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 | |
measure_fit_parent_components(residual_window, rms_window, valid_window, fit_parent_window, direct_window, measurement_window, geometry, moment_config, fit_config, *, parent_index, bounds, image_shape_yx, detection_sigma, island_sigma, minimum_pixels, maximum_bounds_pixels, atrous_plan, minimum_support_fraction)
Fit one bounded measurement parent from its own original pixels.
The window must hold the parent's support and the reviewed context margin around it; no decision here reads further, so one task can measure one fit parent exactly. A parent whose window exceeds the admitted bound is deferred rather than fitted on truncated pixels.
geometry is the caller's local beam and pixel geometry at the centre
of bounds, as
:func:~hebog.algorithms.astrometry.compact_geometries_from_wcs builds
it for a whole batch at once. Deriving it here instead would pay
Astropy's per-call frame machinery once per parent, which costs more
than the fit.
Source code in src/hebog/algorithms/component_measurement.py
1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 | |
reconcile_component_measurements(*, parents, features)
Reconcile the parents' and features' records into one measurement.
Every step that spans fit parents has already run: each connected support feature contributed its extended groups and grouping evidence. What is left is a reduction over records, so it holds no image-sized array at all: the support the parents contributed stays in the generation the cores wrote it to.
Source code in src/hebog/algorithms/component_measurement.py
1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 | |
support_feature_margin_pixels(atrous_plan)
Return the context one support feature reads beyond its own bounds.
Source code in src/hebog/algorithms/component_measurement.py
791 792 793 | |
support_feature_window(feature_bounds, *, margin, image_shape_yx, maximum_bounds_pixels)
Return one feature's grouping window, or absence when unbounded.
A feature wider than the reviewed compact bound is ADR-008 T3 work and contributes no grouping, exactly as the whole-plane pass leaves it.
Source code in src/hebog/algorithms/component_measurement.py
810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 | |
hebog.stages.object_extents
Records and window helpers the per-object stages share.
ADR-008's pass D evaluates each object inside the window that holds it and reduces the results hierarchically. Each per-object stage first has the cores observe every object's extent, reduces those observations into one record per parent here, and then reads each object through a window cropped from a wider read.
CoreExtent
dataclass
One parent's bounds and first pixel as one core observes them.
Source code in src/hebog/stages/object_extents.py
42 43 44 45 46 47 48 49 50 51 | |
ExtentBatchResult
dataclass
Array-free parent extents from one bounded scan task.
Source code in src/hebog/stages/object_extents.py
54 55 56 57 58 | |
ParentExtent
dataclass
One parent's support in each label plane, reduced over the cores.
Source code in src/hebog/stages/object_extents.py
31 32 33 34 35 36 37 38 39 | |
PublishBatchResult
dataclass
Persisted product identities and the labels each plane carried.
observed_labels pairs every label a core wrote with the plane that
carried it — 0 for direct ownership, 1 for measurement ownership — so the
stage can require both planes to name the same components without holding
either.
Source code in src/hebog/stages/object_extents.py
61 62 63 64 65 66 67 68 69 70 71 72 73 | |
bounds_intersect(first, second)
Return whether two half-open bounds share a pixel.
Source code in src/hebog/stages/object_extents.py
212 213 214 215 216 217 218 219 | |
core_label_extents(labels, bounds)
Return each label's bounds, first pixel and size in one owned core.
Source code in src/hebog/stages/object_extents.py
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | |
crop_slices(bounds, window)
Return the slices selecting one window inside a wider read.
Source code in src/hebog/stages/object_extents.py
191 192 193 194 195 196 197 198 | |
parent_holders(results)
Name the cores in which each parent holds a pixel.
Source code in src/hebog/stages/object_extents.py
201 202 203 204 205 206 207 208 209 | |
reduce_extents(results)
Merge every core's observation into one record per parent.
Source code in src/hebog/stages/object_extents.py
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | |
union_bounds(first, second)
Return the smallest bounds containing both inputs, if either exists.
Source code in src/hebog/stages/object_extents.py
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | |
hebog.stages.component_topology
Component topology, the first per-object round of the composition.
Every parent's deblending needs its complete support and nothing beyond it, so one task decides one parent exactly, and the cores then write the component labels they own.
Component numbering stays canonical because the driver offsets each parent's local labels by the components every earlier parent produced, in ascending parent order, which is the order a whole-plane pass would use. The driver needs only each parent's component count for that, so no component pixel reaches it: a core writing a deblended parent decides its memberships again from the parent's own windows, which gives the same memberships bit for bit.
ComponentTopologyStageConfig
dataclass
Reviewed deblending policy and the bounded task limits.
Source code in src/hebog/stages/component_topology.py
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | |
__post_init__()
Reject an unbounded task before stage products are initialized.
Source code in src/hebog/stages/component_topology.py
85 86 87 88 89 90 91 92 93 94 95 96 | |
ComponentTopologyStageResult
dataclass
Published component labels and scalar execution evidence.
Source code in src/hebog/stages/component_topology.py
99 100 101 102 103 104 105 106 107 108 109 110 111 112 | |
component_topology_product_names()
Return the canonical published component-topology product set.
Source code in src/hebog/stages/component_topology.py
180 181 182 | |
run_component_topology_stage(support_source, detection_source, manifest, *, config, executor, sink)
Deblend every parent in its own window and publish the components.
Three rounds: the cores observe each parent's extent, one task per batch of parents deblends them inside those extents and counts their components, and the cores write the component labels they own. Parent order is canonical, so the component numbering does not move with tile geometry or completion order.
The driver holds records only. A parent published as one component is its own support in both planes, so the cores that hold it relabel it from their own windows. That covers a parent beyond either hard compact-work bound, which is deferred exactly as the whole-plane deblender defers it, from its extent alone, and whose window is never read. A parent that splits is deblended again by each core that holds it, inside the same windows, which decides the same memberships; returning them instead would make the driver hold every component pixel in the image.
Source code in src/hebog/stages/component_topology.py
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 | |
hebog.stages.fit_parents
Fit parents: the owners fitted together, numbered and published by core.
Owners whose fit contexts touch need a joint model, and that connectivity follows a chain of any length, so it is reconciled from compact per-core summaries before any fit runs.
FitParentStageConfig
dataclass
The reviewed fit context margin, the joint-fit bounds and task limit.
read_margin_pixels and maximum_bounds_pixels are the window the
component-fit round reads around a parent and the compact bound that
admits it, so they must be that round's own. The joint fit's work
limits are not settings: the stage applies the fit's fixed ones, to a
parent's owners and their direct pixels as an owned-region fit
counts them. A parent beyond either is fitted island by island.
Source code in src/hebog/stages/fit_parents.py
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | |
__post_init__()
Reject an unbounded task before stage products are initialized.
Source code in src/hebog/stages/fit_parents.py
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | |
FitParentStageResult
dataclass
Published fit-parent labels and scalar execution evidence.
Source code in src/hebog/stages/fit_parents.py
107 108 109 110 111 112 113 114 115 116 117 | |
fit_parent_product_names()
Return the canonical published fit-parent product set.
Source code in src/hebog/stages/fit_parents.py
65 66 67 | |
run_fit_parent_stage(component_source, manifest, *, config, executor, sink)
Reconcile the fit contexts owners share and publish their numbers.
Owners whose contexts touch need a joint model, and that connectivity follows a chain of any length, so it is reconciled from compact per-core summaries before any fit runs. A parent of several owners that no joint fit can hold, by its work limits or the compact bound on its window, is fitted island by island: only then are the islands scanned and reconciled in one further round. The cores then write the fit-parent number each support pixel belongs to.
Source code in src/hebog/stages/fit_parents.py
630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 | |
hebog.stages.component_fits
Component fits: every fit parent measured in its own context window.
The measuring round also describes the direct components each parent owns, and the cores then write each measured parent's persistent support.
ComponentFitStageConfig
dataclass
Reviewed measurement policy and the bounded task limits.
Source code in src/hebog/stages/component_fits.py
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | |
margin_pixels
property
Return the context a fit parent reads beyond its own support.
__post_init__()
Reject an unbounded task before stage products are initialized.
Source code in src/hebog/stages/component_fits.py
103 104 105 106 107 108 109 110 111 112 113 114 | |
ComponentFitStageResult
dataclass
Published measurement support and every fit parent's records.
component_records describes every direct component the association
decision reads, in canonical first-pixel order. The parent that reads a
component's pixels builds it: the residual, the validity and both
component planes are already on that task, so nothing after the fits
reads a component's window again.
Source code in src/hebog/stages/component_fits.py
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | |
component_fit_product_names()
Return the canonical published component-fit product set.
Source code in src/hebog/stages/component_fits.py
83 84 85 | |
run_component_fit_stage(source, background_rms_source, detection_source, component_source, fit_parent_source, manifest, *, config, component_count, wcs_header_text, beam, executor, sink)
Fit every parent in its own context window and publish its support.
Three rounds: the cores observe each fit parent's extent, one task per batch of parents measures them inside that extent plus the reviewed context margin, and the cores derive each measured parent's persistent support again inside that window and write their own pixels of it. Only the last round writes, and no round returns an array.
The measuring round also describes the direct components each parent owns, because the residual and the validity those records need are already on the task that fits them.
A parent whose window the reviewed compact bound refuses is deferred, as the whole-plane pass defers it, so its window is never read. Its components are described instead from the pixels each core holding them returns, restored to raster order, which gives the records a window would give, bit for bit. No read is then wider than the budget, one core, or one window that bound admits, whichever is largest.
component_count is the count the topology stage that published
component_source returned. The records must describe exactly those
components, so a fit-parent read that misses one stops the stage rather
than publishing fewer components.
wcs_header_text is the caller's own header as
:meth:astropy.io.fits.Header.tostring writes it, not a WCS; see
:func:~hebog.algorithms.astrometry.celestial_wcs_from_header_text.
Source code in src/hebog/stages/component_fits.py
754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 | |
hebog.stages.extended_groups
Extended groups: the components every connected support feature holds.
ExtendedGroupStageConfig
dataclass
Reviewed grouping policy and the bounded task limits.
Source code in src/hebog/stages/extended_groups.py
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | |
margin_pixels
property
Return the context one support feature reads beyond its bounds.
__post_init__()
Reject an unbounded task before any round is submitted.
Source code in src/hebog/stages/extended_groups.py
91 92 93 94 95 96 97 98 99 100 101 102 | |
ExtendedGroupStageResult
dataclass
Every support feature's extended groups and grouping evidence.
Source code in src/hebog/stages/extended_groups.py
119 120 121 122 123 124 125 126 127 128 129 130 131 | |
SupportFeature
dataclass
One reconciled support feature and the window that groups it.
Source code in src/hebog/stages/extended_groups.py
110 111 112 113 114 115 116 | |
run_extended_group_stage(source, background_rms_source, detection_source, component_source, measurement_source, manifest, *, config, parents, wcs_header_text, beam, executor)
Group the components every connected support feature holds.
Two rounds and no write. The cores label the accumulated measurement support and observe which components lie in each local feature, and the reconciliation joins the features that meet across a core boundary. One task per batch of features then evaluates both cross-parent steps inside that feature's window, which is its reconciled bounds plus the reviewed margin.
wcs_header_text is the caller's own header as
:meth:astropy.io.fits.Header.tostring writes it, not a WCS; see
:func:~hebog.algorithms.astrometry.celestial_wcs_from_header_text.
Source code in src/hebog/stages/extended_groups.py
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 | |
Source association
hebog.algorithms.multiscale_association
Deterministic bounded association of exact multiscale supports.
ScaleDetectionPlane
dataclass
One bounded exact-support label plane and its local label records.
detections[index - 1] describes pixels labelled index. Labels are
deliberately local and may change with partition or task order; stable
detection identities determine every published association.
Source code in src/hebog/algorithms/multiscale_association.py
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | |
__post_init__()
Copy the bounded labels into immutable canonical storage.
Source code in src/hebog/algorithms/multiscale_association.py
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | |
ScaleDetectionRecords
dataclass
One scale's features, without the plane that labelled them.
Source code in src/hebog/algorithms/multiscale_association.py
96 97 98 99 100 101 102 103 104 105 106 | |
__post_init__()
Reject an unconfigured scale before any decision reads it.
Source code in src/hebog/algorithms/multiscale_association.py
103 104 105 106 | |
ScaleDetections
Bases: Protocol
One scale's stable feature records, with or without its labels.
Every hierarchy decision reads identities, bounds and responses, never
the label plane, so a pass that has already reconciled its features can
supply :class:ScaleDetectionRecords and hold no image-sized array.
Source code in src/hebog/algorithms/multiscale_association.py
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | |
detections
property
Return the features, ordered by their canonical first pixel.
scale_order
property
Return the configured scale these features belong to.
adjacent_scale_overlap_edges(planes)
Return canonical fine-to-coarse exact-overlap hierarchy edges.
This is the same bounded overlap evidence used by
:func:associate_adjacent_scale_detections, exposed so a catalogue-source
hierarchy can retain parent direction without constructing another graph
implementation.
Source code in src/hebog/algorithms/multiscale_association.py
577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 | |
associate_adjacent_scale_detections(planes)
Associate exact supports only across adjacent configured scales.
The kernel operates on bounded label planes. It creates vectorized overlap edges between adjacent scales and reduces their connected components to stable associations. Same-scale fragments can therefore join only through an accepted adjacent-scale path.
Source code in src/hebog/algorithms/multiscale_association.py
632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 | |
build_scale_detection_plane(significant_support, response_jy_per_beam, signal_to_noise, valid_pixels, *, scale_order, nominal_scale_beam_fwhm, origin_yx=(0, 0))
Build stable exact features from one reviewed significant scale mask.
Source code in src/hebog/algorithms/multiscale_association.py
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 | |
build_scale_detection_plane_from_islands(significant_support, islands, *, scale_order, nominal_scale_beam_fwhm)
Describe one scale from its stored support and reconciled islands.
A tiled pass reduces each feature's peak response and signal to noise
while the filter response is still in the task's memory, so a later pass
can describe the same features from the stored support mask alone. The
reconciled islands are ordered by their globally row-major canonical
pixel, which is the order scipy.ndimage.label assigns to the same
mask, so the labelling here reproduces the tiled global labels exactly.
Source code in src/hebog/algorithms/multiscale_association.py
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 | |
persistent_adjacent_scale_support(planes)
Return exact support whose features persist across adjacent scales.
Source code in src/hebog/algorithms/multiscale_association.py
656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 | |
persistent_scale_labels(scales, parent_edges)
Return each scale's labels whose feature persists to a neighbour.
Persistence is decided from the reduced adjacent-scale overlap edges and the feature records alone, so it holds no plane.
Source code in src/hebog/algorithms/multiscale_association.py
680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 | |
persistent_scale_support_window(labels, retained_labels)
Return the pixels of one window that one scale's retained labels own.
Source code in src/hebog/algorithms/multiscale_association.py
719 720 721 722 723 724 725 726 727 728 729 | |
persistent_seeded_scale_support(scale_snrs, scale_responses, valid, *, detection_sigma, island_sigma, minimum_pixels)
Apply one seeded adjacent-scale rule to non-publication support.
Callers pair each noise-calibrated SNR with the same beam-aware filtered response in Jy/beam, not the unfiltered residual. Source-protected statistics and source-owned photometry can reuse this support without admitting new catalogue detections or changing a published mask.
Source code in src/hebog/algorithms/multiscale_association.py
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | |
scale_detection_id(scale_order, canonical_pixel_yx)
Derive one stable feature identity from scale and global owner pixel.
A later pass names the same features from the reconciled island records alone, so this identity is part of the published contract rather than an internal detail of the plane builder.
Source code in src/hebog/algorithms/multiscale_association.py
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 | |
scale_detections_from_islands(islands, *, scale_order, nominal_scale_beam_fwhm)
Describe one scale's features from its reconciled islands alone.
A tiled pass reduces each feature's extent, canonical pixel and peak response while its filter response is still in the task's memory, so a later pass names the same features without labelling a plane again.
Source code in src/hebog/algorithms/multiscale_association.py
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | |
hebog.algorithms.component_records
Stable records of the detection components sources are built from.
build_detection_component_record(label_value, raster_indices, association_signal, *, image_width)
Describe one component from its own valid support pixels.
raster_indices are global y * image_width + x positions in
ascending raster order, and association_signal is aligned with them.
A component too wide to read at once arrives as pixels from each core
that holds it; restored to raster order, they are exactly the pixels a
window over it presents, so this is the record
:func:build_detection_component_records builds there, bit for bit.
Raises:
| Type | Description |
|---|---|
ValueError
|
If the component has no pixel, the arrays disagree, or the pixels are not in strictly ascending raster order. |
Source code in src/hebog/algorithms/component_records.py
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | |
build_detection_component_records(component_labels, association_signal, valid_pixels, *, origin_yx=(0, 0), canonical_component_references_yx=None)
Build stable component records from immutable exact owner support.
Source code in src/hebog/algorithms/component_records.py
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | |
stable_id(namespace, prefix, values)
Hash canonical identity fields into one stable domain identifier.
Source code in src/hebog/algorithms/component_records.py
25 26 27 28 29 30 31 | |
validated_component_planes(component_labels, association_signal, valid_pixels)
Return aligned component, signal, and validity planes.
Source code in src/hebog/algorithms/component_records.py
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | |
hebog.algorithms.feature_envelopes
Scale-feature envelopes and the overlap summary association decides on.
The association stage builds the same summary tile by tile from these
envelopes; :func:summarize_hierarchy_overlaps builds it from whole planes.
FeatureOverlaps
dataclass
Every pixel fact the hierarchy decision needs about one feature.
The feature is the object of this work: each field is derived inside the feature's own exact bounds plus the reviewed B3 footprint, so one task can produce it without seeing the plane around it.
Source code in src/hebog/algorithms/feature_envelopes.py
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | |
HierarchyOverlaps
dataclass
Every pixel fact the source hierarchy decision needs.
Each field is a reduction that a tile core or one feature's window can
produce and that merges associatively, so the decision that consumes it
is pure record logic and cannot depend on tile geometry.
support_component is zero where a feature is not wholly inside one
retained support component. influence_component_ids is filled only
for the features :func:influence_candidate_feature_ids admits, and
envelope_edges only for the scale pairs
:func:envelope_pair_is_needed admits, because no decision reads the
rest and deriving them is pixel work.
Source code in src/hebog/algorithms/feature_envelopes.py
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | |
adjacency(feature_ids)
Return the envelope overlap graph over the named features.
Source code in src/hebog/algorithms/feature_envelopes.py
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | |
by_id()
Index the feature overlaps by their stable identities.
Source code in src/hebog/algorithms/feature_envelopes.py
94 95 96 | |
envelope_pair_is_needed(first_scale_order, second_scale_order, *, terminal_scale_order)
Return whether any decision asks about this pair of scales.
Within-scale overlap builds each scale's adjacency graph, and the last two scales are paired once to corroborate a displaced terminal child. No other combination is read.
Source code in src/hebog/algorithms/feature_envelopes.py
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 | |
influence_candidate_feature_ids(exact_component_ids, parent_edges)
Return the features whose B3 influence a decision can ever read.
:func:_feature_influence_candidate rejects every other feature on
record evidence alone, so deriving their influence would be pixel work
nothing consumes.
Source code in src/hebog/algorithms/feature_envelopes.py
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 | |
scale_feature_envelope_bounds(feature_bounds, *, scale_order, image_shape_yx)
Return one feature's B3 envelope box, or absence beyond the footprint.
The box follows from the feature's own bounds, so a driver knows it from records alone and one task can evaluate the envelope inside it.
Source code in src/hebog/algorithms/feature_envelopes.py
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | |
scale_feature_envelope_support(exact_support, valid, *, scale_order)
Dilate one feature's exact support over its own envelope window.
Both arrays cover the envelope box that
:func:scale_feature_envelope_bounds returns.
Source code in src/hebog/algorithms/feature_envelopes.py
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | |
scale_feature_envelopes_overlap(first_support, first_bounds, second_support, second_bounds)
Return whether two bounded envelopes share a supported pixel.
Source code in src/hebog/algorithms/feature_envelopes.py
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | |
scale_feature_influence_bounds(envelope_bounds, *, scale_order, image_shape_yx)
Return the symmetric reviewed B3 influence box of one envelope.
Source code in src/hebog/algorithms/feature_envelopes.py
171 172 173 174 175 176 177 178 179 180 181 182 183 184 | |
scale_feature_influence_component_labels(envelope_seed, valid, component_labels, *, scale_order)
Return the owner labels within the symmetric reviewed B3 influence.
Every array covers the influence box that
:func:scale_feature_influence_bounds returns, with the envelope support
already placed at its offset inside envelope_seed. The labels are
those of component_labels; the caller names their components.
Source code in src/hebog/algorithms/feature_envelopes.py
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | |
summarize_hierarchy_overlaps(records, labels, planes, valid, significant)
Derive every pixel fact the hierarchy decision needs, whole-plane.
This is the serial oracle for the tiled rounds: each field is the same reduction a tile core or one feature's window produces, evaluated here over complete planes.
Source code in src/hebog/algorithms/feature_envelopes.py
447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 | |
hebog.algorithms.source_association
Conservative deterministic grouping of immutable detection components.
associate_components_by_multiscale_hierarchy(records, component_labels, scale_detection_planes, valid_pixels, *, significant_multiscale_support=None)
Partition direct owners at a corroborated common scale feature.
Direct component labels are immutable. Each owner attaches to the finest exact undilated scale features it intersects, then follows only unique adjacent-scale overlap parents. Owners group at their finest shared feature only when that feature persists to a parent, or when every owner directly attaches to the same feature. When exact sibling lineages remain separate, connected significant multiscale support may corroborate a persistent mutually unique pair or non-terminal cycle, but cannot create source membership by itself. A mutually unique adjacent-scale feature may also recover exactly one unresolved displaced owner when the parent and child share one direct anchor and two applications of the same fixed B3 footprint contain only that anchor and the displaced owner. This persistent feature evidence is self-corroborating, but it remains subject to whole-group reconciliation and cannot split or partially overlap an established source. At the last retained scale, a cycle may construct a parent when its constituent features have exact or mutually unique displaced children. One directly owned feature may lack a child without vetoing an otherwise persistent whole-source graph, but only when every feature shares one retained support component and no direct member has a competing cycle. A persistent feature without a direct owner may corroborate cycle geometry but cannot join catalogue membership, which still requires at least three immutable direct components. Displaced and missing-child evidence cannot create cycles or membership. Partial overlap with an exact group, missing support, branching, or conflicting convergence fails closed.
Source code in src/hebog/algorithms/source_association.py
1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 | |
associate_from_hierarchy_overlaps(records, planes, overlaps)
Decide source membership from reduced pixel facts alone.
Every pixel question has already been answered by the tile cores and the
per-feature windows that produced overlaps, so this step is record
logic and cannot depend on tile geometry or completion order.
Source code in src/hebog/algorithms/source_association.py
1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 | |
constrain_source_memberships(association, measured_groups)
Apply compact-model or resolved-morphology evidence before publication.
Unconstrained components remain separate. A hierarchy is a proposal, not positive evidence that a failed or deferred fit belongs to its neighbours. Explicit compact or resolved-morphology groups retain their membership.
Source code in src/hebog/algorithms/source_association.py
1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 | |
hebog.stages.association
Scheduler-facing rounds that answer the source hierarchy's pixel questions.
ADR-008's association round produces
:class:~hebog.algorithms.source_association.HierarchyOverlaps and nothing
else: the decision that consumes it is pure record logic, so it cannot depend
on tile geometry or completion order. Three rounds produce it. The cores
observe which components, features and retained support components meet; one
task per feature derives that feature's B3 influence inside its own window;
and one task per candidate pair decides whether two envelopes overlap inside
the box that holds them both.
HierarchyOverlapStageConfig
dataclass
The bounded task limits of the three association rounds.
Source code in src/hebog/stages/association.py
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | |
__post_init__()
Reject an unbounded task before any round is submitted.
Source code in src/hebog/stages/association.py
93 94 95 96 97 98 99 100 101 102 103 104 105 106 | |
HierarchyOverlapStageResult
dataclass
The reduced pixel facts and this stage's scalar execution evidence.
Source code in src/hebog/stages/association.py
109 110 111 112 113 114 115 116 117 118 119 120 121 122 | |
hierarchy_overlap_product_names()
Return the canonical published hierarchy-overlap product set.
Source code in src/hebog/stages/association.py
1120 1121 1122 | |
run_hierarchy_overlap_stage(detection_source, component_source, manifest, *, config, records, scale_detections, executor, sink)
Answer every pixel question the source hierarchy decision asks.
Three rounds and no write. The cores observe which components, features and retained support components meet, and the support components are reconciled across core boundaries; one task per feature derives that feature's reviewed B3 influence inside its own window; and one task per candidate pair decides whether two envelopes overlap inside the box that holds them both. Candidate pairs follow from the reconciled bounds, so only the pairs that can possibly meet read pixels.
A feature whose influence window, or a pair whose box, exceeds the read budget is never read whole. Both are dilations by the reviewed B3 radius, so each core that the work can reach decides its own pixels under that halo, and the parts join exactly.
Source code in src/hebog/stages/association.py
1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 | |
hebog.stages.sources
Scheduler-facing rounds that own the continuum catalogue's source planes.
ADR-008's catalogue rounds decide one object at a time. The owners a source holds are a record map, so the cores write the source labels from the shard that reaches them; the persistent support a source owns spans tiles, so it is reconciled first and then assigned inside each connected component's own window, by the cores that hold the component, so no assignment reaches the driver.
SourceLabelStageConfig
dataclass
The bounded task limit of the source-label rounds.
Source code in src/hebog/stages/sources.py
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | |
__post_init__()
Reject an unbounded task before any product is initialized.
Source code in src/hebog/stages/sources.py
92 93 94 95 96 97 98 99 100 101 | |
SourceLabelStageResult
dataclass
Published source labels and scalar execution evidence.
Source code in src/hebog/stages/sources.py
104 105 106 107 108 109 110 111 112 | |
SourceSupportStageConfig
dataclass
Reviewed support policy and the bounded task limits.
Source code in src/hebog/stages/sources.py
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 | |
__post_init__()
Reject an unbounded task before any product is initialized.
Source code in src/hebog/stages/sources.py
346 347 348 349 350 351 352 353 354 355 356 357 358 | |
SourceSupportStageResult
dataclass
Published source measurement labels and execution evidence.
Source code in src/hebog/stages/sources.py
361 362 363 364 365 366 367 368 369 370 371 372 373 | |
run_source_label_stage(component_source, manifest, *, config, source_by_owner, executor, sink)
Write the catalogue source each component owner belongs to.
Two rounds: the cores observe which owners they hold, and each then writes the labels of the shard that reaches it. The membership map is a record, so no accepted-label table is broadcast whole.
Source code in src/hebog/stages/sources.py
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 | |
run_source_support_stage(label_source, detection_source, scale_support_source, measurement_support_source, manifest, *, config, executor, sink)
Assign the persistent support each catalogue source owns.
Two rounds: the cores label the support they carry and the pieces that meet across a core boundary are reconciled, then each core assigns the connected components it holds, every unseeded pixel to its nearest source seed inside that component's own window, and writes its share over the seeds it already holds. A component spanning several cores is assigned by each of them from the same window, so they agree, and the driver holds each component's bounds rather than its assignment.
A component whose window exceeds maximum_batch_read_pixels is never
read whole. The cores holding it return its seeds in a round between
those two, and each core that holds its unseeded pixels gets back the
seeds that can own them and assigns them itself, which is the
assignment its window would make. The driver holds the seeds, never the
unseeded support.
Source code in src/hebog/stages/sources.py
1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 | |
source_label_product_names()
Return the canonical published source-label product set.
Source code in src/hebog/stages/sources.py
76 77 78 | |
source_support_product_names()
Return the canonical published source-support product set.
Source code in src/hebog/stages/sources.py
81 82 83 | |
hebog.science.detection_islands
Detection islands of the installed composition and their ownership.
DetectionIslandCatalogue
dataclass
Every measured island and the islands each owner's support reaches.
Source code in src/hebog/science/detection_islands.py
69 70 71 72 73 74 | |
build_detection_island_catalogue(residual_jy_per_beam, rms_jy_per_beam, retained_mask, owner_labels, parent_labels, *, beam_area_pixels)
Measure every island of one complete retained mask, in raster order.
This is the readable whole-plane reference for the tiled rounds in
:mod:hebog.stages.islands, which label each core and reconcile the
fragments instead of labelling the plane. Rows are ordered by the island's
canonical first pixel, which is the order labelling a whole plane gives.
owner_labels are the measurement labels of the components the
catalogue publishes; an owner is linked to every island its retained
support reaches, because published support can be split between islands.
parent_labels are the measurement labels of the owners those
components were deblended from: a component whose own support reaches
no island is linked to the islands its parent's support reaches.
Source code in src/hebog/science/detection_islands.py
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | |
detection_island_identifier(first_pixel_yx)
Name one detection island by the first pixel it owns.
Raster order makes the first pixel canonical: it does not depend on how the mask was partitioned or in which order the tiles completed.
Examples:
>>> detection_island_identifier((12, 40))
'island-detection-12-40'
Source code in src/hebog/science/detection_islands.py
23 24 25 26 27 28 29 30 31 32 33 | |
island_ids_by_component(component_pairs, parent_pairs, component_parents, *, identifier_by_island_label)
Name the islands each component reaches, or else its parent's.
A component reaches the islands its own support overlaps. Support refinement can leave part of an owner outside the retained mask, such as a faint component deblended onto a brighter one's rim; that component then belongs to the islands its parent owner reaches, as a Gaussian belongs to the island it was fitted in, rather than to none. The pairs come either from one whole plane or from the cores that observed them.
Examples:
>>> island_ids_by_component(
... ((1, 10),),
... ((7, 10),),
... ((1, 7), (2, 7)),
... identifier_by_island_label={10: "island-a"},
... )
{1: ('island-a',), 2: ('island-a',)}
Source code in src/hebog/science/detection_islands.py
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 | |
island_ids_by_owner(pairs, *, identifier_by_island_label)
Name the islands every owner reaches, from observed label pairs.
The pairs come either from one whole plane or from the cores that observed them, so this join is the same in both compositions.
Source code in src/hebog/science/detection_islands.py
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | |
measure_detection_island(residual_jy_per_beam, rms_jy_per_beam, support, *, first_pixel_yx, beam_area_pixels)
Summarise one island over the exact pixels its mask retains.
Every array covers the window that holds the island, and support is
that island alone: an island is mask connectivity, not owner support, so
nothing here consults a label plane. The flux is the signed residual over
those pixels, which is why an island row is reported without an
uncertainty.
Raises:
| Type | Description |
|---|---|
ValueError
|
If the island retains no pixel in this window. |
Source code in src/hebog/science/detection_islands.py
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | |
observed_label_pairs(first_labels, second_labels)
Pair every label of one plane with each label of another it meets.
This pairs an owner with the islands its support reaches, or a component with the parent owner whose support holds it, over a whole plane or one core; the island join is the same either way.
Examples:
>>> import numpy as np
>>> observed_label_pairs(
... np.array([[3, 3, 0], [0, 4, 4]]),
... np.array([[1, 2, 2], [0, 2, 0]]),
... )
((3, 1), (3, 2), (4, 2))
Source code in src/hebog/science/detection_islands.py
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | |
hebog.stages.islands
Scheduler-facing rounds that measure one catalogue row per island.
ADR-008's island round is the one object round whose objects are mask connectivity rather than owner support: an island is a connected region of the published retained mask, so it spans tiles exactly as a label plane does and is reconciled the same way. Its labels are never published, because only these rounds read them, and an island's own bounds hold it entirely, so the round that measures it recovers it by labelling its own window.
An island is not bounded in area, so its window can exceed the read budget: a filament may cross the whole image. Such an island is never read whole. The cores that hold it relabel themselves exactly as the scan did, the reconciled mapping names its pixels there, and the row is measured from those pixels alone.
DetectionIslandStageConfig
dataclass
The reviewed beam area and the bounded task limits.
Source code in src/hebog/stages/islands.py
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | |
__post_init__()
Reject an unbounded task before any round is submitted.
Source code in src/hebog/stages/islands.py
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | |
DetectionIslandStageResult
dataclass
Every measured island, its owners, and scalar evidence.
Source code in src/hebog/stages/islands.py
105 106 107 108 109 110 111 112 113 114 115 116 117 118 | |
run_detection_island_stage(source, background_rms_source, publication_source, component_source, manifest, *, config, executor)
Measure every island of the retained mask, each in its own window.
Two rounds and one reconciliation: the cores label their own retained mask and observe which owners its islands hold, the fragments reconcile into islands numbered by canonical first pixel, and one task per batch of islands measures their rows. The round publishes no plane, because only these rounds read the island labels.
island_ids_by_owner names, for every component, the islands its own
support reaches, or, when it reaches none, the islands of the parent
owner it was deblended from.
An island whose own window exceeds maximum_batch_read_pixels takes a
third round instead of a window: the cores holding it return its pixels,
and its row is measured from them, so no read is wider than the budget or
one core, whichever is larger.
Source code in src/hebog/stages/islands.py
708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 | |
Catalogue rows and astrometry
hebog.data_models.astrometry
Compact celestial transformation and beam-deconvolution records.
CelestialCompactGaussianFit
dataclass
One valid compact fit transformed to reviewed catalogue meanings.
Source code in src/hebog/data_models/astrometry.py
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | |
GaussianDeconvolution
dataclass
Identifiable axes or explicit absence after beam removal.
Source code in src/hebog/data_models/astrometry.py
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | |
__post_init__()
Keep full, one-axis, and absent states unambiguous.
Source code in src/hebog/data_models/astrometry.py
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | |
LocalTangentPlaneTransform
dataclass
ICRS center and local east/north Jacobian for pixel (x, y).
Source code in src/hebog/data_models/astrometry.py
17 18 19 20 21 22 23 24 25 | |
hebog.algorithms.astrometry
Astropy WCS transforms and covariance-based beam deconvolution.
celestial_wcs_from_header_text(header_text)
Rebuild a celestial WCS from the header text it was written from.
Work that crosses a task boundary carries this text rather than a
:class:~astropy.wcs.WCS. Astropy pickles a WCS through a header it
reformats itself, which perturbs the transform in its last bits and moves
fitted uncertainties by parts in 1e9; rebuilding from the caller's own
header text instead keeps every executor bit-identical. header_text
is :meth:astropy.io.fits.Header.tostring output, so its cards are
fixed-width and unseparated.
Source code in src/hebog/algorithms/astrometry.py
66 67 68 69 70 71 72 73 74 75 76 77 | |
celestial_wcs_from_metadata(metadata)
Reconstruct an independent celestial WCS from serialized metadata.
Source code in src/hebog/algorithms/astrometry.py
57 58 59 60 61 62 63 | |
compact_geometries_from_wcs(beam, celestial_wcs, positions_xy)
Transform beam and pixels for several positions in one conversion.
Equivalent to :func:compact_geometry_from_wcs at each position. One
conversion pays Astropy's per-call frame machinery once rather than once
per measured object, which dominates it at these window sizes.
Source code in src/hebog/algorithms/astrometry.py
910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 | |
compact_geometry_at_pixel(metadata, position_xy, *, celestial_wcs=None, transform=None)
Derive reviewed local pixel and restoring-beam solid angles.
Source code in src/hebog/algorithms/astrometry.py
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 | |
compact_geometry_from_transform(beam, transform)
Derive local measurement geometry without unrelated spectral data.
Source code in src/hebog/algorithms/astrometry.py
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 | |
compact_geometry_from_wcs(beam, celestial_wcs, position_xy)
Transform native beam and pixels into the same ICRS tangent basis.
Source code in src/hebog/algorithms/astrometry.py
287 288 289 290 291 292 293 294 295 296 | |
deconvolve_gaussian_shapes(fitted_shape, beam, *, relative_tolerance)
Subtract beam covariance with explicit absence states.
Source code in src/hebog/algorithms/astrometry.py
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 | |
local_tangent_plane_transform(metadata, position_xy, *, celestial_wcs=None)
Return the ICRS center and local east/north pixel Jacobian.
ICRS and FK5 inputs are both transformed to ICRS through Astropy's frame
tie, matching :func:restoring_beam_in_icrs.
Source code in src/hebog/algorithms/astrometry.py
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | |
local_tangent_plane_transform_from_wcs(celestial_wcs, position_xy)
Return the ICRS tangent transform from an explicit celestial WCS.
Source code in src/hebog/algorithms/astrometry.py
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | |
local_tangent_plane_transforms_from_wcs(celestial_wcs, positions_xy)
Return one ICRS tangent transform per position, in one conversion.
Equivalent to :func:local_tangent_plane_transform_from_wcs at each
position, and exact rather than approximate: Astropy applies the same
element-wise transform whether it is given one coordinate or many, so
the sampled sky positions are bit-for-bit those of the single-position
calls. Its cost is the per-call frame machinery, which one conversion
pays once instead of once per measured object.
Source code in src/hebog/algorithms/astrometry.py
801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 | |
moment_equivalent_gaussian_shape(covariance_pixels_squared, transform)
Transform one positive pixel moment covariance into a sky ellipse.
Source code in src/hebog/algorithms/astrometry.py
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | |
restoring_beam_in_icrs(beam, celestial_wcs, position_xy)
Rotate a native equatorial FITS beam PA into local ICRS axes.
FK5 equinox precession rotates local north along with the coordinates. Transform a one-arcsecond directional offset using Astropy, preserving the angular beam axes. ICRS returns the original beam without arithmetic. This boundary supports ICRS/FK5, not frames with non-rotational geometry.
Source code in src/hebog/algorithms/astrometry.py
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 | |
restoring_beams_in_icrs(beam, celestial_wcs, positions_xy)
Rotate one native beam into local ICRS axes at several positions.
Equivalent to :func:restoring_beam_in_icrs at each position, for the
same reason :func:local_tangent_plane_transforms_from_wcs is: the
offset and position-angle transforms are element-wise.
Source code in src/hebog/algorithms/astrometry.py
875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 | |
transform_compact_fit_at_tangent(fit, beam, transform, *, deconvolution_relative_tolerance=1e-10, extension_significance_sigma=5.0, deconvolution_axis_significance_sigma=5.0)
Project a Jy/beam fit using an explicit local celestial transform.
Source code in src/hebog/algorithms/astrometry.py
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 | |
hebog.science.catalogue_rows
Internal catalogue rows in canonical physical units.
The quick check's PyBDSF reference worker builds these rows, and its cached
results are keyed by this module's code. The module therefore holds only the
rows, apart from the composition records in :mod:hebog.science.models and
the algorithms they import, so that editing those keeps the cached results.
CatalogueEllipse
dataclass
One canonical catalogue ellipse and optional one-sigma errors.
Source code in src/hebog/science/catalogue_rows.py
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | |
__post_init__()
Require a positive ordered ellipse modulo 180 degrees.
Source code in src/hebog/science/catalogue_rows.py
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | |
CatalogueSource
dataclass
One internal source-catalogue row in canonical physical units.
Source code in src/hebog/science/catalogue_rows.py
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 | |
__post_init__()
Validate identity, coordinates, and positive finite fluxes.
Source code in src/hebog/science/catalogue_rows.py
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | |
from_units(*, identifier, right_ascension, declination, angle_unit, peak_flux_density, peak_flux_unit, integrated_flux_density, integrated_flux_unit)
classmethod
Convert supported angular and flux units into canonical units.
Source code in src/hebog/science/catalogue_rows.py
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 | |
hebog.science.segment_rows
Segment catalogue rows and segment moments of the installed composition.
A segment is one detection label measured as a whole: its position, fluxes and moment-equivalent shape, before any component is fitted.
SegmentPixels
dataclass
The pixels one segment's row reads, in raster order.
A pixel is here when the segment holds it in its seeded ownership
(owned) or in its expanded aperture (aperture); a caller may add
others. Coordinates are in the image's pixel frame and every array is
aligned with y. Each reduction a row makes is over one of those two
sets, so any such superset in raster order gives the same row: a window
over the segment, or the pieces its cores return.
Source code in src/hebog/science/segment_rows.py
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 | |
SegmentRowMeasurement
dataclass
One segment's measured row, before its centroid has a sky position.
centroid_xy is where the row's coordinate belongs, in the image's
pixel frame, so a caller measuring many segments takes every centroid
first and converts them together; see :func:segment_row_at.
Source code in src/hebog/science/segment_rows.py
397 398 399 400 401 402 403 404 405 406 407 408 409 410 | |
build_hebog_segment_catalogue(image_jy_per_beam, background_jy_per_beam, valid_pixels, component_labels, header, *, beam_major_fwhm_pixels, beam_minor_fwhm_pixels, measurement_aperture_radius_beams=4.0, position_signal_jy_per_beam=None, denoised_position_maximum_peak_to_mean_ratio=3.0, aperture_tie_policy='nearest-support', position_labels=None, position_diagnostics=None)
Measure catalogue rows for physically measurable blind segments.
Labels remain the authoritative record of every accepted detection. Expanded-aperture photometry is preferred. When surrounding negative residuals make that aperture non-positive, the accepted owner's positive exact support provides an explicitly flagged conservative fallback.
Source code in src/hebog/science/segment_rows.py
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 | |
build_hebog_segment_moment_catalogue(image_jy_per_beam, background_jy_per_beam, valid_pixels, component_labels, header, *, beam_major_fwhm_pixels, beam_minor_fwhm_pixels, measurement_aperture_radius_beams=4.0, position_signal_jy_per_beam=None, denoised_position_maximum_peak_to_mean_ratio=3.0, aperture_tie_policy='nearest-support', position_labels=None, position_diagnostics=None)
Publish exact-support moment shapes without changing photometry.
Source code in src/hebog/science/segment_rows.py
854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 | |
build_segment_row(residual_window, position_signal_window, valid_window, centroid_window, aperture_window, background_window, celestial_wcs, *, label_value, window, beam_area_pixels, denoised_position_maximum_peak_to_mean_ratio, position_diagnostics=None)
Measure and place one segment's row, one segment at a time.
This is the readable reference for the batched path in
:mod:hebog.stages.catalogue_rows, which converts every centroid of a
batch together.
Source code in src/hebog/science/segment_rows.py
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 | |
catalogue_ellipse(shape)
Translate one validated Gaussian-like shape into catalogue units.
Source code in src/hebog/science/segment_rows.py
633 634 635 636 637 638 639 640 641 642 | |
measure_segment_row(residual_window, position_signal_window, valid_window, centroid_window, aperture_window, background_window, *, label_value, window, beam_area_pixels, denoised_position_maximum_peak_to_mean_ratio, position_diagnostics=None)
Measure one segment's catalogue row inside its own window.
Every array covers that segment's exact support joined with its expanded
aperture, which is the window :func:_segment_crop returns, so this work
costs the segment's own pixels rather than the plane around it. The row
is :func:measure_segment_row_pixels over the pixels of the window the
segment owns or holds in its aperture.
Source code in src/hebog/science/segment_rows.py
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 | |
measure_segment_row_pixels(pixels, *, label_value, plane_shape_yx, beam_area_pixels, denoised_position_maximum_peak_to_mean_ratio, position_diagnostics=None)
Measure one segment's catalogue row from its own pixels.
This is the half that reads pixels, and it needs no WCS. Absence means the segment has no measurable row, not an error.
Source code in src/hebog/science/segment_rows.py
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 | |
moment_shape_fields_at(moment, *, transform, beam_icrs)
Return catalogue fields for one moment under its own local geometry.
transform and beam_icrs belong to this moment's centroid. A
moment the local geometry cannot describe is reported as unavailable,
exactly as an unmeasurable one is.
Source code in src/hebog/science/segment_rows.py
785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 | |
segment_local_rms(rms_jy_per_beam, owner_window, *, label_value)
Return the median local noise over one segment's exact owned support.
owner_window is the segment's seeded ownership, not its expanded
aperture: the noise a catalogue row quotes describes the pixels the
segment itself owns. Both arrays cover the same window. A pixel whose
estimate is not finite and positive carries no usable noise, and
None means this segment owns no pixel that does.
Examples:
>>> import numpy as np
>>> rms = np.array([[1.0, 3.0], [np.nan, 5.0]])
>>> owners = np.array([[2, 2], [2, 0]])
>>> segment_local_rms(rms, owners, label_value=2)
2.0
>>> segment_local_rms(rms, owners, label_value=1) is None
True
Source code in src/hebog/science/segment_rows.py
724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 | |
segment_local_rms_pixels(rms_jy_per_beam)
Return the median usable noise over one segment's owned pixels.
The array holds the noise at the pixels the segment owns, so a segment too wide to read at once quotes the noise its window would give.
Source code in src/hebog/science/segment_rows.py
752 753 754 755 756 757 758 759 760 761 762 763 | |
segment_moment(residual_jy_per_beam, support, window=None)
Return one segment's weighted centroid and covariance, or None.
This is the half of a moment shape that reads pixels. Its centroid is
where the shape's local geometry belongs, so a caller measuring many
segments takes every centroid first and transforms them together; see
:func:moment_shape_fields_at.
Source code in src/hebog/science/segment_rows.py
766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 | |
segment_moment_pixels(y_pixels, x_pixels, residual_jy_per_beam)
Return a positive centroid and covariance from support pixels alone.
The arrays hold the segment's measured support in raster order, with coordinates in the image's pixel frame, so a segment too wide to read at once gives the moment its window would give, bit for bit.
Source code in src/hebog/science/segment_rows.py
645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 | |
segment_row_at(measurement, *, right_ascension_degrees, declination_degrees)
Return one measured row at the sky position its centroid earns.
Source code in src/hebog/science/segment_rows.py
563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 | |
unavailable_moment_shape_fields()
Return the fields of a segment whose shape cannot be measured.
Source code in src/hebog/science/segment_rows.py
713 714 715 716 717 718 719 720 721 | |
hebog.science.catalogues
Reconstructed source and component catalogues of the composition.
AssociatedMomentCatalogues
dataclass
Binding source rows plus retained immutable component diagnostics.
Source code in src/hebog/science/catalogues.py
40 41 42 43 44 45 46 47 | |
build_hebog_reconstructed_source_catalogues(header, *, component_measurements=None, association, hierarchy, component_rows, source_rows, source_positions)
Assemble each common-parent catalogue source exactly once.
Direct seed labels define hierarchy identity. Recovered measurement labels define masks and apertures. Immutable component measurements remain diagnostic. Binding source rows are measured from a source-label plane before aperture expansion, so every observable pixel belongs to at most one source aperture.
This assembles records only: every row was measured by the stage that held the window it was measured in, and every plane the rows describe was checked by the core that wrote it — direct ownership against the measurement plane and the validity beside it, source ownership against the memberships the cores were given.
Source code in src/hebog/science/catalogues.py
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 | |
local_rms_by_object_id(association, *, component_local_rms, source_local_rms)
Name each measured owner's local noise by its catalogue identity.
The row passes measure noise per label, because that is what the plane they read carries: components by their measurement label and sources by their canonical source label, which is the membership's position here. An owner whose support carries no usable estimate is absent, exactly as it is in the mappings this joins.
Source code in src/hebog/science/catalogues.py
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | |
source_label_by_owner(association)
Map each immutable component owner to its canonical source label.
Source code in src/hebog/science/catalogues.py
50 51 52 53 54 55 56 57 58 59 60 61 62 63 | |
hebog.stages.catalogue_rows
Scheduler-facing rounds that measure one catalogue row per segment.
ADR-008's source-row round measures each segment inside the window holding its exact support and its expanded aperture. Only the aperture expansion crosses a segment's own bounds, and it reaches no further than the reviewed radius, so the cores write it under that halo and every row after it is bounded by the segment it describes. No round reduces anything globally.
SegmentRowStageConfig
dataclass
Reviewed row policy and the bounded task limits.
Source code in src/hebog/stages/catalogue_rows.py
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | |
__post_init__()
Reject an unbounded task before any product is initialized.
Source code in src/hebog/stages/catalogue_rows.py
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | |
SegmentRowStageResult
dataclass
Published apertures, the rows they measure, and scalar evidence.
local_rms_by_label holds the median local noise over each segment's
exact owned support, for every segment the rounds observed rather than
only the measurable ones: a catalogue row that no row measured can still
be published from a fitted model, and it quotes the same noise.
Source code in src/hebog/stages/catalogue_rows.py
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | |
run_segment_row_stage(source, background_rms_source, detection_source, label_source, centroid_source, position_source, manifest, *, config, wcs_header_text, beam, executor, sink)
Measure one catalogue row per segment, inside the window holding it.
Three rounds and one global reduction fewer than every other object round: the cores write the expanded apertures under the reviewed radius, they then observe the bounds each segment and aperture occupies, and one task per batch of segments measures their rows, moment shapes and the local noise over the support they own.
wcs_header_text is the caller's own header as
:meth:astropy.io.fits.Header.tostring writes it, not a WCS; see
:func:~hebog.algorithms.astrometry.celestial_wcs_from_header_text.
A segment whose window exceeds maximum_batch_read_pixels is never
read whole. The cores holding it return the pixels its row visits, and
the row is measured from them restored to raster order, which is the row
its window would give.
Source code in src/hebog/stages/catalogue_rows.py
971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 | |
segment_row_product_names()
Return the canonical published segment-row product set.
Source code in src/hebog/stages/catalogue_rows.py
82 83 84 | |
hebog.science.continuum
Current continuum detection and publication-support composition.
compact_deblend_config(config)
Return the reviewed deblending policy at the caller's threshold.
A parent is deblended only where its peak clears the caller's detection threshold, so the reviewed minimum is lowered to just below it rather than to a second, independent threshold.
Source code in src/hebog/science/continuum.py
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | |
residual_detection_config(review)
Return the reviewed thresholds the tiled detection pass runs under.
Source code in src/hebog/science/continuum.py
43 44 45 46 47 48 49 50 51 52 53 54 | |
retained_scale_detections(multiscale)
Describe the retained per-scale features from published records.
The detection pass reconciled these features and published their labels, so this step names them without labelling a plane again, and without holding one: the cores that wrote the scale masks already required them to lie inside the domain their own estimate covers.
Source code in src/hebog/science/continuum.py
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | |
Source-count estimate
hebog.expected_source_count counts an image's bright local maxima before
an analysis, so that a caller can reserve hebog.analysis_memory_bytes
for them; these are its kernels.
hebog.algorithms.source_count
Count an image's bright local maxima, an upper estimate of its sources.
A published source has a peak at least the detection threshold times the
local noise above the background, so the pixels that are the highest of
their 3x3 neighbourhood and that far above a block's median bound the
sources a run can publish. The image is taken in blocks of
:data:BLOCK_PIXELS a side, so the count needs no image-sized array; each
block's noise is its valid pixels' 3-sigma-clipped standard deviation,
lowered to the image's typical block noise where the block's is higher.
These kernels estimate memory before an analysis, not sources: a noise peak counts as a source would, so the count errs high.
BLOCK_PIXELS = 512
module-attribute
The side of a noise block, in pixels.
On the quick check's varying-noise case, 150-pixel blocks, the RMS box
Rapthor passes to PyBDSF, read faint sources' own emission as noise and
counted fewer peaks than the sources published; 512-pixel blocks bounded
the sources of every quick-check, agreement and benchmark case.
MINIMUM_BLOCK_SAMPLES = 64
module-attribute
Valid pixels a block needs before its own noise is measured.
BlockNoise
dataclass
A block's clipped median and standard deviation, in image units.
Source code in src/hebog/algorithms/source_count.py
42 43 44 45 46 47 | |
block_noise(values, valid_pixels)
Return a block's 3-sigma-clipped median and standard deviation.
Returns None when fewer than :data:MINIMUM_BLOCK_SAMPLES pixels
are valid or the clipped spread is not positive.
Source code in src/hebog/algorithms/source_count.py
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | |
count_peaks(values, valid_pixels, core, threshold)
Count the core's valid pixels that are 3x3 maxima at the threshold.
A pixel counts when it is valid, no valid neighbour is higher and it is
at least threshold. The window around the core supplies the
neighbours of its edge pixels; invalid pixels are no one's neighbour.
Equal neighbours both count.
Source code in src/hebog/algorithms/source_count.py
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | |
peak_threshold(noise, *, reference_sigma, detection_sigma)
Return the value a block's peak must reach to count.
It is the block's median plus detection_sigma times the lower of
the block's noise and the image's typical noise: a block's spread is
inflated by a bright source in it, or by a primary-beam correction's
noisier edge, and the typical noise is too high for a quiet block.
Source code in src/hebog/algorithms/source_count.py
78 79 80 81 82 83 84 85 86 87 88 | |
reference_sigma(noises)
Return the median of the blocks' noise, the image's typical noise.
Returns None when no block measured its noise.
Source code in src/hebog/algorithms/source_count.py
69 70 71 72 73 74 75 | |
Workflow adapters
hebog.adapters.rapthor runs one Rapthor sector through find_sources and
writes the files Rapthor's filter_skymodel step reads, under Rapthor's
names; hebog.adapters.rapthor_catalogue holds the eight-column catalogue
codec it writes them with, and hebog.adapters.rapthor_comparison compares
one sector's Hebog and PyBDSF products for Rapthor's dual-run mode. Rapthor
calls the adapter on
Rapthor's Hebog branch,
not yet merged.
hebog.adapters.rapthor
Hebog as the source finder of Rapthor's filter_skymodel step.
Rapthor's step runs PyBDSF through LSMTool on one sector's two images, the
primary-beam-corrected true-sky image and the flat-noise image, then
filters the sector's sky models with LSMTool's filter_sources.
:func:find_sector_sources runs Hebog in its place, in-process on the
executor Rapthor builds, and writes the files Rapthor and filter_sources
read, under the names Rapthor's PyBDSF step gives them. Rapthor calls it
and then filter_sources; this module imports no Rapthor, Prefect,
LSMTool or scheduler objects.
RapthorBlankedImageError
Bases: RuntimeError
A sector image has no pixel to measure, as PyBDSF reports it.
PyBDSF raises RuntimeError("All pixels in the image are blanked.")
when every pixel is NaN, and Rapthor's step recognises that message and
writes its empty products, so this error carries the same message and
type. Hebog also counts as blank a pixel inside a 3x3 square of one
value, as imagers fill blanked regions, so an image of one value is
blank too.
Source code in src/hebog/adapters/rapthor.py
56 57 58 59 60 61 62 63 64 65 66 67 68 69 | |
__init__()
Carry PyBDSF's message.
Source code in src/hebog/adapters/rapthor.py
67 68 69 | |
RapthorCompatibilityConfig
dataclass
Rapthor's source-finding settings, under Rapthor's names.
threshpix and threshisl are the detection and island thresholds
in sigma that Rapthor's imaging strategy passes (5 and 3, or 5 and 4 in
early self-calibration cycles). The minimum island size is not a
setting: :func:find_sector_sources applies PyBDSF's rule to the
sector's beam. profile and background choose Hebog's science
profile and background. Rapthor's are continuum and zero,
PyBDSF's zero mean map: continuum passes the truth-based gate under
either background, and with a zero background it covers more of the
true emission and keeps the mean map Rapthor passes to PyBDSF. The
compact profile fails that gate. The other options LSMTool passes
to PyBDSF (the RMS boxes, the bright-source threshold and the wavelet
scales) are fixed by Hebog's reviewed science, and LSMTool's mask filter
is LSMTool's own; the Rapthor source-finding contract maps each to what
replaces it.
Source code in src/hebog/adapters/rapthor.py
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | |
__post_init__()
Fail where the settings are made, not after the images load.
Source code in src/hebog/adapters/rapthor.py
97 98 99 | |
source_finder_config(minimum_island_pixels)
Return the finder's configuration for one minimum island size.
Source code in src/hebog/adapters/rapthor.py
101 102 103 104 105 106 107 108 109 110 111 | |
RapthorSourceFindingRequest
dataclass
One Rapthor sector's two images, and the root its products are named by.
output_root is Rapthor's <working directory>/<image name>. The
products are <root>.source_catalog.fits, <root>.true_sky_rms.fits
and <root>.flat_noise_rms.fits, the island mask is
<true-sky image name>.mask.fits in the root's directory, and Hebog's
own product bundle is the directory <root>.hebog. run_id names
the sector's analysis; a retried task passes the same one.
Source code in src/hebog/adapters/rapthor.py
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | |
__post_init__()
Reject unsupported versions and empty run identifiers.
Source code in src/hebog/adapters/rapthor.py
132 133 134 135 136 137 | |
RapthorSourceFindingResult
dataclass
The files one sector's analysis wrote for Rapthor, and its counts.
mask_path is the island mask LSMTool's filter_sources clips to
the sector polygon, in place, and groups the sky model by. With no
island, as with PyBDSF's nisl of zero, LSMTool writes a dummy sky
model instead. products_directory is Hebog's own bundle, whose
diagnostics bind the run to its inputs, configuration and science.
Source code in src/hebog/adapters/rapthor.py
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | |
__post_init__()
Validate the version and scalar result metadata.
Source code in src/hebog/adapters/rapthor.py
161 162 163 164 165 166 167 168 169 170 | |
find_sector_sources(request, config, executor)
Find one sector's sources and write the files Rapthor's step reads.
One :func:hebog.find_sources run analyses the true-sky image and
estimates the flat-noise image's RMS, on the executor the caller built,
with Rapthor's thresholds and PyBDSF's minimum island for the sector's
beam. It publishes Hebog's bundle in <root>.hebog, from which this
function writes the eight-column catalogue, the two RMS maps and the
island mask in PyBDSF's four-axis layout, each under Rapthor's name.
Files an earlier run left under those four names are removed before the analysis starts, and a failure removes those this call wrote, so after a failed call none exists. A retry of a finished request reuses the bundle without analysing the images again; a bundle of another request is refused and kept.
Raises:
| Type | Description |
|---|---|
RapthorBlankedImageError
|
If either image has no pixel Hebog measures, so its RMS is unavailable. Rapthor's step handles it as it handles PyBDSF's error. |
SourceFinderError
|
If Hebog refuses the sector, or
|
Source code in src/hebog/adapters/rapthor.py
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 | |
pybdsf_minimum_island_pixels(metadata)
Return the minimum island size PyBDSF would use, in pixels.
PyBDSF's minpix_isl defaults to max(6, int(beam area / 3)), with
the beam area in pixels taken as 1.1331 times the major axis over the
pixel width times the minor axis over the pixel height. The widths are
the celestial WCS's pixel scales, |CDELT1| and |CDELT2| for the
north-up images Rapthor writes, as PyBDSF reads them.
Source code in src/hebog/adapters/rapthor.py
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | |
hebog.adapters.rapthor_comparison
Compare one sector's Hebog and PyBDSF products in Rapthor's dual-run mode.
In dual-run mode Rapthor runs both finders on one sector, each under its
own output root, and keeps both product sets until it selects one.
:func:compare_sector_products reads the four files each finder wrote and
reports how they differ, bound to the exact bytes of all eight and to
Hebog's provenance. It reads both sets and changes neither.
FinderProducts
Bases: BaseModel
One finder's four files for the sector, and its source count.
Source code in src/hebog/adapters/rapthor_comparison.py
100 101 102 103 104 105 106 107 108 109 | |
ProductIdentity
Bases: BaseModel
One product file's path and the exact bytes it held.
Source code in src/hebog/adapters/rapthor_comparison.py
90 91 92 93 94 95 96 97 | |
RapthorDualRunReport
Bases: BaseModel
How one sector's Hebog and PyBDSF products differ.
Sources match when each is the other's nearest within
match_radius_arcsec, half the restoring beam's major axis. The flux
ratio is Hebog's Total_flux over PyBDSF's, the median over matched
sources; each RMS ratio is Hebog's over PyBDSF's, the median over pixels
of a regular 16-pixel grid where both are finite and positive. A ratio
with nothing to compare is None. The mask counts are of nonzero
pixels.
Source code in src/hebog/adapters/rapthor_comparison.py
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | |
RapthorSectorProducts
dataclass
The four files Rapthor's filter step reads for one sector.
Source code in src/hebog/adapters/rapthor_comparison.py
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | |
named(output_root, true_sky_image_path)
classmethod
Name them as Rapthor's PyBDSF step names them from its root.
Source code in src/hebog/adapters/rapthor_comparison.py
56 57 58 59 60 61 62 63 64 65 66 67 68 | |
of(result)
classmethod
Return the four files one Hebog run wrote.
Source code in src/hebog/adapters/rapthor_comparison.py
70 71 72 73 74 75 76 77 78 | |
paths()
Return the catalogue, the two RMS maps and the mask, in order.
Source code in src/hebog/adapters/rapthor_comparison.py
80 81 82 83 84 85 86 87 | |
compare_sector_products(hebog, pybdsf, report_path)
Report how one sector's Hebog and PyBDSF products differ.
The report is written to report_path in one rename and returned.
Both product sets are only read, so Rapthor can still select either.
Raises:
| Type | Description |
|---|---|
ValueError
|
If the two finders' RMS maps or masks are on different pixel grids, or Hebog's bundle holds no public diagnostics. |
Source code in src/hebog/adapters/rapthor_comparison.py
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | |
hebog.adapters.rapthor_catalogue
Minimal deterministic PyBDSF-style catalogue view consumed by Rapthor.
Total_flux carries the source flux the public catalogue publishes. For
the continuum profile that is the sum of the source's fitted Gaussian
components, which is how PyBDSF defines it and what Rapthor's photometry
check compares against; a source with no admitted fit falls back to its
signed aperture. Isl_Total_flux remains the island sum, which Rapthor
carries only through the astrometry check.
read_rapthor_catalogue_fits(path)
Read and strictly validate the frozen Rapthor catalogue view.
Source code in src/hebog/adapters/rapthor_catalogue.py
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | |
write_rapthor_catalogue_fits(path, catalogue)
Atomically publish a deterministic validated Rapthor catalogue view.
Source code in src/hebog/adapters/rapthor_catalogue.py
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | |