Coverage for python/lsst/meas/extensions/multiprofit/pipetasks_fit.py: 63%

266 statements  

« prev     ^ index     » next       coverage.py v7.16.1, created at 2026-09-22 10:43 +0000

1# This file is part of meas_extensions_multiprofit. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (https://www.lsst.org). 

6# See the COPYRIGHT file at the top-level directory of this distribution 

7# for details of code ownership. 

8# 

9# This program is free software: you can redistribute it and/or modify 

10# it under the terms of the GNU General Public License as published by 

11# the Free Software Foundation, either version 3 of the License, or 

12# (at your option) any later version. 

13# 

14# This program is distributed in the hope that it will be useful, 

15# but WITHOUT ANY WARRANTY; without even the implied warranty of 

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with this program. If not, see <https://www.gnu.org/licenses/>. 

21 

22__all__ = ( 

23 "MultiProFitCoaddDeVFitConfig", 

24 "MultiProFitCoaddDeVFitTask", 

25 "MultiProFitCoaddExpDeVFitConfig", 

26 "MultiProFitCoaddExpDeVFitTask", 

27 "MultiProFitCoaddExpFitConfig", 

28 "MultiProFitCoaddExpFitTask", 

29 "MultiProFitCoaddGaussFitConfig", 

30 "MultiProFitCoaddGaussFitTask", 

31 "MultiProFitCoaddObjectFitConfig", 

32 "MultiProFitCoaddPointFitConfig", 

33 "MultiProFitCoaddPsfFitConfig", 

34 "MultiProFitCoaddPsfFitTask", 

35 "MultiProFitCoaddSersicFitConfig", 

36 "MultiProFitCoaddSersicFitTask", 

37 "component_names_default", 

38 "model_names_default", 

39) 

40 

41import itertools 

42import math 

43from abc import abstractmethod 

44from collections.abc import Mapping, Sequence 

45from types import SimpleNamespace 

46from typing import Any 

47 

48import lsst.gauss2d.fit as g2f 

49from lsst.daf.butler import DeferredDatasetHandle 

50from lsst.multiprofit.componentconfig import ( 

51 GaussianComponentConfig, 

52 ParameterConfig, 

53 SersicComponentConfig, 

54 SersicIndexParameterConfig, 

55) 

56from lsst.multiprofit.fitting.fit_source import CatalogExposureSourcesABC, CatalogSourceFitterConfigData 

57from lsst.multiprofit.modelconfig import ModelConfig 

58from lsst.multiprofit.sourceconfig import ComponentGroupConfig, SourceConfig 

59from lsst.pex.config import ConfigDictField, Field 

60from lsst.pipe.tasks.fit_coadd_multiband import ( 

61 CatalogExposureInputs, 

62 CoaddMultibandFitConfig, 

63 CoaddMultibandFitConnections, 

64 CoaddMultibandFitTask, 

65) 

66from lsst.pipe.tasks.fit_coadd_psf import CoaddPsfFitConfig, CoaddPsfFitConnections, CoaddPsfFitTask 

67 

68from .fit_coadd_multiband import ( 

69 CachedBasicModelInitializer, 

70 MagnitudeDependentSizePriorConfig, 

71 MakeBasicInitializerAction, 

72 ModelInitializer, 

73 MultiProFitSourceTask, 

74 PsfComponentsActionBase, 

75 SourceTablePsfComponentsAction, 

76) 

77from .fit_coadd_psf import MultiProFitPsfTask 

78from .input_config import InputConfig 

79 

80component_names_default = SimpleNamespace( 

81 point="point", 

82 gauss="gauss", 

83 exp="exp", 

84 deV="deV", 

85 sersic="sersic", 

86) 

87 

88model_names_default = SimpleNamespace( 

89 point="Point", 

90 gauss="Gauss", 

91 exp="Exp", 

92 deV="DeV", 

93 sersic="Sersic", 

94 fixed_cen="FixedCen", 

95 shapelet_psf="ShapeletPsf", 

96) 

97 

98 

99class MultiProFitCoaddPsfFitConfig( 

100 CoaddPsfFitConfig, 

101 pipelineConnections=CoaddPsfFitConnections, 

102): 

103 """MultiProFit PSF fit task config.""" 

104 

105 def setDefaults(self): 

106 super().setDefaults() 

107 self.fit_coadd_psf.retarget(MultiProFitPsfTask) 

