Source code for openquake.server.db.models

# -*- coding: utf-8 -*-
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright (C) 2010-2016 GEM Foundation
#
# OpenQuake is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# OpenQuake is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with OpenQuake. If not, see <http://www.gnu.org/licenses/>.

# Disable:
# - 'Maximum number of public methods for a class'
# - 'Missing docstring' (because of all of the model Meta)
# pylint: disable=R0904,C0111

'''
Model representations of the OpenQuake DB tables.
'''
import os
from datetime import datetime
from openquake.commonlib import datastore
from django.db import models as djm
from django.core.exceptions import ObjectDoesNotExist


# this is pickleable, ObjectDoesNotExist is not
[docs]class NotFound(Exception): """Raised when a Django object does not exist"""
[docs]def get(djm, **kw): """ Small wrapper around `djm.objects.get` """ try: return djm.objects.get(**kw) except ObjectDoesNotExist: raise NotFound(kw)
#: Kind of supported curve statistics STAT_CHOICES = ( (u'mean', u'Mean'), (u'quantile', u'Quantile')) #: System Reference ID used for geometry objects DEFAULT_SRID = 4326 VS30_TYPE_CHOICES = ( (u"measured", u"Value obtained from on-site measurements"), (u"inferred", u"Estimated value"), ) IMT_CHOICES = ( (u'PGA', u'Peak Ground Acceleration'), (u'PGV', u'Peak Ground Velocity'), (u'PGD', u'Peak Ground Displacement'), (u'SA', u'Spectral Acceleration'), (u'IA', u'Arias Intensity'), (u'RSD', u'Relative Significant Duration'), (u'MMI', u'Modified Mercalli Intensity'), ) #: Minimum value for a seed number MIN_SINT_32 = -(2 ** 31) #: Maximum value for a seed number MAX_SINT_32 = (2 ** 31) - 1 #: Kind of supported type of loss outputs LOSS_TYPES = ["structural", "nonstructural", "fatalities", "contents"] #: relative tolerance to consider two risk outputs (almost) equal RISK_RTOL = 0.05 #: absolute tolerance to consider two risk outputs (almost) equal RISK_ATOL = 0.01 # TODO: these want to be dictionaries INPUT_TYPE_CHOICES = ( (u'unknown', u'Unknown'), (u'source', u'Source Model'), (u'source_model_logic_tree', u'Source Model Logic Tree'), (u'gsim_logic_tree', u'Ground Shaking Intensity Model Logic Tree'), (u'exposure', u'Exposure'), (u'fragility', u'Fragility'), (u'site_model', u'Site Model'), (u'rupture_model', u'Rupture Model'), # vulnerability models (u'structural_vulnerability', u'Structural Vulnerability'), (u'nonstructural_vulnerability', u'Non Structural Vulnerability'), (u'contents_vulnerability', u'Contents Vulnerability'), (u'business_interruption_vulnerability', u'Business Interruption Vulnerability'), (u'occupants_vulnerability', u'Occupants Vulnerability'), (u'structural_vulnerability_retrofitted', u'Structural Vulnerability Retrofitted')) # Tables in the 'uiapi' schema.
[docs]class OqJob(djm.Model): ''' An OpenQuake engine run started by the user ''' description = djm.TextField() user_name = djm.TextField() calculation_mode = djm.TextField() hazard_calculation = djm.ForeignKey('OqJob', null=True) STATUS_CHOICES = ( (u'created', u'Created'), (u'executing', u'Executing'), (u'post_executing', u'Post-Executing'), (u'post_processing', u'Post-Processing'), (u'export', u'Exporting results'), (u'clean_up', u'Cleaning up'), (u'complete', u'Complete'), ) status = djm.TextField(choices=STATUS_CHOICES, default='executing') is_running = djm.BooleanField(default=True) start_time = djm.DateTimeField(editable=False, default=datetime.utcnow) stop_time = djm.DateTimeField(editable=False) relevant = djm.BooleanField(null=False, default=True) ds_calc_dir = djm.TextField(null=False, blank=True) # datastore calc_dir class Meta: db_table = 'job' @property def job_type(self): """ 'hazard' or 'risk' """ # the calculation mode can be unknown if the job parameters # have not been written on the database yet return 'risk' if ('risk' in self.calculation_mode or 'damage' in self.calculation_mode or 'bcr' in self.calculation_mode) else 'hazard'
[docs] def get_oqparam(self): """ Return an OqParam object as read from the database """ datadir = os.path.dirname(self.ds_calc_dir) dstore = datastore.read(self.id, datadir=datadir) return dstore['oqparam']
def __repr__(self): return '<%s %d, %s>' % (self.__class__.__name__, self.id, self.job_type)
[docs]def oqparam(job_id): """ :param job_id: ID of :class:`openquake.server.db.models.OqJob` :returns: instance of :class:`openquake.commonlib.oqvalidation.OqParam` """ return OqJob.objects.get(pk=job_id).get_oqparam()
[docs]class Performance(djm.Model): ''' Contains performance information about a job. ''' job = djm.ForeignKey('OqJob') operation = djm.TextField(null=False) time_sec = djm.FloatField(null=False) memory_mb = djm.FloatField(null=False) counts = djm.IntegerField(null=False) class Meta: db_table = 'performance'
[docs]class Log(djm.Model): ''' Log table for calculations ''' job = djm.ForeignKey('OqJob', null=True) timestamp = djm.DateTimeField(editable=False, default=datetime.utcnow) LOG_LEVEL_CHOICES = ( (u'debug', u'Debug'), (u'info', u'Info'), (u'warn', u'Warn'), (u'error', u'Error'), (u'critical', u'Critical'), ) level = djm.TextField(choices=LOG_LEVEL_CHOICES) process = djm.TextField(null=False) message = djm.TextField(null=False) class Meta: db_table = 'log' ordering = ['id']
[docs]class OutputManager(djm.Manager): """ Manager class to filter and create Output objects """
[docs] def create_output(self, job, display_name, ds_key): """ Create an output for the given `job`, `display_name` and `ds_key` """ return self.create(oq_job=job, display_name=display_name, ds_key=ds_key)
[docs]class Output(djm.Model): ''' A single artifact which is a result of an OpenQuake job. The data may reside in a file or in the database. ''' oq_job = djm.ForeignKey('OqJob', null=False) display_name = djm.TextField() last_update = djm.DateTimeField(editable=False, default=datetime.utcnow) ds_key = djm.TextField(null=False, blank=True) # datastore key objects = OutputManager() def __str__(self): return "%d||%s" % (self.id, self.display_name) class Meta: db_table = 'output' ordering = ['id']