__init__.py 25.3 KB
Newer Older
Yannick Roehlly's avatar
Yannick Roehlly committed
1
# -*- coding: utf-8 -*-
2 3
# Copyright (C) 2012, 2013 Centre de données Astrophysiques de Marseille
# Licensed under the CeCILL-v2 licence - see Licence_CeCILL_V2-en.txt
Yannick Roehlly's avatar
Yannick Roehlly committed
4
# Author: Yannick Roehlly
Yannick Roehlly's avatar
Yannick Roehlly committed
5

6
"""
Yannick Roehlly's avatar
Yannick Roehlly committed
7 8 9 10 11 12 13 14 15 16 17 18 19
This is the database where we store some data used by pcigale:
 - the information relative to the filters
 - the single stellar populations as defined in Marason (2005)
 - the infra-red templates from Dale and Helou (2002)

The classes for these various objects are described in pcigale.data
sub-packages. The corresponding underscored classes here are used by the
SqlAlchemy ORM to store the data in a unique SQLite3 database.

"""

import pkg_resources
from sqlalchemy import (create_engine, exc, Column, String, Text,
20
                        Float, Integer, PickleType)
Yannick Roehlly's avatar
Yannick Roehlly committed
21
from sqlalchemy.ext.declarative import declarative_base
22 23
from sqlalchemy.orm import class_mapper, sessionmaker
import numpy as np
Yannick Roehlly's avatar
Yannick Roehlly committed
24
from .filters import Filter
25 26 27 28 29 30 31
from .m2005 import M2005
from .bc03 import BC03
from .dh2002 import DH2002
from .dale2014 import Dale2014
from .dl2007 import DL2007
from .fritz2006 import Fritz2006
from .nebular_continuum import NebularContinuum
32
from .nebular_lines import NebularLines
Yannick Roehlly's avatar
Yannick Roehlly committed
33 34 35 36 37 38 39 40 41


DATABASE_FILE = pkg_resources.resource_filename(__name__, 'data.db')

ENGINE = create_engine('sqlite:///' + DATABASE_FILE, echo=False)
BASE = declarative_base()
SESSION = sessionmaker(bind=ENGINE)


42 43 44 45 46 47 48 49 50 51 52 53 54 55
class DatabaseLookupError(Exception):
    """
    A custom exception raised when a search in the database does not find a
    result.
    """


class DatabaseInsertError(Exception):
    """
    A custom exception raised when one tries to insert in the database
    something that is already in it.
    """


Yannick Roehlly's avatar
Yannick Roehlly committed
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
class _Filter(BASE):
    """ Storage for filters
    """

    __tablename__ = 'filters'

    name = Column(String, primary_key=True)
    description = Column(String)
    trans_type = Column(String)
    trans_table = Column(PickleType)
    effective_wavelength = Column(Float)

    def __init__(self, f):
        self.name = f.name
        self.description = f.description
        self.trans_type = f.trans_type
        self.trans_table = f.trans_table
        self.effective_wavelength = f.effective_wavelength


76
class _M2005(BASE):
Yannick Roehlly's avatar
Yannick Roehlly committed
77 78 79 80 81 82 83
    """Storage for Maraston 2005 SSP
    """

    __tablename__ = 'maraston2005'

    imf = Column(String, primary_key=True)
    metallicity = Column(Float, primary_key=True)
Yannick Roehlly's avatar
Yannick Roehlly committed
84
    time_grid = Column(PickleType)
Yannick Roehlly's avatar
Yannick Roehlly committed
85 86 87 88 89 90 91
    wavelength_grid = Column(PickleType)
    mass_table = Column(PickleType)
    spec_table = Column(PickleType)

    def __init__(self, ssp):
        self.imf = ssp.imf
        self.metallicity = ssp.metallicity
Yannick Roehlly's avatar
Yannick Roehlly committed
92
        self.time_grid = ssp.time_grid
Yannick Roehlly's avatar
Yannick Roehlly committed
93 94 95 96 97
        self.wavelength_grid = ssp.wavelength_grid
        self.mass_table = ssp.mass_table
        self.spec_table = ssp.spec_table