108 self.fit_coadd_psf.config_fit.eval_residual = False 

109 

110 

111class MultiProFitCoaddPsfFitTask(CoaddPsfFitTask): 

112 """MultiProFit PSF fit task.""" 

113 

114 ConfigClass = MultiProFitCoaddPsfFitConfig 

115 _DefaultName = "multiProFitCoaddPsfFit" 

116 

117 

118class MultiProFitCoaddObjectFitConnections(CoaddMultibandFitConnections): 

119 def __init__(self, *, config=None): 

120 super().__init__(config=config) 

121 for name, config_input in config.inputs_init.items(): 

122 if hasattr(self, name): 

123 raise ValueError( 

124 f"{config_input=} {name=} is invalid, due to being an existing attribute of {self=}" 

125 ) 

126 if config_input.is_multipatch or not config_input.is_multiband: 

127 raise ValueError( 

128 f"Single-band and/or multipatch initialization config_input entries ({name})" 

129 f" are not supported yet." 

130 ) 

131 connection = config_input.get_connection(name) 

132 setattr(self, name, connection) 

133 

134 

135class MultiProFitCoaddObjectFitConfig( 

136 CoaddMultibandFitConfig, 

137 pipelineConnections=MultiProFitCoaddObjectFitConnections, 

138): 

139 """Generic MultiProFit source fit task config.""" 

140 

141 inputs_init = ConfigDictField( 

142 doc="Mapping of optional input dataset configs by name, for initialization", 

143 keytype=str, 

144 itemtype=InputConfig, 

145 default={}, 

146 ) 

147 

148 # This needs to be set, ideally in setDefaults of subclasses 

149 name_model = Field[str](doc="The name of the model", default=None) 

150 

151 def _get_source(self): 

152 return next(iter(self.fit_coadd_multiband.config_model.sources.values())) 

153 

154 def _get_component_group(self, source: SourceConfig | None = None): 

155 if source is None: 

156 source = self._get_source() 

157 return next(iter(source.component_groups.values())) 

158 

159 def add_point_source(self, name: str | None = None): 

160 """Add a point source component. 

161 

162 Parameters 

163 ---------- 

164 name 

165 The name of the component. 

166 """ 

167 if name is None: 167 ↛ 169line 167 didn't jump to line 169 because the condition on line 167 was always true

168 name = component_names_default.point 

169 source = self._get_source() 

170 group = self._get_component_group(source=source) 

171 if name in group.components_gauss: 171 ↛ 172line 171 didn't jump to line 172 because the condition on line 171 was never true

172 raise RuntimeError(f"{name=} component already exists in {source=}") 

173 group.components_gauss[name] = self.make_point_source_component() 

174 self.connections.name_table += model_names_default.point 

175 

176 def finalize( 

177 self, 

178 add_point_source: bool = False, 

179 fix_centroid: bool = False, 

180 use_shapelet_psf: bool = False, 

181 prior_axrat_stddev: float | str | None = None, 

182 ): 

183 """Apply runtime configuration changes to this config. 

184 

185 Parameters 

186 ---------- 

187 add_point_source 

188 Whether to add a point source component. 

189 fix_centroid 

190 Whether to fix the centroid. 

191 use_shapelet_psf 

192 Whether to initialize PSF parameters from prior shapelet fits. 

193 prior_axrat_stddev 

194 The standard deviation for the axis ratio prior. Ignored if None, 

195 otherwise it must be convertible to a float. 

196 """ 

197 if add_point_source: 

198 self.add_point_source() 

199 if fix_centroid: 

200 self.fix_centroid() 

201 if use_shapelet_psf: 

202 self.use_shapelet_psf() 

203 if prior_axrat_stddev is not None: 

204 self.set_prior_axrat_stddev(float(prior_axrat_stddev)) 

205 

206 def fix_centroid(self): 

207 """Fix (freeze) the source centroid parameters.""" 

208 group = self._get_component_group() 

209 centroids = group.centroids["default"] 

210 centroids.x.fixed = True 

211 centroids.y.fixed = True 

212 self.connections.name_table += model_names_default.fixed_cen 

213 

214 @classmethod 

215 @abstractmethod 

216 def get_model_name_default(cls) -> str: 

217 """Return the default name for this model in table columns.""" 

218 raise NotImplementedError("Subclasses must implement get_model_name_default") 

219 

220 @classmethod 

221 def get_model_name_full(cls) -> str: 

