Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
77499a5
deleted unused methods in parametric.py
mcaceres2017 Feb 22, 2023
487966d
tree view created
mcaceres2017 Feb 22, 2023
a0ee6b5
SN_model created
mcaceres2017 Feb 22, 2023
5b9eccb
domain_methods created
mcaceres2017 Feb 22, 2023
92d7c05
changed try except block to if else
mcaceres2017 Feb 22, 2023
8adad88
methods "rename get fit" and "params to df" added
mcaceres2017 Feb 22, 2023
86fe90e
use_case defined
mcaceres2017 Feb 22, 2023
623de6c
controller and presenter done
mcaceres2017 Feb 22, 2023
0068ee8
input and response models defined
mcaceres2017 Feb 22, 2023
8824aaf
flask.py done
mcaceres2017 Feb 22, 2023
a3f5c88
created parametric_api file, refactoring finished
mcaceres2017 Feb 22, 2023
e43384d
upgraded dockerfile, web folder deleted
mcaceres2017 Feb 22, 2023
022a8e5
forgot to put (client,extractor) as args in funcs
mcaceres2017 Feb 22, 2023
b6478f8
tests fixed
mcaceres2017 Feb 22, 2023
5011785
change unittest.yml
mcaceres2017 Feb 22, 2023
6452bd3
unittest.yml updated
mcaceres2017 Feb 22, 2023
ef75615
Update unittests.yml
dirodriguezm Feb 22, 2023
9e61473
files formatted with black
mcaceres2017 Feb 22, 2023
d457720
Merge branch 'refactoring' of https://github.com/alercebroker/forecas…
mcaceres2017 Feb 22, 2023
155f62b
init files added
mcaceres2017 Feb 22, 2023
fa47ab0
parametric api fixed
mcaceres2017 Feb 22, 2023
9d1fb3c
parametric_api fixed, again
mcaceres2017 Feb 22, 2023
a90eafd
parametric api, toma 3
mcaceres2017 Feb 22, 2023
52fc532
tests fixed
mcaceres2017 Feb 22, 2023
8174f2d
minor fix
mcaceres2017 Feb 22, 2023
8f16ffe
probando
mcaceres2017 Feb 22, 2023
cb92e7d
tests mocks fixed
mcaceres2017 Feb 22, 2023
3399112
print flag for tests
mcaceres2017 Feb 22, 2023
84787c8
probando ideas
mcaceres2017 Feb 22, 2023
3e55594
api class self
mcaceres2017 Feb 22, 2023
aefd7f5
revision de parametros mock
mcaceres2017 Feb 22, 2023
09f16d3
intentando arreglar los tests
mcaceres2017 Feb 22, 2023
5fc4899
testing a model fix
mcaceres2017 Feb 23, 2023
fc5b71d
minor fix
mcaceres2017 Feb 23, 2023
d4ffd37
minor fix
mcaceres2017 Feb 23, 2023
fa2fe6a
debugging tests error 500
mcaceres2017 Feb 23, 2023
6ad6f54
refactoring done, tests finally working
mcaceres2017 Feb 23, 2023
e41060e
presenter.py deleted
mcaceres2017 Feb 23, 2023
bb9db21
minor fix
mcaceres2017 Feb 23, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .github/workflows/unittests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,20 @@ jobs:

steps:
- uses: actions/checkout@v2
- name: Set up Python 3.10
- name: Set up Python 3.10.6
uses: actions/setup-python@v2
with:
python-version: "3.10"
python-version: "3.10.6"
- name: Black Formatting
uses: psf/black@stable
with:
options: "--check --verbose"
src: "src/"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pytest pytest-mock Cython numpy
pip install -r requirements.txt
- name: Black Formatting
uses: psf/black@stable
with:
options: "--check --verbose"
src: "web/"
- name: Test with pytest
run: |
python -m pytest tests
4 changes: 1 addition & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,4 @@ __pycache__/
tests/tests.out
*.pyc
.vscode/
.coverage
htmlcov/
src
.coverage
6 changes: 3 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
FROM python:3.10
FROM python:3.10.6

ADD requirements.txt /app/
WORKDIR /app
RUN pip install --upgrade pip && pip install gunicorn==19.9.0
RUN pip install --upgrade pip && pip install gunicorn==20.1.0
RUN pip install Cython numpy
RUN pip install -r requirements.txt
COPY . /app
EXPOSE 8080