98
class _BC03(BASE):
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
    """Storage for Bruzual and Charlot 2003 SSP
    """

    __tablename__ = "bc03"

    imf = Column(String, primary_key=True)
    metallicity = Column(Float, primary_key=True)
    time_grid = Column(PickleType)
    wavelength_grid = Column(PickleType)
    color_table = Column(PickleType)
    lumin_table = Column(PickleType)

    def __init__(self, ssp):
        self.imf = ssp.imf
        self.metallicity = ssp.metallicity
        self.time_grid = ssp.time_grid
        self.wavelength_grid = ssp.wavelength_grid
        self.color_table = ssp.color_table
        self.lumin_table = ssp.lumin_table


120
class _DH2002(BASE):
Yannick Roehlly's avatar
Yannick Roehlly committed
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
    """Storage for Dale and Helou (2002) infra-red templates

    The Dale and Helou (2002) template are gathered in a unique numpy array,
    nevertheless, they are stored in their own table with a unique row.

    """

    __tablename__ = 'dh2002_templates'

    name = Column(String, primary_key=True)
    description = Column(Text)
    data = Column(PickleType)

    def __init__(self, name, description, data):
        self.name = name
        self.description = description
        self.data = data

139 140

class _Dale2014(BASE):
141 142 143 144 145 146 147 148 149 150 151 152 153 154
    """Storage for Dale et al (2014) infra-red templates
    """

    __tablename__ = 'dale2014_templates'
    fracAGN = Column(Float, primary_key=True)
    alpha = Column(String, primary_key=True)
    wave = Column(PickleType)
    lumin = Column(PickleType)

    def __init__(self, iragn):
        self.fracAGN = iragn.fracAGN
        self.alpha = iragn.alpha
        self.wave = iragn.wave
        self.lumin = iragn.lumin
Yannick Roehlly's avatar
Yannick Roehlly committed
155

156

157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
class _DL2007(BASE):
    """Storage for Draine and Li (2007) IR models
    """

    __tablename__ = 'DL2007_models'
    qpah = Column(Float, primary_key=True)
    umin = Column(Float, primary_key=True)
    umax = Column(Float, primary_key=True)
    wave = Column(PickleType)
    lumin = Column(PickleType)

    def __init__(self, model):
        self.qpah = model.qpah
        self.umin = model.umin
        self.umax = model.umax
        self.wave = model.wave
        self.lumin = model.lumin


176
class _Fritz2006(BASE):
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
    """Storage for Fritz et al. (2006) models
    """

    __tablename__ = 'fritz2006_agn'
    model_nb = Column(Integer, primary_key=True)
    agn_type = Column(Integer)
    r_ratio = Column(Float)
    tau = Column(Float)
    beta = Column(Float)
    gamma = Column(Float)
    theta = Column(Float)
    psy = Column(Float)
    wave = Column(PickleType)
    luminosity = Column(PickleType)

    def __init__(self, agn):
        self.model_nb = agn.model_nb
        self.agn_type = agn.agn_type
        self.r_ratio = agn.r_ratio
        self.tau = agn.tau
        self.beta = agn.beta
        self.gamma = agn.gamma
        self.theta = agn.theta
        self.psy = agn.psy
        self.wave = agn.wave
        self.luminosity = agn.luminosity


205
class _NebularLines(BASE):
206 207
    """Storage for line templates
    """
208 209

    __tablename__ = 'nebular_lines'
210 211 212 213
    metallicity = Column(Float, primary_key=True)
    logU = Column(Float, primary_key=True)
    wave = Column(PickleType)
    ratio = Column(PickleType)
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236

    def __init__(self, nebular_lines):
        self.metallicity = nebular_lines.metallicity
        self.logU = nebular_lines.logU
        self.wave = nebular_lines.wave
        self.ratio = nebular_lines.ratio


class _NebularContinuum(BASE):
    """Storage for nebular continuum templates
    """

    __tablename__ = 'nebular_continuum'
    metallicity = Column(Float, primary_key=True)
    logU = Column(Float, primary_key=True)
    wave = Column(PickleType)
    lumin = Column(PickleType)

    def __init__(self, nebular_continuum):
        self.metallicity = nebular_continuum.metallicity
        self.logU = nebular_continuum.logU
        self.wave = nebular_continuum.wave
        self.lumin = nebular_continuum.lumin
237 238


