コード例 #1
0
ファイル: nodes.py プロジェクト: LSSTDESC/SN-PWV
    def __init__(
            self,
            sn_model: SNModel,
            catalog: VariableCatalog = None,
            num_processes: int = 1,
            add_scatter: bool = True,
            fixed_snr: Optional[float] = None,
            abs_mb: float = const.betoule_abs_mb,
            cosmo: Cosmology = const.betoule_cosmo
    ) -> None:
        """Fit light-curves using multiple processes and combine results into an output file

        Args:
            sn_model: Model to use when simulating light-curves
            catalog: Optional reference start catalog to calibrate simulated flux values to
            num_processes: Number of processes to allocate to the node
            abs_mb: The absolute B-band magnitude of the simulated SNe
            cosmo: Cosmology to assume in the simulation
        """

        self.sim_model = copy(sn_model)
        self.catalog = catalog
        self.add_scatter = add_scatter
        self.fixed_snr = fixed_snr
        self.abs_mb = abs_mb
        self.cosmo = cosmo

        # Node connectors
        self.input = Input('Simulated Cadence')
        self.success_output = Output('Simulation Success')
        self.failure_output = Output('Simulation Failure')
        super().__init__(num_processes=num_processes)
コード例 #2
0
ファイル: nodes.py プロジェクト: LSSTDESC/SN-PWV
    def __init__(
            self, plasticc_dao: PLAsTICC, iter_lim: int = float('inf'), override_zp: float = 30, num_processes: int = 1
    ) -> None:
        """Source node for loading PLAsTICC cadence data from disk

        This node can only be run using a single process. This can be the main
        process (``num_processes=0``) or a single forked process (``num_processes=1``.)

        Args:
            plasticc_dao: A PLAsTICC data access object
            iter_lim: Exit after loading the given number of light-curves
            override_zp: Overwrite the zero-point used by plasticc with this number
            num_processes: Number of processes to allocate to the node (must be 0 or 1 for this node)
        """

        if num_processes not in (0, 1):
            raise RuntimeError('Number of processes for ``LoadPlasticcCadence`` must be 0 or 1.')

        self.cadence = plasticc_dao
        self.iter_lim = iter_lim
        self.override_zp = override_zp

        # Node connectors
        self.output = Output('Loading Cadence Output')
        super().__init__(num_processes=num_processes)
コード例 #3
0
    def setUp(self) -> None:
        """Connect two outputs to a single input"""

        self.input = Input()
        self.output1 = Output()
        self.output2 = Output()

        self.output1.connect(self.input)
        self.output2.connect(self.input)
コード例 #4
0
ファイル: mock.py プロジェクト: mwvgroup/Egon
class MockNode(MockObject, nodes.Node):
    """A ``Node`` subclass that implements placeholder functions for abstract methods"""
    def __init__(self, name: Optional[str] = None) -> None:
        self.output = Output()
        self.input = Input()
        super().__init__(name)

    def action(self) -> None:  # pragma: no cover
        """Placeholder function to satisfy requirements of abstract parent"""

        for x in self.input.iter_get():
            self.output.put(x)
コード例 #5
0
ファイル: mock.py プロジェクト: mwvgroup/Egon
class MockSource(MockObject, nodes.Source):
    """A ``Source`` subclass that implements placeholder functions for abstract methods"""
    def __init__(self,
                 load_data: list = None,
                 name: Optional[str] = None) -> None:
        self.output = Output()
        self.load_data = load_data or []
        super().__init__(name)

    def action(self) -> None:
        """Placeholder function to satisfy requirements of abstract parent"""

        for x in self.load_data:
            self.output.put(x)
コード例 #6
0
ファイル: test_node_validation.py プロジェクト: mwvgroup/Egon
    def test_error_if_malformed(self) -> None:
        """Test a malformed error is raised by the ``validate`` method"""

        self.test_class.input = Input()
        self.test_class.output = Output()
        with self.assertRaises(self.malformed_exception):
            self.test_class.validate()