222 """Return a longer, more descriptive name for the model.""" 

223 return cls.get_model_name_default() 

224 

225 @abstractmethod 

226 def make_default_model_config(self) -> ModelConfig: 

227 """Make a default configuration object for this model.""" 

228 raise NotImplementedError("Subclasses must implement make_default_model_config") 

229 

230 @staticmethod 

231 def make_point_source_component() -> GaussianComponentConfig: 

232 """Make a point source component config (zero-size Gaussian).""" 

233 return GaussianComponentConfig( 

234 size_x=ParameterConfig(value_initial=0.0, fixed=True), 

235 size_y=ParameterConfig(value_initial=0.0, fixed=True), 

236 rho=ParameterConfig(value_initial=0.0, fixed=True), 

237 ) 

238 

239 @staticmethod 

240 def make_sersic_component(**kwargs) -> SersicComponentConfig: 

241 """Make a default Sersic component config. 

242 

243 Parameters 

244 ---------- 

245 **kwargs 

246 Keyword arguments to pass to the SersicIndexParameterConfig. 

247 

248 Returns 

249 ------- 

250 config 

251 The default-initialized config. 

252 """ 

253 return SersicComponentConfig( 

254 prior_axrat_stddev=1.0, 

255 prior_size_stddev=0.2, 

256 sersic_index=SersicIndexParameterConfig(**kwargs), 

257 ) 

258 

259 @staticmethod 

260 def make_single_model_config(group: ComponentGroupConfig) -> ModelConfig: 

261 """Make a default single-source, single component group config. 

262 

263 Parameters 

264 ---------- 

265 group 

266 The component group config for the single source. 

267 

268 Returns 

269 ------- 

270 config 

271 A model config with a single nameless source and component group. 

272 """ 

273 return ModelConfig( 

274 sources={ 

275 "": SourceConfig( 

276 component_groups={ 

277 "": group, 

278 } 

279 ) 

280 } 

281 ) 

282 

283 def set_prior_axrat_stddev(self, stddev: float) -> None: 

284 """Set the standard deviation for all axis ratio priors. 

285 

286 Parameters 

287 ---------- 

288 stddev 

289 The standard deviation. 

290 """ 

291 for source in self.fit_coadd_multiband.config_model.sources.values(): 

292 for group in source.component_groups.values(): 

293 for comp in itertools.chain( 

294 group.components_gauss.values(), 

295 group.components_sersic.values(), 

296 ): 

297 comp.prior_axrat_stddev = stddev 

298 

299 group = self._get_component_group() 

300 centroids = group.centroids["default"] 

301 centroids.x.fixed = True 

302 centroids.y.fixed = True 

303 self.connections.name_table += model_names_default.fixed_cen 

304 

305 def setDefaults(self): 

306 super().setDefaults() 

307 self.fit_coadd_multiband.retarget(MultiProFitSourceTask) 

308 self.fit_coadd_multiband.action_psf = PsfComponentsActionBase() 

309 self.fit_coadd_multiband.bands_fit = ("u", "g", "r", "i", "z", "y") 

310 

311 self.fit_coadd_multiband.config_model = self.make_default_model_config() 

312 self.name_model = self.get_model_name_default() 

313 self.connections.name_table = self.name_model 

314 

315 def use_shapelet_psf(self): 

316 """Reconfigure self to use prior shapelet PSF fit parameters.""" 

317 self.fit_coadd_multiband.action_psf = SourceTablePsfComponentsAction() 

318 self.drop_psf_connection = True 

319 self.connections.name_table += model_names_default.shapelet_psf 

320 

321 

322class MultiProFitCoaddObjectFitTask(CoaddMultibandFitTask): 

323 """MultiProFit coadd object model fitting task.""" 

324 

325 ConfigClass = MultiProFitCoaddObjectFitConfig 

326 _DefaultName = "multiProFitCoaddObjectFit" 

327 

328 def make_kwargs(self, butlerQC, inputRefs, inputs): 

329 inputs_init = {} 

330 for name, config in self.config.inputs_init.items(): 

331 input_ = inputs[name][0] 

332 if isinstance(input_, DeferredDatasetHandle): 

333 parameters = None 

334 if config.needs_metadata: 

335 parameters = {"strip_astropy_meta_yaml": False} 

336 input_ = input_.get(parameters=parameters) 

337 

338 inputs_init[name] = (config, input_) 

339 

340 kwargs = {} 

