cerc-persistence 0.1.0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. cerc-persistence-0.1.0.4/PKG-INFO +13 -0
  2. cerc-persistence-0.1.0.4/README.md +63 -0
  3. cerc-persistence-0.1.0.4/cerc_persistence/__init__.py +3 -0
  4. cerc-persistence-0.1.0.4/cerc_persistence/configuration.py +67 -0
  5. cerc-persistence-0.1.0.4/cerc_persistence/db_control.py +241 -0
  6. cerc-persistence-0.1.0.4/cerc_persistence/db_setup.py +70 -0
  7. cerc-persistence-0.1.0.4/cerc_persistence/models/__init__.py +8 -0
  8. cerc-persistence-0.1.0.4/cerc_persistence/models/application.py +32 -0
  9. cerc-persistence-0.1.0.4/cerc_persistence/models/city.py +36 -0
  10. cerc-persistence-0.1.0.4/cerc_persistence/models/city_object.py +82 -0
  11. cerc-persistence-0.1.0.4/cerc_persistence/models/simulation_results.py +33 -0
  12. cerc-persistence-0.1.0.4/cerc_persistence/models/user.py +42 -0
  13. cerc-persistence-0.1.0.4/cerc_persistence/repositories/__init__.py +3 -0
  14. cerc-persistence-0.1.0.4/cerc_persistence/repositories/application.py +111 -0
  15. cerc-persistence-0.1.0.4/cerc_persistence/repositories/city.py +138 -0
  16. cerc-persistence-0.1.0.4/cerc_persistence/repositories/city_object.py +200 -0
  17. cerc-persistence-0.1.0.4/cerc_persistence/repositories/simulation_results.py +193 -0
  18. cerc-persistence-0.1.0.4/cerc_persistence/repositories/user.py +159 -0
  19. cerc-persistence-0.1.0.4/cerc_persistence/repository.py +22 -0
  20. cerc-persistence-0.1.0.4/cerc_persistence/version.py +4 -0
  21. cerc-persistence-0.1.0.4/cerc_persistence.egg-info/PKG-INFO +13 -0
  22. cerc-persistence-0.1.0.4/cerc_persistence.egg-info/SOURCES.txt +27 -0
  23. cerc-persistence-0.1.0.4/cerc_persistence.egg-info/dependency_links.txt +1 -0
  24. cerc-persistence-0.1.0.4/cerc_persistence.egg-info/requires.txt +7 -0
  25. cerc-persistence-0.1.0.4/cerc_persistence.egg-info/top_level.txt +1 -0
  26. cerc-persistence-0.1.0.4/pyproject.toml +8 -0
  27. cerc-persistence-0.1.0.4/requirements.txt +6 -0
  28. cerc-persistence-0.1.0.4/setup.cfg +4 -0
  29. cerc-persistence-0.1.0.4/setup.py +41 -0