コード例 #7
0
ファイル: nodes.py プロジェクト: LSSTDESC/SN-PWV
    def __init__(
            self, sn_model: SNModel, vparams: List[str], bounds: Dict = None, num_processes: int = 1
    ) -> None:
        """Fit light-curves using multiple processes and combine results into an output file

        Args:
            sn_model: Model to use when fitting light-curves
            vparams: List of parameter names to vary in the fit
            bounds: Bounds to impose on ``fit_model`` parameters when fitting light-curves
            num_processes: Number of processes to allocate to the node
        """

        self.sn_model = sn_model
        self.vparams = vparams
        self.bounds = bounds

        # Node Connectors
        self.input = Input('Simulated Light-Curve')
        self.success_output = Output('Fitting Success')
        self.failure_output = Output('Fitting Failure')
        super(FitLightCurves, self).__init__(num_processes=num_processes)
コード例 #8
0
ファイル: nodes.py プロジェクト: LSSTDESC/SN-PWV
class LoadPlasticcCadence(Source):
    """Pipeline node for loading PLAsTICC cadence data from disk

    Connectors:
        output: Emits a pipeline packet decorated with the snid, simulation parameters, and cadence
    """

    def __init__(
            self, plasticc_dao: PLAsTICC, iter_lim: int = float('inf'), override_zp: float = 30, num_processes: int = 1
    ) -> None:
        """Source node for loading PLAsTICC cadence data from disk

        This node can only be run using a single process. This can be the main
        process (``num_processes=0``) or a single forked process (``num_processes=1``.)

        Args:
            plasticc_dao: A PLAsTICC data access object
            iter_lim: Exit after loading the given number of light-curves
            override_zp: Overwrite the zero-point used by plasticc with this number
            num_processes: Number of processes to allocate to the node (must be 0 or 1 for this node)
        """

        if num_processes not in (0, 1):
            raise RuntimeError('Number of processes for ``LoadPlasticcCadence`` must be 0 or 1.')

        self.cadence = plasticc_dao
        self.iter_lim = iter_lim
        self.override_zp = override_zp

        # Node connectors
        self.output = Output('Loading Cadence Output')
        super().__init__(num_processes=num_processes)

    def action(self) -> None:
        """Load PLAsTICC cadence data from disk"""

        for snid, params, cadence in self.cadence.iter_cadence(iter_lim=self.iter_lim):
            cadence.zp = np.full_like(cadence.zp, self.override_zp)
            self.output.put(PipelinePacket(snid, params, cadence))
コード例 #9
0
class MultiplePartnerMapping(TestCase):
    """Test connectors with an established connection correctly map to neighboring connectors/nodes"""
    def setUp(self) -> None:
        """Connect two outputs to a single input"""

        self.input = Input()
        self.output1 = Output()
        self.output2 = Output()

        self.output1.connect(self.input)
        self.output2.connect(self.input)

    def test_output_maps_to_partners(self) -> None:
        """Test connectors map to the correct partner connector"""

        output_connectors = [self.output1, self.output2]
        self.assertCountEqual(output_connectors, self.input.partners)

    def test_input_maps_to_partners(self) -> None:
        """Test connectors map to the correct partner connector"""

        input_connectors = [self.input]
        self.assertCountEqual(input_connectors, self.output1.partners)
        self.assertCountEqual(input_connectors, self.output2.partners)
コード例 #10
0
ファイル: test_output.py プロジェクト: mwvgroup/Egon
    def test_stores_value_in_queue(self) -> None:
        """Test the ``put`` method puts data into the underlying connected queue"""

        # Create a node with an output connector
        output = Output()
        input = Input()
        output.connect(input)

        test_val = 'test_val'
        output.put(test_val)
        self.assertEqual(input._queue.get(), test_val)
コード例 #11
0
ファイル: test_output.py プロジェクト: mwvgroup/Egon
class InstanceConnect(TestCase):
    """Test the connection of generic connector objects to other"""
    def setUp(self) -> None:

        self.input_connector = Input()
        self.output_connector = Output()

    def test_error_on_connection_to_same_type(self) -> None:
        """Test an error is raised when connecting two outputs together"""

        with self.assertRaises(ValueError):
            self.output_connector.connect(Output())

    def test_overwrite_error_on_connection_overwrite(self) -> None:
        """Test an error is raised when trying to overwrite an existing connection"""

        input = Input()
        self.output_connector.connect(input)
        with self.assertRaises(exceptions.OverwriteConnectionError):
            self.output_connector.connect(input)