Yannick Roehlly's avatar
Yannick Roehlly committed
239 240 241 242 243 244 245
class Database(object):
    """Object giving access to pcigale database."""

    def __init__(self, writable=False):
        """
        Create a collection giving access to access the pcigale database.

Yannick Roehlly's avatar
Yannick Roehlly committed
246
        Parameters
Yannick Roehlly's avatar
Yannick Roehlly committed
247 248 249 250 251 252 253 254 255
        ----------
        writable : boolean
            If True the user will be able to write new data in the database
            (but he/she must have a writable access to the sqlite file). By
            default, False.
        """
        self.session = SESSION()
        self.is_writable = writable

256 257 258 259 260 261
    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.close()

Yannick Roehlly's avatar
Yannick Roehlly committed
262 263 264 265 266 267
    def upgrade_base(self):
        """ Upgrade the table schemas in the database
        """
        if self.is_writable:
            BASE.metadata.create_all(ENGINE)
        else:
268
            raise Exception('The database is not writable.')
Yannick Roehlly's avatar
Yannick Roehlly committed
269 270 271 272 273 274 275 276 277 278 279 280 281

    def close(self):
        """ Close the connection to the database

        TODO: It would be better to wrap the database use inside a context
        manager.
        """
        self.session.close_all()

    def add_filter(self, pcigale_filter):
        """
        Add a filter to pcigale database.

Yannick Roehlly's avatar
Yannick Roehlly committed
282
        Parameters
Yannick Roehlly's avatar
Yannick Roehlly committed
283 284 285 286 287 288 289 290 291
        ----------
        pcigale_filter : pcigale.data.Filter
        """
        if self.is_writable:
            self.session.add(_Filter(pcigale_filter))
            try:
                self.session.commit()
            except exc.IntegrityError:
                self.session.rollback()
292
                raise DatabaseInsertError('The filter is already in the base.')
Yannick Roehlly's avatar
Yannick Roehlly committed
293
        else:
294
            raise Exception('The database is not writable.')
Yannick Roehlly's avatar
Yannick Roehlly committed
295

296
    def add_m2005(self, ssp_m2005):
Yannick Roehlly's avatar
Yannick Roehlly committed
297 298 299
        """
        Add a Maraston 2005 SSP to pcigale database

Yannick Roehlly's avatar
Yannick Roehlly committed
300
        Parameters
Yannick Roehlly's avatar
Yannick Roehlly committed
301
        ----------
302
        ssp : pcigale.base.M2005
Yannick Roehlly's avatar
Yannick Roehlly committed
303 304 305

        """
        if self.is_writable:
306
            ssp = _M2005(ssp_m2005)
Yannick Roehlly's avatar
Yannick Roehlly committed
307 308 309 310 311
            self.session.add(ssp)
            try:
                self.session.commit()
            except exc.IntegrityError:
                self.session.rollback()
312
                raise DatabaseInsertError('The SSP is already in the base.')
Yannick Roehlly's avatar
Yannick Roehlly committed
313
        else:
314
            raise Exception('The database is not writable.')
Yannick Roehlly's avatar
Yannick Roehlly committed
315

316
    def add_bc03(self, ssp_bc03):
317 318 319 320 321 322 323 324 325
        """
        Add a Bruzual and Charlot 2003 SSP to pcigale database

        Parameters
        ----------
        ssp : pcigale.data.SspBC03

        """
        if self.is_writable:
326
            ssp = _BC03(ssp_bc03)
327 328 329 330 331
            self.session.add(ssp)
            try:
                self.session.commit()
            except exc.IntegrityError:
                self.session.rollback()
332
                raise DatabaseInsertError('The SSP is already in the base.')
333
        else:
334
            raise Exception('The database is not writable.')
335

336
    def add_dh2002(self, data):
Yannick Roehlly's avatar
Yannick Roehlly committed
337 338 339
        """
        Add Dale and Helou (2002) templates the collection.

Yannick Roehlly's avatar
Yannick Roehlly committed
340
        Parameters
Yannick Roehlly's avatar
Yannick Roehlly committed
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
        ----------
        data : array
            Array containing the templates data.

        """
        name = 'dh2002'

        description = ("These are the Dale & Helou (2002) infra-red "
                       "templates to which the stellar emission was "
                       "subtracted (Nohl et al., 2009). The data is a "
                       "tuple composed of the alpha grid, the lambda grid "
                       "and a 2D array of luminosity density (normalised "
                       "over the full spectrum) with the alpha in the first "
                       "axis and the lambda in the second.")

        if self.is_writable:
357
            template = _DH2002(name, description, data)
Yannick Roehlly's avatar
Yannick Roehlly committed
358 359 360 361 362
            self.session.add(template)
            try:
                self.session.commit()
            except exc.IntegrityError:
                self.session.rollback()
363 364
                raise DatabaseInsertError(
                    'The template is already in the base.')
Yannick Roehlly's avatar
Yannick Roehlly committed
365
        else:
366
            raise Exception('The database is not writable.')
367

368 369 370 371 372 373
    def add_dale2014(self, iragn):
        """
        Add Dale et al (2014) templates the collection.

        Parameters
        ----------
374
        iragn : pcigale.data.Dale2014
375 376 377 378

        """

        if self.is_writable:
379
            template = _Dale2014(iragn)
380 381 382 383 384
            self.session.add(template)
            try:
                self.session.commit()
            except exc.IntegrityError:
                self.session.rollback()
385
                raise DatabaseInsertError(
386
                    'The Dale2014 template is already in the base.')
387
        else:
388
            raise Exception('The database is not writable.')
Yannick Roehlly's avatar
Yannick Roehlly committed
389

390 391
    def add_dl2007(self, model):
        """
Yannick Roehlly's avatar
Yannick Roehlly committed
392
        Add a Draine and Li (2007) model to the database.
393 394 395 396 397 398 399 400 401 402 403 404

        Parameters
        ----------
        model: pcigale.data.DL2007

        """
        if self.is_writable:
            self.session.add(_DL2007(model))
            try:
                self.session.commit()
            except exc.IntegrityError:
                self.session.rollback()
405 406
                raise DatabaseInsertError(
                    'The DL07 model is already in the base.')
407
        else:
408
            raise Exception('The database is not writable.')
409

410
    def add_fritz2006(self, agn):
411 412 413 414 415
        """
        Add a Fritz et al. (2006) AGN model to the database.

        Parameters
        ----------
416
        agn : pcigale.data.Fritz2006
417 418 419

        """
        if self.is_writable:
420
            self.session.add(_Fritz2006(agn))
421 422 423 424
            try:
                self.session.commit()
            except exc.IntegrityError:
                self.session.rollback()
425 426
                raise DatabaseInsertError(
                    'The agn model is already in the base.')
427
        else:
428
            raise Exception('The database is not writable.')
429

430
    def add_nebular_lines(self, nebular_lines):
431 432 433 434
        """
        Add ultraviolet and optical line templates to the database.
        """
        if self.is_writable:
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
            self.session.add(_NebularLines(nebular_lines))
            try:
                self.session.commit()
            except exc.IntegrityError:
                self.session.rollback()
                raise Exception('The line is already in the base')
        else:
            raise Exception('The database is not writable')

    def add_nebular_continuum(self, nebular_continuum):
        """
        Add nebular continuum templates to the database.
        """
        if self.is_writable:
            self.session.add(_NebularContinuum(nebular_continuum))
450 451 452 453
            try:
                self.session.commit()
            except exc.IntegrityError:
                self.session.rollback()
454 455
                raise Exception('The continuum template is already in the '
                                'base')
456
        else:
457
            raise Exception('The database is not writable')
458

Yannick Roehlly's avatar
Yannick Roehlly committed
459 460 461 462
    def get_filter(self, name):
        """
        Get a specific filter from the collection

Yannick Roehlly's avatar
Yannick Roehlly committed
463
        Parameters
Yannick Roehlly's avatar
Yannick Roehlly committed
464 465 466 467 468 469 470
        ----------
        name : string
            Name of the filter

        Returns
        -------
        filter : pcigale.base.Filter
471 472 473 474 475 476
            The Filter object.

        Raises
        ------
        DatabaseLookupError : if the requested filter is not in the database.

Yannick Roehlly's avatar
Yannick Roehlly committed
477 478 479 480 481 482 483 484 485
        """
        result = (self.session.query(_Filter).
                  filter(_Filter.name == name).
                  first())
        if result:
            return Filter(result.name, result.description,
                          result.trans_type, result.trans_table,
                          result.effective_wavelength)
        else:
486 487
            raise DatabaseLookupError(
                "The filter <{0}> is not in the database".format(name))
Yannick Roehlly's avatar
Yannick Roehlly committed
488

489
    def get_bc03(self, imf, metallicity):
490 491 492 493 494 495 496 497 498 499 500 501
        """
        Query the database for the Bruzual and Charlot 2003 SSP corresponding
        to the given initial mass function and metallicity.

        Parameters
        ----------
        imf : string
            Initial mass function (salp for Salpeter, chab for Chabrier)
        metallicity : float
            0.02 for Solar metallicity
        Returns
        -------
502 503
        ssp : pcigale.data.BC03
            The BC03 object.
504 505 506 507

        Raises
        ------
        DatabaseLookupError : if the requested SSP is not in the database.
508 509

        """
510 511 512
        result = self.session.query(_BC03)\
            .filter(_BC03.imf == imf)\
            .filter(_BC03.metallicity == metallicity)\
513 514
            .first()
        if result:
515
            return BC03(result.imf, result.metallicity, result.time_grid,
516 517 518
                           result.wavelength_grid, result.color_table,
                           result.lumin_table)
        else:
519 520 521
            raise DatabaseLookupError(
                "The BC03 SSP for imf <{0}> and metallicity <{1}> is not in "
                "the database.".format(imf, metallicity))
522

523
    def get_m2005(self, imf, metallicity):
Yannick Roehlly's avatar
Yannick Roehlly committed
524 525 526 527
        """
        Query the database for a Maraston 2005 SSP corresponding to the given
        initial mass function and metallicity.

Yannick Roehlly's avatar
Yannick Roehlly committed
528
        Parameters
Yannick Roehlly's avatar
Yannick Roehlly committed
529 530 531 532 533 534 535 536
        ----------
        imf : string
            Initial mass function (ss for Salpeter, kr for Kroupa)
        metallicity : float
            [Z/H] = Log10(Z/Zsun) - Log10(H/Hsun)

        Returns
        -------
537 538
        ssp : pcigale.base.M2005
            The M2005 object.
539 540 541 542

        Raises
        ------
        DatabaseLookupError : if the requested SSP is not in the database.
Yannick Roehlly's avatar
Yannick Roehlly committed
543 544

        """
545 546 547
        result = self.session.query(_M2005)\
            .filter(_M2005.imf == imf)\
            .filter(_M2005.metallicity == metallicity)\
Yannick Roehlly's avatar
Yannick Roehlly committed
548 549
            .first()
        if result:
550
            return M2005(result.imf, result.metallicity, result.time_grid,
Yannick Roehlly's avatar
Yannick Roehlly committed
551 552 553
                            result.wavelength_grid, result.mass_table,
                            result.spec_table)
        else:
554 555 556
            raise DatabaseLookupError(
                "The M2005 SSP for imf <{0}> and metallicity <{1}> is not in "
                "the database.".format(imf, metallicity))
Yannick Roehlly's avatar
Yannick Roehlly committed
557

558
    def get_dh2002(self):
Yannick Roehlly's avatar
Yannick Roehlly committed
559 560 561 562 563
        """
        Get the Dale and Helou infrared templates from the database

        Returns
        -------
564
        template : pcigale.base.DH2002
565 566 567 568 569
            The Dale and Helou (2002) infrared templates.

        Raises
        ------
        DatabaseLookupError : if the templates are not in the database.
Yannick Roehlly's avatar
Yannick Roehlly committed
570 571

        """
572 573
        result = (self.session.query(_DH2002).
                  filter(_DH2002.name == 'dh2002').
Yannick Roehlly's avatar
Yannick Roehlly committed
574 575
                  first())
        if result:
576
            return DH2002(result.data[0], result.data[1],
Yannick Roehlly's avatar
Yannick Roehlly committed
577 578
                                     result.data[2])
        else:
579 580
            raise DatabaseLookupError(
                "The DH2002 templates are not in the database.")
Yannick Roehlly's avatar
Yannick Roehlly committed
581

582
    def get_dale2014(self, frac_agn, alpha):