341 if inputs_init: 

342 kwargs["inputs_init"] = inputs_init 

343 

344 return kwargs 

345 

346 

347class MultiProFitCoaddPointFitConfig( 

348 MultiProFitCoaddObjectFitConfig, 

349 pipelineConnections=MultiProFitCoaddObjectFitConnections, 

350): 

351 """MultiProFit single Sersic model fit task config.""" 

352 

353 @classmethod 

354 def get_model_name_default(cls) -> str: 

355 return model_names_default.point 

356 

357 @classmethod 

358 def get_model_name_full(cls) -> str: 

359 return "Point Source" 

360 

361 def make_default_model_config(self) -> ModelConfig: 

362 config_group = ComponentGroupConfig() 

363 # This is a bit silly but add_point_source will look for the first 

364 # source so it must be added now. Perhaps add_point_source should 

365 # add to a config instance or only self by default 

366 self.fit_coadd_multiband.config_model = self.make_single_model_config(group=config_group) 

367 self.add_point_source() 

368 return self.fit_coadd_multiband.config_model 

369 

370 

371class MultiProFitCoaddSersicFitConfig( 

372 MultiProFitCoaddObjectFitConfig, 

373 pipelineConnections=MultiProFitCoaddObjectFitConnections, 

374): 

375 """MultiProFit single Sersic model fit task config.""" 

376 

377 def _rename_defaults( 

378 self, 

379 name_new: str, 

380 name_model: str | None = None, 

381 name_old: str | None = None, 

382 index_new: float | None = None, 

383 fix_index: bool = False, 

384 ): 

385 """Rename the default Sersic component to something more specific. 

386 

387 This is intended for fixed index models such as exponential and 

388 deVaucouleurs. 

389 

390 Parameters 

391 ---------- 

392 name_new 

393 The new name for the component. 

394 name_model 

395 The new name of the model. Default is to capitalize name_new. 

396 name_old 

397 The old name of the component. Default is to set to 

398 component_names_default.sersic. 

399 index_new 

400 The initial value for the Sersic index. 

401 fix_index 

402 Whether the fix the index to the new value. 

403 """ 

404 if name_old is None: 404 ↛ 406line 404 didn't jump to line 406 because the condition on line 404 was always true

405 name_old = component_names_default.sersic 

406 if name_model is None: 406 ↛ 407line 406 didn't jump to line 407 because the condition on line 406 was never true

407 name_model = name_new.capitalize() 

408 group = self._get_component_group() 

409 comps_sersic = group.components_sersic 

410 

411 if name_new in comps_sersic: 411 ↛ 412line 411 didn't jump to line 412 because the condition on line 411 was never true

412 raise RuntimeError(f"{name_new=} is already in {comps_sersic=}") 

413 

414 comp_sersic = comps_sersic[name_old] 

415 del comps_sersic[name_old] 

416 if index_new is not None: 416 ↛ 418line 416 didn't jump to line 418 because the condition on line 416 was always true

417 comp_sersic.sersic_index.value_initial = index_new 

418 if fix_index: 418 ↛ 420line 418 didn't jump to line 420 because the condition on line 418 was always true

419 comp_sersic.sersic_index.fixed = True 

420 comps_sersic[name_new] = comp_sersic 

421 

422 if prior_old := self.fit_coadd_multiband.size_priors.get(name_old): 422 ↛ 426line 422 didn't jump to line 426 because the condition on line 422 was always true

423 self.fit_coadd_multiband.size_priors[name_new] = prior_old 

424 del self.fit_coadd_multiband.size_priors[name_old] 

425 

426 self.name_model = name_model 

427 self.connections.name_table = name_model 

428 

429 @classmethod 

430 def get_model_name_default(cls) -> str: 

431 return model_names_default.sersic 

432 

433 @classmethod 

434 def get_model_name_full(cls) -> str: 

435 return "Sersic" 

436 

437 def make_default_model_config(self) -> ModelConfig: 

438 config_group = ComponentGroupConfig( 

439 components_sersic={ 

440 component_names_default.sersic: self.make_sersic_component(), 

441 }, 

442 ) 

443 return self.make_single_model_config(group=config_group) 

444 

445 def setDefaults(self): 

446 super().setDefaults() 

447 # This is in pixels and based on DC2. See DM-46498 for details. 