コード例 #12
0
ファイル: test_output.py プロジェクト: mwvgroup/Egon
class InstanceDisconnect(TestCase):
    """Test the disconnection of two connectors"""
    def setUp(self) -> None:
        self.input = Input()
        self.output = Output()
        self.output.connect(self.input)

    def test_both_connectors_are_disconnected(self) -> None:
        """Test both connectors are no longer listed as partners"""

        self.assertTrue(self.input.is_connected())
        self.assertTrue(self.output.is_connected())

        self.output.disconnect(self.input)
        self.assertNotIn(self.output, self.input.partners)
        self.assertFalse(self.input.is_connected())
        self.assertFalse(self.output.is_connected())

    def test_error_if_not_connected(self) -> None:
        """Test an error is raised when disconnecting a connector that is not connected"""

        with self.assertRaises(MissingConnectionError):
            Output().disconnect(Input())
コード例 #13
0
ファイル: test_output.py プロジェクト: mwvgroup/Egon
    def test_error_on_connection_to_same_type(self) -> None:
        """Test an error is raised when connecting two outputs together"""

        with self.assertRaises(ValueError):
            self.output_connector.connect(Output())
コード例 #14
0
ファイル: test_output.py プロジェクト: mwvgroup/Egon
    def setUp(self) -> None:

        self.input_connector = Input()
        self.output_connector = Output()
コード例 #15
0
ファイル: test_output.py プロジェクト: mwvgroup/Egon
    def test_error_override() -> None:
        """Test the optional suppression of errors for unconnected outputs"""

        Output().put(5, raise_missing_connection=False)
コード例 #16
0
ファイル: test_output.py プロジェクト: mwvgroup/Egon
    def test_error_if_unconnected(self) -> None:
        """Test ``put`` raises an error if the output is not connected"""

        with self.assertRaises(MissingConnectionError):
            Output().put(5)
コード例 #17
0
ファイル: nodes.py プロジェクト: LSSTDESC/SN-PWV
class SimulateLightCurves(Node):
    """Pipeline node for simulating light-curves based on PLAsTICC cadences

    Connectors:
        input: A Pipeline Packet
        success_output: Emits pipeline packets successfully decorated with a simulated light-curve
        failure_output: Emits pipeline packets for cases where the simulation procedure failed
    """

    def __init__(
            self,
            sn_model: SNModel,
            catalog: VariableCatalog = None,
            num_processes: int = 1,
            add_scatter: bool = True,
            fixed_snr: Optional[float] = None,
            abs_mb: float = const.betoule_abs_mb,
            cosmo: Cosmology = const.betoule_cosmo
    ) -> None:
        """Fit light-curves using multiple processes and combine results into an output file

        Args:
            sn_model: Model to use when simulating light-curves
            catalog: Optional reference start catalog to calibrate simulated flux values to
            num_processes: Number of processes to allocate to the node
            abs_mb: The absolute B-band magnitude of the simulated SNe
            cosmo: Cosmology to assume in the simulation
        """

        self.sim_model = copy(sn_model)
        self.catalog = catalog
        self.add_scatter = add_scatter
        self.fixed_snr = fixed_snr
        self.abs_mb = abs_mb
        self.cosmo = cosmo

        # Node connectors
        self.input = Input('Simulated Cadence')
        self.success_output = Output('Simulation Success')
        self.failure_output = Output('Simulation Failure')
        super().__init__(num_processes=num_processes)

    def simulate_lc(self, params: Dict[str, float], cadence: ObservedCadence) -> LightCurve:
        """Duplicate a plastic light-curve using the simulation model

        Args:
            params: The simulation parameters to use with ``self.model``
            cadence: The observed cadence of the returned light-curve
        """

        # Set model parameters and scale the source brightness to the desired intrinsic brightness
        model_for_sim = copy(self.sim_model)
        model_for_sim.update({p: v for p, v in params.items() if p in model_for_sim.param_names})
        model_for_sim.set_source_peakabsmag(self.abs_mb, 'standard::b', 'AB', cosmo=self.cosmo)

        # Simulate the light-curve. Make sure to include model parameters as meta data
        duplicated = model_for_sim.simulate_lc(cadence, scatter=self.add_scatter, fixed_snr=self.fixed_snr)

        # Rescale the light-curve using the reference star catalog if provided
        if self.catalog is not None:
            duplicated = self.catalog.calibrate_lc(duplicated, ra=params['ra'], dec=params['dec'])

        return duplicated

    def action(self) -> None:
        """Simulate light-curves with atmospheric effects"""

        for packet in self.input.iter_get():
            try:
                packet.light_curve = self.simulate_lc(
                    packet.sim_params, packet.cadence
                )

            except Exception as excep:
                packet.message = f'{self.__class__.__name__}: {repr(excep)}'
                self.failure_output.put(packet)

            else:
                self.success_output.put(packet)