583 584 585 586 587 588
        """
        Get the Dale et al (2014) template corresponding to the given set of
        parameters.

        Parameters
        ----------
589
        frac_agn: float
590 591
            contribution of the AGN to the IR luminosity
        alpha: float
592 593
            alpha corresponding to the updated Dale & Helou (2002) star
            forming template.
594

595 596 597 598 599 600 601 602 603
        Returns
        -------
        template : pcigale.data.Dale2014
            The Dale et al. (2014) IR template.

        Raises
        ------
        DatabaseLookupError : if the requested template is not in the database.

604
        """
605 606 607
        result = (self.session.query(_Dale2014).
                  filter(_Dale2014.fracAGN == frac_agn).
                  filter(_Dale2014.alpha == alpha).
608 609
                  first())
        if result:
610 611
            return Dale2014(result.fracAGN, result.alpha, result.wave,
                            result.lumin)
612
        else:
613 614 615
            raise DatabaseLookupError(
                "The Dale2014 template for frac_agn <{0}> and alpha <{1}> "
                "is not in the database.".format(frac_agn, alpha))
616

617
    def get_fritz2006(self, model_nb):
618 619 620 621 622 623 624 625 626 627
        """
        Get the Fritz et al. (2006) AGN model corresponding to the number.

        Parameters
        ----------
        model_nb : integer
            Model number.

        Returns
        -------
628
        agn : pcigale.data.Fritz2006
629 630 631 632 633
            The AGN model.

        Raises
        ------
        DatabaseLookupError : if the requested template is not in the database.
634 635

        """
636 637
        result = (self.session.query(_Fritz2006).
                  filter(_Fritz2006.model_nb == model_nb).
638 639
                  first())
        if result:
640
            return Fritz2006(result.model_nb, result.agn_type,
641 642 643 644
                                result.r_ratio, result.tau, result.beta,
                                result.gamma, result.theta, result.psy,
                                result.wave, result.luminosity)
        else:
645 646
            raise DatabaseLookupError(
                "The Fritz2006 model is not in the database.")
647

648 649 650
    def get_dl2007(self, qpah, umin, umax):
        """
        Get the Draine and Li (2007) model corresponding to the given set of
Yannick Roehlly's avatar
Yannick Roehlly committed
651
        parameters.
652 653 654 655 656 657 658 659 660

        Parameters
        ----------
        qpah: float
            Mass fraction of PAH
        umin: float
            Minimum radiation field
        umax: float
            Maximum radiation field
661 662 663 664 665 666 667 668 669

        Returns
        -------
        model : pcigale.data.DL2007
            The Draine and Li (2007) model.

        Raises
        ------
        DatabaseLookupError : if the requested model is not in the database.
670 671 672 673 674 675 676 677 678 679 680

        """
        result = (self.session.query(_DL2007).
                  filter(_DL2007.qpah == qpah).
                  filter(_DL2007.umin == umin).
                  filter(_DL2007.umax == umax).
                  first())
        if result:
            return DL2007(result.qpah, result.umin, result.umax, result.wave,
                          result.lumin)
        else:
681 682 683
            raise DatabaseLookupError(
                "The DL2007 model for qpah <{0}>, umin <{1}>, and umax <{2}> "
                "is not in the database.".format(qpah, umin, umax))
684

685
    def get_nebular_lines(self, metallicity, logU):
686 687
        """
        Get the line ratios corresponding to the given set of parameters.
688

689 690 691 692 693 694 695
        Parameters
        ----------
        metallicity: float
            Gas phase metallicity
        logU: float
            Radiation field intensity
        """
696 697 698 699
        result = (self.session.query(_NebularLines).
                  filter(_NebularLines.metallicity == metallicity).
                  filter(_NebularLines.logU == logU).
                  first())
700
        if result:
701 702
            return NebularLines(result.metallicity, result.logU, result.wave,
                                result.ratio)
703 704 705
        else:
            return None

706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726
    def get_nebular_continuum(self, metallicity, logU):
        """
        Get the nebular continuum corresponding to the given set of parameters.

        Parameters
        ----------
        metallicity: float
            Gas phase metallicity
        logU: float
            Radiation field intensity
        """
        result = (self.session.query(_NebularContinuum).
                  filter(_NebularContinuum.metallicity == metallicity).
                  filter(_NebularContinuum.logU == logU).
                  first())
        if result:
            return NebularContinuum(result.metallicity, result.logU,
                                    result.wave, result.lumin)
        else:
            return None