448 self.fit_coadd_multiband.size_priors[component_names_default.sersic] = ( 

449 MagnitudeDependentSizePriorConfig( 

450 intercept_mag=22.6, 

451 slope_median_per_mag=-0.15, 

452 slope_stddev_per_mag=0, 

453 ) 

454 ) 

455 

456 

457class MultiProFitCoaddSersicFitTask(MultiProFitCoaddObjectFitTask): 

458 """MultiProFit single Sersic model fit task.""" 

459 

460 ConfigClass = MultiProFitCoaddSersicFitConfig 

461 _DefaultName = "multiProFitCoaddSersicFit" 

462 

463 

464class MultiProFitCoaddGaussFitConfig( 

465 MultiProFitCoaddSersicFitConfig, 

466 pipelineConnections=MultiProFitCoaddObjectFitConnections, 

467): 

468 """MultiProFit single Gaussian model fit task config.""" 

469 

470 @classmethod 

471 def get_model_name_default(cls) -> str: 

472 return model_names_default.gauss 

473 

474 @classmethod 

475 def get_model_name_full(cls) -> str: 

476 return "Gaussian" 

477 

478 def setDefaults(self): 

479 super().setDefaults() 

480 self._rename_defaults( 

481 name_new=component_names_default.gauss, 

482 name_model=model_names_default.gauss, 

483 index_new=0.5, 

484 fix_index=True, 

485 ) 

486 

487 

488class MultiProFitCoaddGaussFitTask(MultiProFitCoaddObjectFitTask): 

489 """MultiProFit single Gaussian model fit task.""" 

490 

491 ConfigClass = MultiProFitCoaddGaussFitConfig 

492 _DefaultName = "multiProFitCoaddGaussFit" 

493 

494 

495class MultiProFitCoaddExpFitConfig( 

496 MultiProFitCoaddSersicFitConfig, 

497 pipelineConnections=MultiProFitCoaddObjectFitConnections, 

498): 

499 """MultiProFit single exponential model fit task config.""" 

500 

501 @classmethod 

502 def get_model_name_default(cls) -> str: 

503 return model_names_default.exp 

504 

505 @classmethod 

506 def get_model_name_full(cls) -> str: 

507 return "Exponential" 

508 

509 def setDefaults(self): 

510 super().setDefaults() 

511 self._rename_defaults( 

512 name_new=component_names_default.exp, 

513 name_model=model_names_default.exp, 

514 index_new=1.0, 

515 fix_index=True, 

516 ) 

517 # These are typical values from DC2 and could/should be switched to a 

518 # more data-driven prior (from HSC?) 

519 prior_size = self.fit_coadd_multiband.size_priors[component_names_default.exp] 

520 prior_size.intercept_mag = 23.4 

521 prior_size.slope_median_per_mag = -0.14 

522 

523 

524class MultiProFitCoaddExpFitTask(MultiProFitCoaddObjectFitTask): 

525 """MultiProFit single exponential model fit task.""" 

526 

527 ConfigClass = MultiProFitCoaddExpFitConfig 

528 _DefaultName = "multiProFitCoaddExpFit" 

529 

530 

531class MultiProFitCoaddDeVFitConfig( 

532 MultiProFitCoaddSersicFitConfig, 

533 pipelineConnections=MultiProFitCoaddObjectFitConnections, 

534): 

535 """MultiProFit single DeVaucouleurs model fit task config.""" 

536 

537 @classmethod 

538 def get_model_name_default(cls) -> str: 

539 return model_names_default.deV 

540 

541 @classmethod 

542 def get_model_name_full(cls) -> str: 

543 return "de Vaucouleurs" 

544 

545 def setDefaults(self): 

546 super().setDefaults() 

547 self._rename_defaults( 

548 name_new=component_names_default.deV, 

549 name_model=model_names_default.deV, 

550 index_new=4.0, 

551 fix_index=True, 

552 ) 

553 # These are typical values from DC2 and could/should be switched to a 

554 # more data-driven prior (from HSC?). See DM-46498 for details. 

555 prior_size = self.fit_coadd_multiband.size_priors[component_names_default.deV] 

556 prior_size.intercept_mag = 21.2 

557 prior_size.slope_median_per_mag = -0.14 

558 

559 

560class MultiProFitCoaddDeVFitTask(MultiProFitCoaddObjectFitTask): 

561 """MultiProFit single DeVaucouleurs model fit task.""" 

562 

563 ConfigClass = MultiProFitCoaddDeVFitConfig 