コード例 #18
0
ファイル: mock.py プロジェクト: mwvgroup/Egon
 def __init__(self,
              load_data: list = None,
              name: Optional[str] = None) -> None:
     self.output = Output()
     self.load_data = load_data or []
     super().__init__(name)
コード例 #19
0
ファイル: test_output.py プロジェクト: mwvgroup/Egon
 def setUp(self) -> None:
     self.input = Input()
     self.output = Output()
     self.output.connect(self.input)
コード例 #20
0
ファイル: mock.py プロジェクト: mwvgroup/Egon
 def __init__(self, name: Optional[str] = None) -> None:
     self.output = Output()
     self.input = Input()
     super().__init__(name)
コード例 #21
0
ファイル: test_output.py プロジェクト: mwvgroup/Egon
    def test_error_if_not_connected(self) -> None:
        """Test an error is raised when disconnecting a connector that is not connected"""

        with self.assertRaises(MissingConnectionError):
            Output().disconnect(Input())
コード例 #22
0
ファイル: nodes.py プロジェクト: LSSTDESC/SN-PWV
class FitLightCurves(Node):
    """Pipeline node for fitting simulated light-curves

    Connectors:
        input: A Pipeline Packet
        success_output: Emits pipeline packets with successful fit results
        failure_output: Emits pipeline packets for cases where the fitting procedure failed
    """

    def __init__(
            self, sn_model: SNModel, vparams: List[str], bounds: Dict = None, num_processes: int = 1
    ) -> None:
        """Fit light-curves using multiple processes and combine results into an output file

        Args:
            sn_model: Model to use when fitting light-curves
            vparams: List of parameter names to vary in the fit
            bounds: Bounds to impose on ``fit_model`` parameters when fitting light-curves
            num_processes: Number of processes to allocate to the node
        """

        self.sn_model = sn_model
        self.vparams = vparams
        self.bounds = bounds

        # Node Connectors
        self.input = Input('Simulated Light-Curve')
        self.success_output = Output('Fitting Success')
        self.failure_output = Output('Fitting Failure')
        super(FitLightCurves, self).__init__(num_processes=num_processes)

    def fit_lc(self, light_curve: LightCurve, initial_guess: Dict[str, float]) -> Tuple[SNFitResult, SNModel]:
        """Fit the given light-curve

        Args:
            light_curve: The light-curve to fit
            initial_guess: Parameters to use as the initial guess in the chi-squared minimization

        Returns:
            - The optimization result
            - A copy of the model with parameter values set to minimize the chi-square
        """

        # Use the true light-curve parameters as the initial guess
        model = copy(self.sn_model)
        model.update({k: v for k, v in initial_guess.items() if k in self.sn_model.param_names})

        return model.fit_lc(
            light_curve, self.vparams, bounds=self.bounds,
            guess_t0=False, guess_amplitude=False, guess_z=False)

    def action(self) -> None:
        """Fit light-curves"""

        for packet in self.input.iter_get():
            try:
                packet.fit_result, packet.fitted_model = self.fit_lc(packet.light_curve, packet.sim_params)
                packet.covariance = packet.fit_result.salt_covariance_linear()

            except Exception as excep:
                packet.message = f'{self.__class__.__name__}: {repr(excep)}'
                self.failure_output.put(packet)

            else:
                packet.message = f'{self.__class__.__name__}: {packet.fit_result.message}'
                self.success_output.put(packet)