CMD ["gunicorn", "-t", "4", "--bind", "0.0.0.0", "web.app:app"]
CMD ["gunicorn", "-t", "4", "--bind", "0.0.0.0", "src.frameworks.flask:app"]
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
alerce
flask_restx
flask_cors
pytest-mock
File renamed without changes.
File renamed without changes.
24 changes: 24 additions & 0 deletions src/adapters/controller.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from src.use_cases.get_parametric_response import get
from src.domain.domain_methods import check_object, mjd_now
import numpy as np

from lc_classifier.features.extractors import SNParametricModelExtractor
from alerce.core import Alerce


client = Alerce()
extractor = SNParametricModelExtractor(bands=[1, 2])


def controller_parametric_response(parametric_parser):
args = parametric_parser.parse_args()
object = check_object(args.oid, client)
min_mjd = object["firstmjd"]
if not args.mjd:
forecast_mjd = np.array([mjd_now()])
else:
forecast_mjd = np.array(args.mjd)
shifted_mjd = forecast_mjd - min_mjd
parametric_response = get(args.oid, forecast_mjd, shifted_mjd, client, extractor)

return parametric_response
32 changes: 32 additions & 0 deletions src/domain/SN_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from numba import jit, types
import numpy as np


MODEL_PARAMS = [
"SPM_t0",
"SPM_chi",
"SPM_gamma",
"SPM_beta",
"SPM_A",
"SPM_tau_rise",
"SPM_tau_fall",
]


def flux_to_mag(flux):
return 16.4 - 2.5 * np.log10(flux)


@jit(nopython=True)
def model_inference(times, A, t0, gamma, f, t_rise, t_fall):
# f in this function is SPM_beta
beta = 1.0 / 3.0
t1 = t0 + gamma

sigmoid = 1.0 / (1.0 + np.exp(-beta * (times - t1)))
den = 1 + np.exp(-(times - t0) / t_rise)
flux = A * (1 - f) * np.exp(-(times - t1) / t_fall) / den * sigmoid + A * (
1.0 - f * (times - t0) / gamma
) / den * (1 - sigmoid)

return flux
Empty file added src/domain/__init__.py
Empty file.
91 changes: 91 additions & 0 deletions src/domain/domain_methods.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
from astropy.time import Time
import datetime
from alerce.exceptions import ObjectNotFoundError
from flask_restx import abort
from src.domain.SN_model import flux_to_mag, model_inference, MODEL_PARAMS


def check_object(oid, client):
try:
object = client.query_object(oid, format="pandas")
object = object.iloc[0]
return object
except ObjectNotFoundError:
return abort(404, "Not Found", errors="Object ID not found in ALeRCE database")


def mjd_now():
now_datetime = datetime.datetime.utcnow()
astro_time = Time(now_datetime)
return astro_time.mjd


def fit_parameters(oid, client, extractor):
detections = client.query_detections(oid, format="pandas")
detections["oid"] = oid
detections.set_index("oid", inplace=True)
params = extractor.compute_features(detections)
return params


def rename_and_get_fit(params):
fids = [int(i.rsplit("_", 1)[1]) for i in params.index]
params.index = [i.rsplit("_", 1)[0] for i in params.index]
return fids


def params_to_dataframe(params, fids):
params = params.to_frame()
params.reset_index(inplace=True)
# Setting new column names
params.columns = ["name", "value"]

# Adding fid
params["fid"] = fids
return params


def get_parameters(oid, client, extractor):
features = client.query_features(oid, format="pandas")
if len(features) > 0:
params = features[features.name.isin(MODEL_PARAMS)]
return True, params
else:
# Fitting model and getting params
params = fit_parameters(oid, client, extractor).iloc[0]

# Renaming index and getting fid
fids = rename_and_get_fit(params)

# Transforming to dataframe and resetting index
params = params_to_dataframe(params, fids)

return False, params


def infer(params, mjd):
flux_forecast = model_inference(
mjd,
params.SPM_A,
params.SPM_t0,
params.SPM_gamma,
params.SPM_beta,
params.SPM_tau_rise,
params.SPM_tau_fall,
)

magnitude_forecast = flux_to_mag(flux_forecast)
return magnitude_forecast