727 728 729 730 731 732 733 734 735 736 737 738 739
    def _get_parameters(self, schema):
        """Generic function to get parameters from an arbitrary schema.

        Returns
        -------
        parameters: dictionary
            Dictionary of parameters and their values
        """

        return {k.name: np.sort(
                [v[0] for v in set(self.session.query(schema).values(k))])
                for k in class_mapper(schema).primary_key}

740 741
    def get_m2005_parameters(self):
        """Get parameters for the Maraston 2005 stellar models.
742 743 744 745 746 747

        Returns
        -------
        paramaters: dictionary
            dictionary of parameters and their values
        """
748
        return self._get_parameters(_M2005)
749

750 751
    def get_bc03_parameters(self):
        """Get parameters for the Bruzual & Charlot 2003 stellar models.
752 753 754 755 756 757

        Returns
        -------
        paramaters: dictionary
            dictionary of parameters and their values
        """
758
        return self._get_parameters(_BC03)
759

760
    def get_dh2002_parameters(self):
761 762 763 764 765 766 767
        """Get parameters for the Dale 2014 models.

        Returns
        -------
        paramaters: dictionary
            dictionary of parameters and their values
        """
768
        return self._get_parameters(_DH2002)
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

    def get_dale2014_parameters(self):
        """Get parameters for the Dale 2014 models.

        Returns
        -------
        paramaters: dictionary
            dictionary of parameters and their values
        """
        return self._get_parameters(_Dale2014)

    def get_dl2007_parameters(self):
        """Get parameters for the DL2007 models.

        Returns
        -------
        paramaters: dictionary
            dictionary of parameters and their values
        """
        return self._get_parameters(_DL2007)

    def get_nebular_lines_parameters(self):
        """Get parameters for the nebular lines.

        Returns
        -------
        paramaters: dictionary
            dictionary of parameters and their values
        """
        return self._get_parameters(_NebularLines)

    def get_nebular_continuum_parameters(self):
        """Get parameters for the nebular continuum.

        Returns
        -------
        paramaters: dictionary
            dictionary of parameters and their values
        """
        return self._get_parameters(_NebularContinuum)

810
    def get_fritz2006_parameters(self):
811 812 813 814 815 816 817
        """Get parameters for the Fritz 2006 AGN models.

        Returns
        -------
        paramaters: dictionary
            dictionary of parameters and their values
        """
818
        return self._get_parameters(_Fritz2006)
819

Yannick Roehlly's avatar
Yannick Roehlly committed
820 821 822 823 824
    def get_filter_list(self):
        """Get the list of the filters in the database.

        Returns
        -------
Yannick Roehlly's avatar
Yannick Roehlly committed
825
        names, lambda_eff : array, dictionary
Yannick Roehlly's avatar
Yannick Roehlly committed
826
            names is the list of the filter names and lambda_eff is a
Yannick Roehlly's avatar
Yannick Roehlly committed
827
            dictionary associating the effective wavelength (in nm) to the
Yannick Roehlly's avatar
Yannick Roehlly committed
828 829 830 831 832 833 834 835 836
            filter name
        """
        result = self.session.query(_Filter.name,
                                    _Filter.effective_wavelength).all()
        result = dict(result)
        return result.keys(), result

    def parse_filters(self):
        """Generator to parse the filter database."""
837
        for filt in self.session.query(_Filter):
Yannick Roehlly's avatar
Yannick Roehlly committed
838 839 840
            yield Filter(filt.name, filt.description, filt.trans_type,
                         filt.trans_table, filt.effective_wavelength)

841
    def parse_m2005(self):
Yannick Roehlly's avatar
Yannick Roehlly committed
842
        """Generator to parse the Maraston 2005 SSP database."""
843 844
        for ssp in self.session.query(_M2005):
            yield M2005(ssp.imf, ssp.metallicity, ssp.time_grid,
Yannick Roehlly's avatar
Yannick Roehlly committed
845 846
                           ssp.wavelength_grid, ssp.mass_table,
                           ssp.spec_table)