Source code for optiwindnet.db.model

# SPDX-License-Identifier: MIT
# https://gitlab.windenergy.dtu.dk/TOPFARM/OptiWindNet/
"""Database model v3 for storage of locations and route sets (Peewee).

Tables:
  - NodeSet: location definition
  - RouteSet: routeset (i.e. a record of G)
  - Method: info on algorithm & options to produce routesets
  - Machine: info on machine that generated a routeset
"""

import os
from contextlib import contextmanager

from peewee import (
    AutoField,
    BlobField,
    CharField,
    DatabaseProxy,
    DateTimeField,
    FloatField,
    ForeignKeyField,
    IntegerField,
    Model,
    SqliteDatabase,
)
from playhouse.sqlite_ext import JSONField

from ._core import _naive_utc_now

__all__ = ()

database_proxy = DatabaseProxy()


class BaseModel(Model):
    class Meta:
        database = database_proxy


[docs] class NodeSet(BaseModel): # hashlib.sha256(VertexC + boundary).digest() digest = BlobField(primary_key=True) name = CharField(unique=True) T = IntegerField() # # of non-root nodes R = IntegerField() # # of root nodes B = IntegerField() # num_border_vertices # vertices (nodes + roots) coordinates (UTM) # np.lib.format.write_array(io, np.empty((R + T + B, 2), dtype=float)) VertexC = BlobField() # the first group is the border (ccw), then obstacles (cw) # B is sum(constraint_groups) constraint_groups = JSONField() # indices to VertexC, concatenation of the groups' ordered vertices constraint_vertices = JSONField() landscape_angle = FloatField(null=True)
[docs] class Method(BaseModel): # hashlib.sha256(funhash + pickle(options)).digest() digest = BlobField(primary_key=True) solver_name = CharField() funname = CharField() # options is a dict of function parameters options = JSONField() timestamp = DateTimeField(default=_naive_utc_now) funfile = CharField() # hashlib.sha256(fun.__code__.co_code) funhash = BlobField()
[docs] class Machine(BaseModel): id = AutoField() name = CharField(unique=True) attrs = JSONField(null=True)
[docs] class RouteSet(BaseModel): id = AutoField() handle = CharField() T = IntegerField() # num_nodes R = IntegerField() # num_roots capacity = IntegerField() length = FloatField() # runtime always in [s] runtime = FloatField(null=True) feeders_per_root = JSONField() # number of contour nodes C = IntegerField(default=0) # number of detour nodes D = IntegerField(default=0) # short identifier of routeset origin (redundant with Method) creator = CharField(null=True) # relative increase from undetoured routeset to the detoured one # detoured_length = (1 + detextra)*undetoured_length detextra = FloatField(null=True) num_diagonals = IntegerField(null=True) tentative = JSONField(null=True) rogue = JSONField(null=True) timestamp = DateTimeField(null=True, default=_naive_utc_now) misc = JSONField(default=dict) # never NULL, defaults to {} # len(clone2prime) == C + D clone2prime = JSONField(null=True) edges = JSONField() nodes = ForeignKeyField(NodeSet, backref='routesets') method = ForeignKeyField(Method, backref='routesets') machine = ForeignKeyField(Machine, backref='routesets', null=True)
_ALL_MODELS = [NodeSet, Method, Machine, RouteSet] _DEFAULT_SQLITE_TIMEOUT = 15
[docs] def open_database( filepath: str, create_db: bool = False, timeout: int = _DEFAULT_SQLITE_TIMEOUT ) -> SqliteDatabase: """Opens the sqlite database v3 file specified in `filepath`. Args: filepath: path to database file create_db: True -> create a new file if it does not exist timeout: seconds to wait for a locked database to be released Returns: SqliteDatabase object (Peewee) """ filepath = os.path.abspath(os.path.expanduser(str(filepath))) if not create_db and not os.path.exists(filepath): raise OSError(f'Database file not found: {filepath}') db = SqliteDatabase( filepath, pragmas={'foreign_keys': 1}, timeout=timeout, ) database_proxy.initialize(db) db.connect() db.create_tables(_ALL_MODELS) return db
[docs] @contextmanager def database_connection( filepath: str, create_db: bool = False, timeout: int = _DEFAULT_SQLITE_TIMEOUT ): """Open the sqlite database for the duration of a context block. Args: filepath: path to database file create_db: True -> create a new file if it does not exist timeout: seconds to wait for a locked database to be released Yields: Connected SqliteDatabase object (Peewee) """ db = open_database(filepath, create_db=create_db, timeout=timeout) try: yield db finally: db.close()