def get_features_message(features_on_db: bool):
message = "Forecast based on modified Villar et al. 2019. analytic model"
message += " (see [https://arxiv.org/abs/1905.07422] and [https://arxiv.org/abs/2008.03311]). "
if features_on_db:
message += "Using precomputed ALeRCE [http://alerce.science] parameters."
else:
message += (
"On-demand parameters computed in ALeRCE [http://alerce.science] API."
)
message += " Warning: This forecast was made with few points."
return message
Empty file added src/frameworks/__init__.py
Empty file.
4 changes: 3 additions & 1 deletion web/app.py → src/frameworks/flask.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@
from flask import Flask
from flask_restx import Api
from flask_cors import CORS
from src.frameworks.parametric_api import api as parametric_api

from .modules.parametric import api as parametric_api

app = Flask(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app, x_host=1, x_prefix=1)
CORS(app)

description = open("description.md")


api = Api(
app, version="1.0.1", title="ALeRCE Forecast API", description=description.read()
)
Expand Down
File renamed without changes.
19 changes: 19 additions & 0 deletions src/frameworks/parametric_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from flask_restx import Namespace, Resource
from src.adapters.controller import controller_parametric_response
from src.frameworks.input_model import parametric_parser
from src.frameworks.response_model import parametric_response, forecast_model

api = Namespace("parametric", description="Parametric Forecasts Module")
api.models[parametric_response.name] = parametric_response
api.models[forecast_model.name] = forecast_model


@api.route("/sn")
@api.response(200, "Success")
@api.response(404, "Not found")
@api.response(400, "Bad Request")
class SNParametricForecast(Resource):
@api.marshal_with(parametric_response)
@api.expect(parametric_parser)
def get(self):
return controller_parametric_response(parametric_parser)
File renamed without changes.
Empty file added src/use_cases/__init__.py
Empty file.
24 changes: 24 additions & 0 deletions src/use_cases/get_parametric_response.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from src.domain.domain_methods import get_parameters, get_features_message, infer
import numpy as np


def get(oid, forecast_mjd, shifted_mjd, client, extractor):
features_on_db, parameters = get_parameters(oid, client, extractor)
message = get_features_message(features_on_db)

forecasts = []
for fid in parameters.fid.unique():
fid_params = parameters[parameters.fid == fid]
fid_params.set_index("name", inplace=True)
fid_params = fid_params.value
magpsf = infer(fid_params, shifted_mjd)

forecasts.append(
{
"magpsf": magpsf.tolist(),
"mjd": forecast_mjd.tolist(),
"fid": int(fid),
}
)

return {"oid": oid, "forecast": forecasts, "comment": message}
12 changes: 6 additions & 6 deletions tests/parametric/test_sn.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import pytest
from web.app import app
from src.frameworks.flask import app

import pandas as pd
from alerce.exceptions import ObjectNotFoundError
Expand Down Expand Up @@ -32,11 +32,11 @@ def test_already_on_db(tester, mocker):
params = {"oid": "ZTF21aaqfrxz"}

mocker.patch(
"web.modules.parametric.parametric.SNParametricForecast.check_object",
"src.adapters.controller.check_object",
return_value={"firstmjd": 58000},
)
mocker.patch(
"web.modules.parametric.parametric.SNParametricForecast.get_parameters",
"src.use_cases.get_parametric_response.get_parameters",
return_value=(
True,
pd.DataFrame(
Expand All @@ -51,7 +51,6 @@ def test_already_on_db(tester, mocker):
),
),
)

response = tester.get(forecast_route, content_type="html/text", query_string=params)
assert response.status_code == 200
assert "precomputed" in response.data.decode("utf-8").lower()
Expand All @@ -61,11 +60,11 @@ def test_fit_parameters(tester, mocker):
params = {"oid": "ZTF21aaqfrxz"}

mocker.patch(
"web.modules.parametric.parametric.SNParametricForecast.check_object",
"src.adapters.controller.check_object",
return_value={"firstmjd": 58000},
)
mocker.patch(
"web.modules.parametric.parametric.SNParametricForecast.get_parameters",
"src.use_cases.get_parametric_response.get_parameters",
return_value=(
False,
pd.DataFrame(
Expand All @@ -80,6 +79,7 @@ def test_fit_parameters(tester, mocker):
),
),
)

response = tester.get(forecast_route, content_type="html/text", query_string=params)
assert response.status_code == 200
assert "demand" in response.data.decode("utf-8").lower()
1 change: 0 additions & 1 deletion web/modules/parametric/__init__.py

This file was deleted.

Loading