pmelchior / scarlet2

Scarlet, all new and shiny
MIT License
15 stars 4 forks source link

Combined sources #44

Closed pmelchior closed 7 months ago

pmelchior commented 7 months ago

This PR brings sources with more than one component. The idea is that a source gets a new attribute: components, which behave like sources themselves. These can be added or multiplied to the existing source, e.g. a bulge component

source = Source(center, spectrum, morphology)
bulge = Component(center, bulge_spectrum, bulge_morphology)
source += bulge

or a dust component

source = Source(center, spectrum, morphology)
dust = DustComponent(center, dust_spectrum, dust_morphology)
source *= dust

The difference between Source and Component is as follows:

  1. A Source is a Component
  2. A Source can have additional Component or Source instances, that are added/multiplied on top of itself in the order they have been pushed onto the components list
  3. A Scene only registers Sources: as the name implies, sources shine, while components themselves do not.

Item 1 states that the modeling implementation rests with Component. This is why we have a DustComponent because it needs a __call__ that returns $\exp(-\mathrm{spectrum}\times\mathrm{morphology})$.

Item 2 states that you can also add sources to sources to make them fully hierarchical. This might be good for organizing sources, but it's critical if we want different pieces of a galaxy to have different dust attenuation.

Item 3 prevents nonsensical behavior, e.g. to have a DustComponent without its base Source (it can't attenuate if it doesn't get illuminated) or to evaluate a Component twice, namely on its own and then as component of a source.

SampsonML commented 7 months ago

I think something in module.py needs to be altered to handle the multi-somponent sources in a tuple here:

Screenshot 2024-03-24 at 10 40 42 AM

This could be user error on my part I specifically want a prior on both components, run code is here:

# run the fitting code
with Scene(model_frame) as scene:
    for center in centers:
        # initialize the spctrum and morphology with Scarlet2
        init_spec = initialization.init_spectrum(obs, center)
        init_morph = initialization.init_morphology(obs, center, components=2)

        # check if multicomponent
        if isinstance(init_morph, list):
            primary_morph = init_morph[0]
            secondary_morph = init_morph[1]
            multi = True
        else:
            multi - False

        # construct the source
        if multi:
            # add primary component
            source = Source(
                center,
                ArraySpectrum(
                    Parameter(init_spec, constraint=constraints.positive, stepsize=1e-2)
                ),
                ArrayMorphology(Parameter(primary_morph, prior=prior, stepsize=5e-3)),
            )

            # add secondary component
            secondary = Component(
                center,
                ArraySpectrum(
                    Parameter(init_spec, constraint=constraints.positive, stepsize=1e-2)
                ),
                ArrayMorphology(Parameter(secondary_morph, prior=prior, stepsize=5e-3)),
            )

            source += secondary

        # if just a single component
        else:
            source = Source(
                center,
                ArraySpectrum(
                    Parameter(init_spec, constraint=constraints.positive, stepsize=1e-2)
                ),
                ArrayMorphology(Parameter(init_morph, prior=prior, stepsize=5e-3)),
            )

scene_ = scene.fit(obs, max_iter=200, e_rel=1e-4)
SampsonML commented 7 months ago

The source which is causing the issues:

source_pic
pmelchior commented 7 months ago

I can't see what's causing the failure here. I tested with two components and it worked. The only thing I noticed is this mistake:

else:
    multi - False

This must be multi = False.

pmelchior commented 7 months ago

@SampsonML check now if the problem still persists.

SampsonML commented 7 months ago

Great, works a charm now.