564 _DefaultName = "multiProFitCoaddDeVFit" 

565 

566 

567class CachedChainedModelInitializer(CachedBasicModelInitializer): 

568 def get_centroid_and_shape( 

569 self, 

570 source: Mapping[str, Any], 

571 catexps: list[CatalogExposureSourcesABC], 

572 config_data: CatalogSourceFitterConfigData, 

573 values_init: Mapping[g2f.ParameterD, float] | None = None, 

574 ) -> tuple[tuple[float, float], tuple[float, float, float]]: 

575 row_best = None 

576 chisq_red_min = math.inf 

577 for name, input_data in self.inputs.items(): 

578 data = input_data.data 

579 index_row = input_data.id_index.get(source["id"]) 

580 if index_row is not None: 

581 row = data[index_row] 

582 chisq_red = input_data.get_column("chisq_reduced", data=row) 

583 if chisq_red < chisq_red_min: 

584 row_best = (row, input_data) 

585 chisq_red_min = chisq_red 

586 if row_best is None: 

587 return super().get_centroid_and_shape( 

588 source=source, 

589 catexps=catexps, 

590 config_data=config_data, 

591 values_init=values_init, 

592 ) 

593 row_best, input_data = row_best 

594 cen_x, cen_y, reff_x, reff_y, rho = ( 

595 input_data.get_column(column, data=row_best) 

596 for column in ( 

597 input_data.get_column("cen_x").name, 

598 input_data.get_column("cen_y").name, 

599 input_data.get_column(f"{input_data.size_column}_x").name, 

600 input_data.get_column(f"{input_data.size_column}_y").name, 

601 input_data.get_column("rho").name, 

602 ) 

603 ) 

604 return (cen_x, cen_y), (reff_x, reff_y, rho) 

605 

606 

607class MakeCachedChainedInitializerAction(MakeBasicInitializerAction): 

608 def _make_initializer( 

609 self, 

610 catalog_multi: Sequence, 

611 catexps: list[CatalogExposureInputs], 

612 config_data: CatalogSourceFitterConfigData, 

613 ) -> ModelInitializer: 

614 sources, priors = config_data.sources_priors 

615 return CachedChainedModelInitializer(config=self.config, priors=priors, sources=sources) 

616 

617 

618class MultiProFitCoaddExpDeVFitConfig( 

619 MultiProFitCoaddObjectFitConfig, 

620 pipelineConnections=MultiProFitCoaddObjectFitConnections, 

621): 

622 """MultiProFit single Exponential+DeVaucouleurs model fit task config.""" 

623 

624 @classmethod 

625 def get_model_name_default(cls) -> str: 

626 return f"{model_names_default.exp}{model_names_default.deV}" 

627 

628 @classmethod 

629 def get_model_name_full(cls) -> str: 

630 return "Exponential + de Vaucouleurs" 

631 

632 def make_default_model_config(self) -> ModelConfig: 

633 config_group = ComponentGroupConfig( 

634 components_sersic={ 

635 component_names_default.exp: self.make_sersic_component(value_initial=1.0, fixed=True), 

636 component_names_default.deV: self.make_sersic_component(value_initial=4.0, fixed=True), 

637 }, 

638 ) 

639 return self.make_single_model_config(group=config_group) 

640 

641 def setDefaults(self): 

642 super().setDefaults() 

643 self.fit_coadd_multiband.action_initializer = MakeCachedChainedInitializerAction() 

644 self.fit_coadd_multiband.config_model = self.make_default_model_config() 

645 self.name_model = self.get_model_name_default() 

646 self.connections.name_table = self.name_model 

647 

648 size_priors = self.fit_coadd_multiband.size_priors 

649 size_priors[component_names_default.exp] = MagnitudeDependentSizePriorConfig( 

650 intercept_mag=23.3, 

651 slope_median_per_mag=-0.14, 

652 ) 

653 size_priors[component_names_default.deV] = MagnitudeDependentSizePriorConfig( 

654 intercept_mag=21.2, 

655 slope_median_per_mag=-0.14, 

656 ) 

657 

658 

659class MultiProFitCoaddExpDeVFitTask(MultiProFitCoaddObjectFitTask): 

660 """MultiProFit single ExpDeV model fit task.""" 

661 

662 ConfigClass = MultiProFitCoaddExpDeVFitConfig 

663 _DefaultName = "multiProFitCoaddExpDeVFit"