@@ -0,0 +1,13 @@
1
+ Metadata-Version: 2.1
2
+ Name: cerc-persistence
3
+ Version: 0.1.0.4
4
+ Classifier: License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)
5
+ Classifier: Programming Language :: Python
6
+ Classifier: Programming Language :: Python :: 3
7
+ Requires-Dist: pathlib
8
+ Requires-Dist: python-dotenv
9
+ Requires-Dist: SQLAlchemy
10
+ Requires-Dist: cerc-hub
11
+ Requires-Dist: psycopg2-binary
12
+ Requires-Dist: sqlalchemy_utils
13
+ Requires-Dist: setuptools
@@ -0,0 +1,63 @@
1
+ # CERC Persistence
2
+
3
+ The persistence package includes classes to store different class objects in a Postgres database.
4
+
5
+ ## Models
6
+
7
+ This defines models for all class objects that we want to persist. It is used for Object Relation Mapping (ORM)
8
+ of the class objects to database table columns
9
+
10
+ ## Repositories
11
+
12
+ This defines repository classes that contain CRUD methods for database operations. The constructor of all repositories
13
+ requires the database name to connect to and the application environment (PROD or TEST). Tests use a different database
14
+ from the production environment, which is why this is necessary. An example is shown below:
15
+
16
+ ```python
17
+ from cerc_persistence.db_setup import DBSetup
18
+
19
+ # instantiate city repo for hub production database
20
+ db = DBSetup(db_name='hub', app_env='PROD', dotenv_path='/path/to/.env', admin_password='application_password', application_uuid='UUID')
21
+ ```
22
+
23
+ All database operations are conducted with the production database (*PROD*) named *hub* in the example above.
24
+
25
+ ## config_db
26
+
27
+ This Python file is a configuration class that contains variables that map to configuration parameters in a .env file.
28
+ It also contains a method ``def conn_string()`` which returns the connection string to a Postgres database.
29
+
30
+ ## Base
31
+
32
+ This class has a constructor that establishes a database connection and returns a reference for database-related CRUD
33
+ operations.
34
+
35
+ ## Database Configuration Parameter
36
+
37
+ A .env file (or environment variables) with configuration parameters described below are needed to establish a database
38
+ connection:
39
+
40
+ ```
41
+ # production database credentials
42
+ PROD_DB_USER=postgres-database-user
43
+ PROD_DB_PASSWORD=postgres-database-password
44
+ PROD_DB_HOST=database-host
45
+ PROD_DB_PORT=database-port
46
+
47
+ # test database credentials
48
+ TEST_DB_USER=postgres-database-user
49
+ TEST_DB_PASSWORD=postgres-database-password
50
+ TEST_DB_HOST=database-host
51
+ TEST_DB_PORT=database-port
52
+ ```
53
+
54
+ ## Database Related Unit Test
55
+
56
+ Unit tests that involve database operations require a Postgres database to be set up.
57
+ The tests connect to the database server using the default postgres user (*postgres*).
58
+ NB: You can provide any credentials for the test to connect to postgres, just make sure
59
+ the credentials are set in your .env file as explained above in *Database Configuration Parameters* section.
60
+
61
+ When the tests are run, a **test_db** database is created and then the required tables for
62
+ the test. Before the tests run, the *test_db* is deleted to ensure that each test starts
63
+ on a clean slate.
@@ -0,0 +1,3 @@
1
+ """
2
+ Repositories Package
3
+ """
@@ -0,0 +1,67 @@
1
+ """
2
+ Persistence (Postgresql) configuration
3
+ SPDX - License - Identifier: LGPL - 3.0 - or -later
4
+ Copyright © 2022 Concordia CERC group
5
+ Project Coder Peter Yefi peteryefi@gmail.com
6
+ """
7
+
8
+ import logging
9
+ import os
10
+ from pathlib import Path
11
+ from dotenv import load_dotenv
12
+ from sqlalchemy.ext.declarative import declarative_base
13
+
14
+ Models = declarative_base()
15
+
16
+
17
+ class Configuration:
18
+ """
19
+ Configuration class to hold common persistence configuration
20
+ """
21
+
22
+ def __init__(self, db_name: str, dotenv_path: str, app_env='TEST'):
23
+ """
24
+ :param db_name: database name
25
+ :param app_env: application environment, test or production
26
+ :param dotenv_path: the absolute path to dotenv file
27
+ """
28
+ try:
29
+ # load environmental variables
30
+ if not Path(dotenv_path).exists():
31
+ error_message = f'dotenv file doesn\'t exists at {dotenv_path}'
32
+ logging.error(error_message)
33
+ raise FileNotFoundError(error_message)
34
+ load_dotenv(dotenv_path=dotenv_path)
35
+
36
+ self._db_name = db_name
37
+ self._db_host = os.getenv(f'{app_env}_DB_HOST')
38
+ self._db_user = os.getenv(f'{app_env}_DB_USER')
39
+ self._db_pass = os.getenv(f'{app_env}_DB_PASSWORD')
40
+ self._db_port = os.getenv(f'{app_env}_DB_PORT')
41
+ self.hub_token = os.getenv('HUB_TOKEN')
42
+ except KeyError as err:
43
+ logging.error('Error with credentials: %s', err)
44
+
45
+ @property
46
+ def connection_string(self):
47
+ """
48
+ Returns a connection string postgresql
49
+ :return: connection string
50
+ """
51
+ if self._db_pass:
52
+ return f'postgresql://{self._db_user}:{self._db_pass}@{self._db_host}:{self._db_port}/{self._db_name}'
53
+ return f'postgresql://{self._db_user}@{self._db_host}:{self._db_port}/{self._db_name}'
54
+
55
+ @property
56
+ def db_user(self):
57
+ """
58
+ retrieve the configured username
59
+ """
60
+ return self._db_user
61
+
62
+ @property
63
+ def db_name(self):
64
+ """
65
+ retrieve the configured database name
66
+ """
67
+ return self._db_name
@@ -0,0 +1,241 @@
1
+ """
2
+ DBFactory performs read related operations
3
+ SPDX - License - Identifier: LGPL - 3.0 - or -later
4
+ Copyright © 2022 Concordia CERC group
5
+ Project CoderPeter Yefi peteryefi@gmail.com
6
+ """
7
+ from typing import Dict
8
+
9
+ from cerc_persistence.repositories.application import Application
10
+ from cerc_persistence.repositories.city import City
11
+ from cerc_persistence.repositories.city_object import CityObject
12
+ from cerc_persistence.repositories.simulation_results import SimulationResults
13
+ from cerc_persistence.repositories.user import User
14
+ from cerc_persistence.repositories.user import UserRoles
15
+
16
+
17
+ class DBControl:
18
+ """
19
+ DBFactory class
20
+ """
21
+
22
+ def __init__(self, db_name, app_env, dotenv_path):
23
+ self._city = City(db_name=db_name, dotenv_path=dotenv_path, app_env=app_env)
24
+ self._application = Application(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path)
25
+ self._user = User(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path)
26
+ self._city_object = CityObject(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path)
27
+ self._simulation_results = SimulationResults(db_name=db_name, dotenv_path=dotenv_path, app_env=app_env)
28
+
29
+ def application_info(self, application_uuid) -> Application:
30
+ """
31
+ Retrieve the application info for the given uuid from the database
32
+ :param application_uuid: the uuid for the application
33
+ :return: Application
34
+ """
35
+ return self._application.get_by_uuid(application_uuid)
36
+
37
+ def user_info(self, name, password, application_id) -> User:
38
+ """
39
+ Retrieve the user info for the given name and password and application_id from the database
40
+ :param name: the username
41
+ :param password: the user password
42
+ :param application_id: the application id
43
+ :return: User
44
+ """
45
+ return self._user.get_by_name_application_id_and_password(name, password, application_id)
46
+
47
+ def user_login(self, name, password, application_uuid) -> User:
48
+ """
49
+ Retrieve the user info from the database
50
+ :param name: the username
51
+ :param password: the user password
52
+ :param application_uuid: the application uuid
53
+ :return: User
54
+ """
55
+ return self._user.get_by_name_application_uuid_and_password(name, password, application_uuid)
56
+
57
+ def cities_by_user_and_application(self, user_id, application_id) -> [City]:
58
+ """
59
+ Retrieve the cities belonging to the user and the application from the database
60
+ :param user_id: User id
61
+ :param application_id: Application id
62
+ :return: [City]
63
+ """
64
+ return self._city.get_by_user_id_and_application_id(user_id, application_id)
65
+
66
+ def building(self, name, user_id, application_id, scenario) -> CityObject:
67
+ """
68
+ Retrieve the building from the database
69
+ :param name: Building name
70
+ :param user_id: User id
71
+ :param application_id: Application id
72
+ :param scenario: Scenario
73
+ :
74
+ """
75
+ cities = self._city.get_by_user_id_application_id_and_scenario(user_id, application_id, scenario)
76
+ city = [city[0].id for city in cities]
77
+ result = self._city_object.building_in_cities_info(name, city)
78
+ if result is not None:
79
+ return result
80
+ return None
81
+
82
+ def building_info(self, name, city_id) -> CityObject:
83
+ """
84
+ Retrieve the building info from the database
85
+ :param name: Building name
86
+ :param city_id: City ID
87
+ :return: CityObject
88
+ """
89
+ return self._city_object.get_by_name_or_alias_and_city(name, city_id)
90
+
91
+ def building_info_in_cities(self, name, cities) -> CityObject:
92
+ """
93
+ Retrieve the building info from the database
94
+ :param name: Building name
95
+ :param cities: [City ID]
96
+ :return: CityObject
97
+ """
98
+ return self._city_object.get_by_name_or_alias_in_cities(name, cities)
99
+
100
+ def results(self, user_id, application_id, request_values, result_names=None) -> Dict:
101
+ """
102
+ Retrieve the simulation results for the given cities from the database
103
+ :param user_id: the user id owning the results
104
+ :param application_id: the application id owning the results
105
+ :param request_values: dictionary containing the scenario and building names to grab the results
106
+ :param result_names: if given, filter the results to the selected names
107
+ """
108
+ if result_names is None:
109
+ result_names = []
110
+ results = {}
111
+ for scenario in request_values['scenarios']:
112
+ for scenario_name in scenario.keys():
113
+ result_sets = self._city.get_by_user_id_application_id_and_scenario(
114
+ user_id,
115
+ application_id,
116
+ scenario_name
117
+ )
118
+ if result_sets is None:
119
+ continue
120
+ results[scenario_name] = []
121
+ city_ids = [r[0].id for r in result_sets]
122
+ for building_name in scenario[scenario_name]:
123
+ _building = self._city_object.get_by_name_or_alias_in_cities(building_name, city_ids)
124
+ if _building is None:
125
+ continue
126
+ city_object_id = _building.id
127
+ _ = self._simulation_results.get_simulation_results_by_city_object_id_and_names(
128
+ city_object_id,
129
+ result_names)
130
+
131
+ for value in _:
132
+ values = value.values
133
+ values["building"] = building_name
134
+ results[scenario_name].append(values)
135
+ return results
136
+
137
+ def persist_city(self, city: City, pickle_path, scenario, application_id: int, user_id: int):
138
+ """
139
+ Creates a city into the database
140
+ :param city: City to be stored
141
+ :param pickle_path: Path to save the pickle file
142
+ :param scenario: Simulation scenario name
143
+ :param application_id: Application id owning this city
144
+ :param user_id: User who create the city
145
+ return identity_id
146
+ """
147
+ return self._city.insert(city, pickle_path, scenario, application_id, user_id)
148
+
149
+ def update_city(self, city_id, city):
150
+ """
151
+ Update an existing city in the database
152
+ :param city_id: the id of the city to update
153
+ :param city: the updated city object
154
+ """
155
+ return self._city.update(city_id, city)
156
+
157
+ def persist_application(self, name: str, description: str, application_uuid: str):
158
+ """
159
+ Creates information for an application in the database
160
+ :param name: name of application
161
+ :param description: the description of the application
162
+ :param application_uuid: the uuid of the application to be created
163
+ """
164
+ return self._application.insert(name, description, application_uuid)
165
+
166
+ def update_application(self, name: str, description: str, application_uuid: str):
167
+ """
168
+ Update the application information stored in the database
169
+ :param name: name of application
170
+ :param description: the description of the application
171
+ :param application_uuid: the uuid of the application to be created
172
+ """
173
+ return self._application.update(application_uuid, name, description)
174
+
175
+ def add_simulation_results(self, name, values, city_id=None, city_object_id=None):
176
+ """
177
+ Add simulation results to the city or to the city_object to the database
178
+ :param name: simulation and simulation engine name
179
+ :param values: simulation values in json format
180
+ :param city_id: city id or None
181
+ :param city_object_id: city object id or None
182
+ """
183
+ return self._simulation_results.insert(name, values, city_id, city_object_id)
184
+
185
+ def create_user(self, name: str, application_id: int, password: str, role: UserRoles):
186
+ """
187
+ Creates a new user in the database
188
+ :param name: the name of the user
189
+ :param application_id: the application id of the user
190
+ :param password: the password of the user
191
+ :param role: the role of the user
192
+ """
193
+ return self._user.insert(name, password, role, application_id)
194
+
195
+ def update_user(self, user_id: int, name: str, password: str, role: UserRoles):
196
+ """
197
+ Updates a user in the database
198
+ :param user_id: the id of the user
199
+ :param name: the name of the user
200
+ :param password: the password of the user
201
+ :param role: the role of the user
202
+ """
203
+ return self._user.update(user_id, name, password, role)
204
+
205
+ def get_by_name_and_application(self, name: str, application: int):
206
+ """
207
+ Retrieve a single user from the database
208
+ :param name: username
209
+ :param application: application accessing hub
210
+ """
211
+ return self._user.get_by_name_and_application(name, application)
212
+
213
+ def delete_user(self, user_id):
214
+ """
215
+ Delete a single user from the database
216
+ :param user_id: the id of the user to delete
217
+ """
218
+ self._user.delete(user_id)
219
+
220
+ def delete_city(self, city_id):
221
+ """
222
+ Deletes a single city from the database
223
+ :param city_id: the id of the city to get
224
+ """
225
+ self._city.delete(city_id)
226
+
227
+ def delete_results_by_name(self, name, city_id=None, city_object_id=None):
228
+ """
229
+ Deletes city object simulation results from the database
230
+ :param name: simulation name
231
+ :param city_id: if given, delete delete the results for the city with id city_id
232
+ :param city_object_id: if given, delete delete the results for the city object with id city_object_id
233
+ """
234
+ self._simulation_results.delete(name, city_id=city_id, city_object_id=city_object_id)
235
+
236
+ def delete_application(self, application_uuid):
237
+ """
238
+ Deletes a single application from the database
239
+ :param application_uuid: the id of the application to get
240
+ """
241
+ self._application.delete(application_uuid)
@@ -0,0 +1,70 @@
1
+ """
2
+ Database setup
3
+ SPDX - License - Identifier: LGPL - 3.0 - or -later
4
+ Copyright © 2022 Concordia CERC group
5
+ Project Coder Peter Yefi peteryefi@gmail.com
6
+ """
7
+
8
+ import logging
9
+ from cerc_persistence.repository import Repository
10
+ from cerc_persistence.models import Application
11
+ from cerc_persistence.models import City
12
+ from cerc_persistence.models import CityObject
13
+ from cerc_persistence.models import User
14
+ from cerc_persistence.models import UserRoles
15
+ from cerc_persistence.models import SimulationResults
16
+ from cerc_persistence.repositories.user import User as UserRepository
17
+ from cerc_persistence.repositories.application import Application as ApplicationRepository
18
+
19
+
20
+ class DBSetup:
21
+ """
22
+ Creates a Persistence database structure
23
+ """
24
+
25
+ def __init__(self, db_name, app_env, dotenv_path, admin_password, application_uuid):
26
+ """
27
+ Creates database tables a default admin user and a default admin app with the given password and uuid
28
+ :param db_name: database name
29
+ :param app_env: application environment type [TEST|PROD]
30
+ :param dotenv_path: .env file path
31
+ :param admin_password: administrator password for the application uuid
32
+ :application_uuid: application uuid
33
+ """
34
+ repository = Repository(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path)
35
+
36
+ # Create the tables using the models
37
+ Application.__table__.create(bind=repository.engine, checkfirst=True)
38
+ User.__table__.create(bind=repository.engine, checkfirst=True)
39
+ City.__table__.create(bind=repository.engine, checkfirst=True)
40
+ CityObject.__table__.create(bind=repository.engine, checkfirst=True)
41
+ SimulationResults.__table__.create(bind=repository.engine, checkfirst=True)
42
+
43
+ self._user_repo = UserRepository(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path)
44
+ self._application_repo = ApplicationRepository(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path)
45
+ application_id = self._create_admin_app(self._application_repo, application_uuid)
46
+ self._create_admin_user(self._user_repo, admin_password, application_id)
47
+
48
+ @staticmethod
49
+ def _create_admin_app(application_repo, application_uuid):
50
+ name = 'AdminTool'
51
+ description = 'Admin tool to control city persistence and to test the API v1.4'
52
+ logging.info('Creating default admin tool application...')
53
+ application = application_repo.insert(name, description, application_uuid)
54
+
55
+ if isinstance(application, dict):
56
+ logging.info(application)
57
+ else:
58
+ msg = f'Created Admin tool with application_uuid: {application_uuid}'
59
+ logging.info(msg)
60
+ return application.id
61
+
62
+ @staticmethod
63
+ def _create_admin_user(user_repo, admin_password, application_id):
64
+ password = admin_password
65
+ logging.info('Creating default admin user...')
66
+ user = user_repo.insert('Administrator', password, UserRoles.Admin, application_id)
67
+ if isinstance(user, dict):
68
+ logging.info(user)
69
+ else:
70
+ logging.info('Created Admin user')
@@ -0,0 +1,8 @@
1
+ """
2
+ Models package
3
+ """
4
+ from .application import Application
5
+ from .city import City
6
+ from .city_object import CityObject
7
+ from .simulation_results import SimulationResults
8
+ from .user import User, UserRoles
@@ -0,0 +1,32 @@
1
+ """
2
+ Model representation of an application
3
+ SPDX - License - Identifier: LGPL - 3.0 - or -later
4
+ Copyright © 2022 Concordia CERC group
5
+ Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
6
+ """
7
+
8
+ import datetime
9
+
10
+ from sqlalchemy import Column, Integer, String, Sequence
11
+ from sqlalchemy import DateTime
12
+ from sqlalchemy.dialects.postgresql import UUID
13
+
14
+ from cerc_persistence.configuration import Models
15
+
16
+
17
+ class Application(Models):
18
+ """
19
+ A model representation of an application
20
+ """
21
+ __tablename__ = 'application'
22
+ id = Column(Integer, Sequence('application_id_seq'), primary_key=True)
23
+ name = Column(String, nullable=False)
24
+ description = Column(String, nullable=False)
25
+ application_uuid = Column(UUID(as_uuid=True), nullable=False)
26
+ created = Column(DateTime, default=datetime.datetime.utcnow)
27
+ updated = Column(DateTime, default=datetime.datetime.utcnow)
28
+
29
+ def __init__(self, name, description, application_uuid):
30
+ self.name = name
31
+ self.description = description
32
+ self.application_uuid = application_uuid
@@ -0,0 +1,36 @@
1
+ """
2
+ Model representation of a City
3
+ SPDX - License - Identifier: LGPL - 3.0 - or -later
4
+ Copyright © 2022 Concordia CERC group
5
+ Project Coder Peter Yefi peteryefi@gmail.com
6
+ """
7
+
8
+ import datetime
9
+
10
+ from sqlalchemy import Column, Integer, String, Sequence, ForeignKey
11
+ from sqlalchemy import DateTime
12
+
13
+ from cerc_persistence.configuration import Models
14
+
15
+
16
+ class City(Models):
17
+ """A model representation of a city
18
+ """
19
+ __tablename__ = 'city'
20
+ id = Column(Integer, Sequence('city_id_seq'), primary_key=True)
21
+ pickle_path = Column(String, nullable=False)
22
+ name = Column(String, nullable=False)
23
+ scenario = Column(String, nullable=False)
24
+ application_id = Column(Integer, ForeignKey('application.id', ondelete='CASCADE'), nullable=False)
25
+ user_id = Column(Integer, ForeignKey('user.id', ondelete='CASCADE'), nullable=True)
26
+ hub_release = Column(String, nullable=False)
27
+ created = Column(DateTime, default=datetime.datetime.utcnow)
28
+ updated = Column(DateTime, default=datetime.datetime.utcnow)
29
+
30
+ def __init__(self, pickle_path, name, scenario, application_id, user_id, hub_release):
31
+ self.pickle_path = str(pickle_path)
32
+ self.name = name
33
+ self.scenario = scenario
34
+ self.application_id = application_id
35
+ self.user_id = user_id
36
+ self.hub_release = hub_release
@@ -0,0 +1,82 @@
1
+ """
2
+ Model representation of a city object
3
+ SPDX - License - Identifier: LGPL - 3.0 - or -later
4
+ Copyright © 2022 Concordia CERC group
5
+ Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
6
+ """
7
+
8
+ import datetime
9
+ import logging
10
+
11
+ from sqlalchemy import Column, Integer, String, Sequence, ForeignKey, Float
12
+ from sqlalchemy import DateTime
13
+
14
+ from hub.city_model_structure.building import Building
15
+ from cerc_persistence.configuration import Models
16
+
17
+
18
+ class CityObject(Models):
19
+ """
20
+ A model representation of an application
21
+ """
22
+ __tablename__ = 'city_object'
23
+ id = Column(Integer, Sequence('city_object_id_seq'), primary_key=True)
24
+ city_id = Column(Integer, ForeignKey('city.id', ondelete='CASCADE'), nullable=False)
25
+ name = Column(String, nullable=False)
26
+ aliases = Column(String, nullable=True)
27
+ type = Column(String, nullable=False)
28
+ year_of_construction = Column(Integer, nullable=True)
29
+ function = Column(String, nullable=True)
30
+ usage = Column(String, nullable=True)
31
+ volume = Column(Float, nullable=False)
32
+ area = Column(Float, nullable=False)
33
+ total_heating_area = Column(Float, nullable=False)
34
+ wall_area = Column(Float, nullable=False)
35
+ windows_area = Column(Float, nullable=False)
36
+ roof_area = Column(Float, nullable=False)
37
+ total_pv_area = Column(Float, nullable=False)
38
+ system_name = Column(String, nullable=False)
39
+ created = Column(DateTime, default=datetime.datetime.utcnow)
40
+ updated = Column(DateTime, default=datetime.datetime.utcnow)
41
+
42
+ def __init__(self, city_id, building: Building):
43
+ self.city_id = city_id
44
+ self.name = building.name
45
+ self.aliases = building.aliases
46
+ self.type = building.type
47
+ self.year_of_construction = building.year_of_construction
48
+ self.function = building.function
49
+ self.usage = building.usages_percentage
50
+ self.volume = building.volume
51
+ self.area = building.floor_area
52
+ self.roof_area = sum(roof.solid_polygon.area for roof in building.roofs)
53
+ self.total_pv_area = sum(
54
+ roof.solid_polygon.area * roof.solar_collectors_area_reduction_factor for roof in building.roofs
55
+ )
56
+ storeys = building.storeys_above_ground
57
+ wall_area = 0
58
+ window_ratio = 0
59
+ try:
60
+ if storeys is None:
61
+ storeys = building.max_height / building.average_storey_height
62
+ for internal_zone in building.internal_zones:
63
+ for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
64
+ for thermal_boundary in thermal_zone.thermal_boundaries:
65
+ window_ratio = thermal_boundary.window_ratio
66
+ break
67
+ except TypeError:
68
+ storeys = 0
69
+ logging.warning(
70
+ 'building %s has no storey height so heating area, storeys and window ratio cannot be calculated',
71
+ self.name
72
+ )
73
+ self.total_heating_area = building.floor_area * storeys
74
+
75
+ for wall in building.walls:
76
+ wall_area += wall.solid_polygon.area
77
+ self.wall_area = wall_area
78
+ self.windows_area = wall_area * window_ratio
79
+ system_name = building.energy_systems_archetype_name
80
+ if system_name is None:
81
+ system_name = ''
82
+ self.system_name = system_name
@@ -0,0 +1,33 @@
1
+ """
2
+ Model representation of simulation results
3
+ SPDX - License - Identifier: LGPL - 3.0 - or -later
4
+ Copyright © 2022 Concordia CERC group
5
+ Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
6
+ """
7
+
8
+ import datetime
9
+
10
+ from sqlalchemy import Column, Integer, String, Sequence, ForeignKey
11
+ from sqlalchemy import DateTime
12
+ from sqlalchemy.dialects.postgresql import JSONB
13
+ from cerc_persistence.configuration import Models
14
+
15
+
16
+ class SimulationResults(Models):
17
+ """
18
+ A model representation of an application
19
+ """
20
+ __tablename__ = 'simulation_results'
21
+ id = Column(Integer, Sequence('simulation_results_id_seq'), primary_key=True)
22
+ city_id = Column(Integer, ForeignKey('city.id', ondelete='CASCADE'), nullable=True)
23
+ city_object_id = Column(Integer, ForeignKey('city_object.id', ondelete='CASCADE'), nullable=True)
24
+ name = Column(String, nullable=False)
25
+ values = Column(JSONB, nullable=False)
26
+ created = Column(DateTime, default=datetime.datetime.utcnow)
27
+ updated = Column(DateTime, default=datetime.datetime.utcnow)
28
+
29
+ def __init__(self, name, values, city_id=None, city_object_id=None):
30
+ self.name = name
31
+ self.values = values
32
+ self.city_id = city_id
33
+ self.city_object_id = city_object_id