From c2bbece21ca458e6311ffd70c046840216d4dbb9 Mon Sep 17 00:00:00 2001 From: Ruben Sanchez Date: Tue, 28 Nov 2023 13:36:40 -0500 Subject: [PATCH] Copy from hub docs modified to fit the persistence repo --- .gitignore | 3 + Makefile | 40 ++ README.md | 171 ++++++++ create_dot.py | 43 ++ make.bat | 35 ++ source/_ext/cerc_documenter.py | 159 +++++++ source/_static/alert.png | Bin 0 -> 1350 bytes source/_static/cat.png | Bin 0 -> 57361 bytes source/_static/custom.css | 7 + source/_templates/layout.html | 5 + source/conf.py | 77 ++++ source/index.rst | 750 +++++++++++++++++++++++++++++++++ 12 files changed, 1290 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README.md create mode 100644 create_dot.py create mode 100644 make.bat create mode 100644 source/_ext/cerc_documenter.py create mode 100644 source/_static/alert.png create mode 100644 source/_static/cat.png create mode 100644 source/_static/custom.css create mode 100644 source/_templates/layout.html create mode 100644 source/conf.py create mode 100644 source/index.rst diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a6f3eea --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +build +docs +.idea \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ce597ea --- /dev/null +++ b/Makefile @@ -0,0 +1,40 @@ +# Minimal makefile for Sphinx documentation +# +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build +UNAME_S := $(shell uname -s) +SED_FLAG = -i +ifeq ($(UNAME_S),Darwin) + SED_FLAG = -e +endif + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +all: % + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @echo 'Create the trees for the files' + @tree -I '__pycache__' ../cerc_persistence/cerc_persistence/models/ | convert -size 404x310 label:@- ./source/models.png + @tree -I '__pycache__' ../cerc_persistence/cerc_persistence/repositories/ | convert -size 496x394 -quality 100 label:@- ./source/repositories.png + @tree -I '__pycache__' ../cerc_persistence/cerc_persistence/ | convert -size 496x394 -quality 100 label:@- ./source/cerc_persistence.png + + @echo 'Create the uml' + @python3 ./create_dot.py + @dot -n ./source/uml.dot -Tpng -Nshape=rect -o ./source/dot.png + + + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + + @rm ./source/*.png + @rm ./source/uml.dot + diff --git a/README.md b/README.md new file mode 100644 index 0000000..43fa799 --- /dev/null +++ b/README.md @@ -0,0 +1,171 @@ +# libs_doc + +Automatic tool to create the libs' documentation + +# Windows compilation instructions using Windows Subsystem for Linux (WSL2) + +Open Powershell as an Administrator and run +``` +wsl.exe --install +``` + +This will enable the Windows Subsystem for Linux and install the command line version of Ubuntu. Once finished, restart your computer. When you login again, Ubuntu will open automatically. Enter in a new username and password for the Ubuntu installation. + +Update and upgrade the apt packages +``` +sudo apt update && sudo apt upgrade -y +``` + +Next, follow the steps outlined in the [Linux compilation section](#linux-compilation) below. + +Create a new directory called *cerc_docs* and navigate to the new directory +``` +mkdir cerc_docs && cd cerc_docs +``` + +Clone the *cerc_persistence_doc* repository +``` +git clone https://nextgenerations-cities.encs.concordia.ca/gitea/CERC/cerc_persistence_doc +``` + +Clone the *cerc_persistence* repository +``` +git clone https://nextgenerations-cities.encs.concordia.ca/gitea/CERC/cerc_persistence +``` + +Navigate to the *cerc_persistence_doc* directory +``` +cd cerc_persistence_doc +``` + +Compile the PDF +``` +make latexpdf +``` + +The compiled *cercpersistencereferencemanual.pdf* will be created in +``` +cerc_docs/cerc_persistence_doc/build/latex/ +``` + +# Mac compilation +Open terminal and install homebrew +``` +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" +``` + +Install Sphinx +``` +brew install sphinx-doc +echo 'export PATH="/usr/local/opt/sphinx-doc/bin:$PATH"' >> ~/.zshrc +``` + +Install latexmk +``` +sudo tlmgr install latexmk +``` + +Install BasicTeX +``` +brew install --cask basictex +``` + +Install texlive +``` +brew install texlive +``` + +Install Tree +``` +brew install tree +``` + +Install ImageMagick +``` +brew install imagemagick +``` + +Install Graphviz +``` +brew install graphviz +``` + +Create a new directory called *cerc_docs* and navigate to the new directory +``` +mkdir cerc_docs && cd cerc_docs +``` + +Clone the *cerc_persistence_doc* repository +``` +git clone https://nextgenerations-cities.encs.concordia.ca/gitea/CERC/cerc_persistence_doc +``` + +Clone the *cerc_persistence* repository +``` +git clone https://nextgenerations-cities.encs.concordia.ca/gitea/CERC/cerc_persistence +``` + +Navigate to the *cerc_persistence_doc* directory +``` +cd cerc_persistence_doc +``` + +Compile the PDF +``` +make latexpdf +``` + +The compiled *cercpersistencereferencemanual.pdf* will be created in +``` +cerc_docs/cerc_persistence_doc/build/latex/ +``` + + +# Linux compilation + +Some dependencies are needed in Linux systems, this manual cover only debian based distros (like Ubuntu), but the process should be similar for other Linux distributions + +- Build essential + +``` +sudo apt install build-essential +``` + +- Sphinx + +``` +sudo apt install sphinx +``` + +- Latex + +``` +sudo apt install texlive-latex-extra latexmk +``` + +- Tree +``` +sudo apt install tree +``` + +- ImageMagick +``` +sudo apt install libpng-dev libjpeg-dev libtiff-dev imagemagick +``` + +- Graphviz +``` +sudo apt install graphviz +``` + +Some changes are mandatory in the policymap of imagemagick (/etc/ImageMagick-6/policy.xml) + +Disable security policy by commenting or deleting the following line +``` + +``` +To prevent size errors change the width and height values to 16MP +``` + + +``` diff --git a/create_dot.py b/create_dot.py new file mode 100644 index 0000000..b438fd2 --- /dev/null +++ b/create_dot.py @@ -0,0 +1,43 @@ +from pathlib import Path +result = list(Path("../hub/hub/city_model_structure").rglob("*.[pP][yY]")) +dot_file = './source/uml.dot' +dot = 'digraph { \n ratio="fill"; \nsize="16.6,23.4!";\nmargin=0; \n \n' +class_line = None +for file_path in result: + with open(file_path) as file: + lines = file.readlines() + for line in lines: + if 'class ' == line[0:6]: + line = line.replace('class ', '"')\ + .replace(':', '"')\ + .replace('(', '" -> "')\ + .replace(')', '"[arrowhead="empty"] ')\ + .replace(' "', '')\ + .replace('->', '-> "') + class_line = line + if ' -> ' in line: + class_line = line.split(' -> ')[0] + if '"City"' == line[0:6]: + line = line[0:6] + ' [pos="0,1!"]\n' + dot += line + if 'def ' in line[2:8]: + if ' -> ' in line: + reference = line.split(' -> ')[1].replace(':', '').strip(' ()[]{},').replace('\n', '') + reference = reference.replace('Union', '').replace('List', '').replace('float', '').replace('str', '') + reference = reference.replace('bool', '').replace('None', '').replace(',', '') + reference = reference.replace(' ', '').replace('np.ndarray', '').replace('dict', '') + reference = reference.replace('[', '').replace(']', '').replace('Path', '').replace('pd.DataFrame', '') + reference = reference.replace('Trimesh', '').replace('}', '').replace('Edge)', '') + reference = reference.replace('(', '').replace(')', '') + + if 'Point' not in reference: + reference = reference.replace('int', '') + + if reference != '': + dot += f'"{reference}"-> {class_line}[arrowhead="diamond"] ' + + +dot += '}' + +with open(dot_file, 'w') as file: + file.write(dot.replace(' \n', ' ').replace('\n', ' ').replace('ABC, ', '').replace(' " ', ' ')) diff --git a/make.bat b/make.bat new file mode 100644 index 0000000..9534b01 --- /dev/null +++ b/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/source/_ext/cerc_documenter.py b/source/_ext/cerc_documenter.py new file mode 100644 index 0000000..febe71f --- /dev/null +++ b/source/_ext/cerc_documenter.py @@ -0,0 +1,159 @@ +from typing import Optional, Any + +from docutils.statemachine import StringList +from sphinx.application import Sphinx +from sphinx.ext.autodoc import ClassDocumenter, PropertyDocumenter, MethodDocumenter, bool_option +from sphinx.util import inspect +from sphinx.util.typing import restify + + +def setup(app: Sphinx) -> None: + app.setup_extension('sphinx.ext.autodoc') # Require autodoc extension + app.add_autodocumenter(CercClassDocumenter) + app.add_autodocumenter(CercPropertyDocumenter) + app.add_autodocumenter(CercMethodDocumenter) + + +class CercMethodDocumenter(MethodDocumenter): + objtype = 'cercmethod' + directivetype = 'method' + member_order = 50 + priority = MethodDocumenter.priority + 10 + + @staticmethod + def _get_type(sig_return): + types = sig_return.replace('Optional', '').replace('List', '').split('.') + prefix = '' + if types[0][0] in '[(': + prefix = types[0][0] + return f'{prefix}{types[len(types) -1]}' + + def format_signature(self, **kwargs: Any) -> str: + sig = super().format_signature(**kwargs) + if '->' in sig: + sig_pars = sig.split(' -> ') + return_type = CercMethodDocumenter._get_type(sig_pars[1]) + return_str = f'{return_type}' + if 'Optional' in sig_pars[1]: + return_str = f'Optional{return_str}' + return f'{sig_pars[0]} -> {return_str}' + return sig + + def add_content(self, more_content: Optional[StringList], no_docstring: bool = False) -> None: + source_name = self.get_sourcename() + docstrings = self.get_doc() + self.content_indent = ' ' + for i, line in enumerate(self.process_doc(docstrings)): + if ':return:' in line: + line = line.replace(':return:', '**Returns**') + elif ':param ' in line: + line = line.replace(':param ', '**Parameter** ') + line = line.replace(':', ' ') + elif ':alert:' in line: + line = line.replace(':alert:', '|alert|') + elif ':cat:' in line: + line = line.replace(':cat:', '|cat|') + self.add_line(f'{line}\n', source_name, i) + + +class CercPropertyDocumenter(PropertyDocumenter): + objtype = 'cercproperty' + directivetype = 'property' + member_order = 60 + priority = PropertyDocumenter.priority + 10 + + @staticmethod + def _get_type(annotations): + if len(annotations) == 0: + return annotations + return_str = str(annotations['return']).replace('typing.', '') + if 'Union' in return_str: + return_str = return_str.replace('Union', 'Optional').replace(', None', '').replace('None, ', '') + return_str = return_str.replace('NoneType, ','').replace(', NoneType', '') + if 'List' in return_str: + return_str = return_str.replace('typing.List', '').replace('List', '') + if "", '') + if '.' in return_str: + for i, c in enumerate(reversed(return_str)): + if c not in '])': + types_str = return_str.split('.') + if 'Optional' in return_str: + return_str = f'{types_str[0][0:8+i]}{types_str[len(types_str)-1]}' + else: + return_str = f'{types_str[0][0:i]}{types_str[len(types_str)-1]}' + break + return_str = return_str.replace('~', '').replace('Type', '') + return return_str + + def add_directive_header(self, sig: str) -> None: + name = self.format_name() + source_name = self.get_sourcename() + annotations = self.get_attr(self.object.fget, '__annotations__', None) + self.retann = CercPropertyDocumenter._get_type(annotations) + for i, sig_line in enumerate(sig.split("\n")): + self.add_line(f'.. py:property:: {name}({sig_line}) {(f" -> {self.retann}" if self.retann else "")}', source_name) + if self.objpath: + self.add_line(f' :module: {self.modname}', source_name) + if inspect.isabstractmethod(self.object): + self.add_line(' :abstractmethod:', source_name) + self.add_line(f' :property:', source_name) + + def add_content(self, more_content: Optional[StringList], no_docstring: bool = False) -> None: + source_name = self.get_sourcename() + docstrings = self.get_doc() + self.content_indent = ' ' + if not no_docstring: + if not docstrings: + docstrings.append([]) + for i, line in enumerate(self.process_doc(docstrings)): + if ':return:' in line: + line = line.replace(':return:', '**Returns**') + elif ':alert:' in line: + line = line.replace(':alert:', '|alert|') + self.add_line(f'{line}\n', source_name, i) + + +class CercClassDocumenter(ClassDocumenter): + objtype = 'cercclass' + directivetype = 'class' + priority = 10 + ClassDocumenter.priority + option_spec = dict(ClassDocumenter.option_spec) + option_spec['hex'] = bool_option + + def get_bases(self, source_name): + bases = [] + if hasattr(self.object, '__orig_bases__') and len(self.object.__orig_bases__): + bases = [restify(cls) for cls in self.object.__orig_bases__] + elif hasattr(self.object, '__bases__') and len(self.object.__bases__): + # A normal class + bases = [restify(cls) for cls in self.object.__bases__] + if ':class:`object`' in bases: + bases.remove(':class:`object`') + cleaned_bases = [] + for base in bases: + base_tmp = base.replace('`', '').split('.') + base_tmp = base_tmp[len(base_tmp)-1] + cleaned_bases.append(base_tmp) + if len(cleaned_bases) != 0: + self.add_line(' Inherit: %s' % ', '.join(cleaned_bases), source_name) + self.add_line(' ', source_name) + + def add_directive_header(self, sig: str) -> None: + prefix = f'.. py:class:: ' + name = self.format_name() + source_name = self.get_sourcename() + self.add_line('%s%s%s' % (prefix, name, sig), source_name) + if self.analyzer and '.'.join(self.objpath) in self.analyzer.finals: + self.add_line(' :final:', source_name) + self.get_bases(source_name) + + def add_content(self, more_content: Optional[StringList], no_docstring: bool = False) -> None: + source_name = self.get_sourcename() + docstrings = self.get_doc() + self.content_indent = ' ' + if not no_docstring: + if not docstrings: + docstrings.append([]) + for i, line in enumerate(self.process_doc(docstrings)): + self.add_line(line, source_name) diff --git a/source/_static/alert.png b/source/_static/alert.png new file mode 100644 index 0000000000000000000000000000000000000000..867315df62ad769d2156d0ede4875e16bacad239 GIT binary patch literal 1350 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 +{% endblock %} \ No newline at end of file diff --git a/source/conf.py b/source/conf.py new file mode 100644 index 0000000..857b9c5 --- /dev/null +++ b/source/conf.py @@ -0,0 +1,77 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys + +sys.path.insert(0, os.path.abspath('../../hub/')) +sys.path.append(os.path.abspath("./_ext")) +sys.path.append(os.path.abspath("./_static")) +sys.path.append(os.path.abspath(".")) + +from hub.version import __version__ + +sys.setrecursionlimit(1500) + + +# -- Project information ----------------------------------------------------- + +project = 'CERC hub reference manual' +copyright = '2021, Guille Gutierrez and Pilar Monsalvete' +author = 'CERC Next-Generation Cities' + +# The full version, including alpha/beta/rc tags +release = __version__ + + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. 'sphinx.ext.autodoc', +extensions = [ + 'sphinx.ext.autodoc', + 'cerc_documenter' +] +autodoc_mock_imports = ["pyproj", "numpy", "trimesh", "Node", "Edge", "pandas", "typing", "xmltodict", "geomeppy", + "parseidf", "rhino3dm", "pyecore", "EPackage", "pyecore.ecore", "geopandas", "shapely", + "hub.catalog_factories.greenery.greenery_catalog", "catalog_factories.greenery.greenery_catalog" + ] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +source_suffix = ['.rst', '.md'] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = [] + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'sphinx_rtd_theme' + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +todo_include_todos = True + +master_doc = 'index' + +latex_elements = {'extraclassoptions': 'openany,oneside'} diff --git a/source/index.rst b/source/index.rst new file mode 100644 index 0000000..0e645d8 --- /dev/null +++ b/source/index.rst @@ -0,0 +1,750 @@ +.. _how to use the hub: https://todo/ + +.. _development manual: https://todo/ + +.. _catalogs manual: https://todo + +.. |alert| image:: ./_static/alert.png + :width: 15 + :alt: Alert + +.. |cat| image:: ./_static/cat.png + :width: 30 + :alt: Cat + +CERC HUB' reference manual +===================================== +.. toctree:: + :maxdepth: 4 + :caption: Contents: + +CERC HUB' reference manual +===================================== +Authors +************************* + +* Guillermo Gutierrez Morote +* Pilar Monsalvete Alvarez de Uribarri + +Contributors +************************* + +* Seyedehrabeeh Hosseinihaghighi +* Milad Aghamohamadnia +* Peter Yefi +* Koa Wells +* Sanam Dabirian +* Soroush Samareh Abolhassani + +About the HUB +************************* + +This document contains the essential documentation for the CERC HUB, a set of classes, factories, and helpers that simplifies the research at urban scale in multiples domains; these components are designed around three central axes, **extensibility**, **code clarity** and **consistency** as we intend to allow domain experts to perform urban scale simulations with multiple programs and enrich the city from several data sources. +HUB is composed of four main components: **city model structure**, **factories**, **catalogs** and, **helpers**. + +- **City model structure** is the set of classes designed to be familiar to the domain experts; this familiarity will be possible thanks to using a *standard-based* approach in order to flatten the learning curve. These classes compose the CERC *data model* that provides a simple way to study cities at an urban scale after the enriching process. +- **Factories** are pieces of code in charge of import and export information in and out of the **data model** they will perform the needed conversions to read or write different formats such as epw weather files, insel files or citygml. these factories are mean to be extended, allowing the HUB ecosystem to expand with new formats. +- **Catalogs** are datasets used in the enrichment of the city that can also be used by third party consumers like researchers or simulations software. +- **Helpers** are sets of general tools used by any of the other parts and does not fit in any of the previous categories. + +City model structure +===================================== + +The **city model structure** contains the common data model intended to represent a city digital twin, CERC team and contributors, will further extend these classes to include other domains, in the following sections, researchers and developers could find information about the methods and properties exposed by the city model structure classes. + +.. important:: + + Please take a look to HUB tutorial to see how to use HUB for your own research + + [`how to use the hub`_] + +City model structure UML +************************ + +.. image:: dot.png + :width: 575 + +.. raw:: latex + + \clearpage + +Folder structure +****************** + +city_model_structure +^^^^^^^^^^^^^^^^^^^^^^ +Main city objects. + +.. image:: ./city_model_structure.png + :width: 200 + +attributes +^^^^^^^^^^^^^^^^^^^^^^ +Geometrical and non physical components of the city. + +.. image:: ./attributes.png + :width: 200 + +building_demand +^^^^^^^^^^^^^^^^^^^^^^ +Main classes to model building energy demand. + +.. image:: ./building_demand.png + :width: 300 + +energy_systems +^^^^^^^^^^^^^^^^^^^^^^ +Main classes to model energy systems. + +.. image:: ./energy_systems.png + :width: 300 + +iot +^^^^^^^^^^^^^^^^^^^^^^ +Classes to model IoT devices. + +.. image:: ./iot.png + :width: 250 + +.. raw:: latex + + \clearpage + +full schema +^^^^^^^^^^^^^^^^^^^^^^ + +.. image:: ./city_model_structure_complete.png + :width: 300 + +Classes +**************************** + +City +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.city.City + :members: + +CityObject +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.city_object.CityObject + :members: + +City Objects Cluster +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.city_objects_cluster.CityObjectsCluster + :members: + +Building +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.building.Building + :members: + +Parts Consisting Building +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.parts_consisting_building.PartsConsistingBuilding + :members: + +Buildings Cluster +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.buildings_cluster.BuildingsCluster + :members: + +Network +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.network.Network + :members: + +Level of detail +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.level_of_detail.LevelOfDetail + :members: + +Edge +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.attributes.edge.Edge + :members: + +Node +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.attributes.node.Node + :members: + +Plane +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.attributes.plane.Plane + :members: + +Point +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.attributes.point.Point + :members: + +Polygon +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.attributes.polygon.Polygon + :members: + +Polyhedron +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.attributes.polyhedron.Polyhedron + :members: + +Record +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.attributes.record.Record + :members: + +Schedule +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.attributes.schedule.Schedule + :members: + +Time Series +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.attributes.time_series.TimeSeries + :members: + +Appliances +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.building_demand.appliances.Appliances + :members: + +Household +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.building_demand.household.Household + :members: + +Internal Gain +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.building_demand.internal_gain.InternalGain + :members: + +Internal Zone +^^^^^^^^^^^^^^^^^^^^^^ +.. note:: The internal zone class represents each of the internal zones described in the geometry when imported. + + This imported geometry can be later on divided in different thermal zones in a workflow (e.g. if the building with no interiors defined (LoD up to 3), it will produce one interior zone. Later on, this can be divided by storey and create one thermal zone per each). + + Also, several usages can be associated with that internal zone. This usages are described in the Usage class, which has not only the parameters that describe each usage, but also the percentage of the internal zone volume that is affected by that specific use. + +.. autocercclass:: hub.city_model_structure.building_demand.internal_zone.InternalZone + :members: + +Layer +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.building_demand.layer.Layer + :members: + +Lighting +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.building_demand.lighting.Lighting + :members: + +Occupancy +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.building_demand.occupancy.Occupancy + :members: + +Storey +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.building_demand.storey.Storey + :members: + +Surface +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.building_demand.surface.Surface + :members: + +Thermal Boundary +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.building_demand.thermal_boundary.ThermalBoundary + :members: + +Thermal Control +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.building_demand.thermal_control.ThermalControl + :members: + +Thermal Opening +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.building_demand.thermal_opening.ThermalOpening + :members: + +Thermal Zone +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.building_demand.thermal_zone.ThermalZone + :members: + +Usage +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.building_demand.usage.Usage + :members: + +Plant +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.greenery.plant.Plant + :members: + +Soil +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.greenery.soil.Soil + :members: + +Vegetation +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.greenery.vegetation.Vegetation + :members: + +Sensor +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.iot.sensor.Sensor + :members: + +Sensor Measure +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.iot.sensor_measure.SensorMeasure + :members: + +Sensor Type +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.iot.sensor_type.SensorType + :members: + +Station +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.city_model_structure.iot.station.Station + :members: + +Factories +===================================== + +Factories are divided into Imports and Exports, depending on if they are used to enrich (Import) the *city model structure* or to deliver third party defined formats (Export) such as **INSEL** or **IDF** file, the factories could be extended to include new imports and outputs providing an additional level of abstraction to researchers. + +|alert| Please, note that the private methods, the ones starting with an underscore character (_), documented in the factories are mean to be called by using the **handler** parameter; this parameter must contain the method name without the _ character. + +.. note:: + For instance, to use _citygml handler in the Geometry factory, the handler parameter value needs to be 'citygml' + +|alert| **This documentation includes only the base factories classes as these are the intended entry points for the Import/Export functionality.** + +.. important:: + + Please refer to the development manual if you want to create your own factories. + + [`development manual`_] + +.. raw:: latex + + \clearpage + +Folder structure +****************** + +Imports +^^^^^^^^^^^^^^^^^^^^^^ + +.. image:: ./imports.png + :width: 250 + +Exports +^^^^^^^^^^^^^^^^^^^^^^ + +.. image:: ./exports.png + :width: 250 + +.. raw:: latex + + \clearpage + + +Imports Classes +*************** + +Construction Factory +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.imports.construction_factory.ConstructionFactory + :members: + :private-members: + +Geometry Factory +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.imports.geometry_factory.GeometryFactory + :members: + :private-members: + +Usage Factory +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.imports.usage_factory.UsageFactory + :members: + :private-members: + +Weather Factory +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.imports.weather_factory.WeatherFactory + :members: + :private-members: + +.. raw:: latex + + \clearpage + +Exports +******* + +Export Factory +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.exports.exports_factory.ExportsFactory + :members: + :private-members: + +Catalogs +===================================== + +In its simplest form, a catalogue is a file or group of files that provide technical and/or commercial information regarding components that form a system within any domain. The components are listed with relevant details and associated data is tabulated. Also listed are the dominant/standard configurations in which the components may be used to satisfy use-cases/output requirements (as supplied by component manufacturer/standard organisations). + + +.. note:: + Examples, Heat Pump catalogue should consist of the heat pump models produced, heat pump type, manufacturer name, output temperatures, nominal capacities, typical configurations for the heat pumps (e.g., configurations when used for space heating only, Domestic Hot Water/DHW purposes only, both space heating and DHW, combinations with solar thermal/PV), storage tank data, circulation pump data, compressor type and associated technical data, valve types etc. + +.. important:: + + Please refer to the catalogs manual if you want to create or extend your own catalogs. + + [`catalogs manual`_] + +Folder structure +****************** + +Catalogs +^^^^^^^^^^^^^^^^^^^^^^ + +.. image:: ./catalogs.png + :width: 240 + +Catalog Base Class +******************* + +Catalog +^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.catalog.Catalog + :members: + +.. raw:: latex + + \clearpage + +Greenery +*************** + +Greenery Catalog Factory +^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.greenery_catalog_factory.GreeneryCatalogFactory + :members: + :private-members: + +Greenery Content Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.greenery.content.Content + :members: + +Greenery Plant Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.greenery.plant.Plant + :members: + +Greenery Plant Percentage Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.greenery.plant_percentage.PlantPercentage + :members: + +Greenery Plant Soil Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.greenery.soil.Soil + :members: + +Greenery Vegetation Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.greenery.vegetation.Vegetation + :members: + +.. raw:: latex + + \clearpage + +Construction +*************** + +Construction Catalog Factory +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.construction_catalog_factory.ConstructionCatalogFactory + :members: + :private-members: + +Construction Content Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.construction.content.Content + :members: + +Construction Archetype Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.construction.archetype.Archetype + :members: + +Construction Construction Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.construction.construction.Construction + :members: + +Construction Layer Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.construction.layer.Layer + :members: + +Construction Material Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.construction.material.Material + :members: + +Construction Window Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.construction.window.Window + :members: + +.. raw:: latex + + \clearpage + +Costs +*************** + +Costs Catalog Factory +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.costs_catalog_factory.CostsCatalogFactory + :members: + :private-members: + +Costs Content Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.cost.content.Content + :members: + +Costs Archetype Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.cost.archetype.Archetype + :members: + +Costs Capital Cost Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.cost.capital_cost.CapitalCost + :members: + +Costs Chapter Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.cost.chapter.Chapter + :members: + +Costs Fuel Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.cost.fuel.Fuel + :members: + +Costs Income Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.cost.income.Income + :members: + +Costs Item Description Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.cost.item_description.ItemDescription + :members: + +Costs Operational Cost Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.cost.operational_cost.OperationalCost + :members: + +.. raw:: latex + + \clearpage + +Energy Systems +*************** + +Energy Systems Catalog Factory +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.energy_systems_catalog_factory.EnergySystemsCatalogFactory + :members: + :private-members: + +Energy Systems Content Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.energy_systems.content.Content + :members: + +Energy Systems Archetype Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.energy_systems.archetype.Archetype + :members: + +Energy Systems Distribution System Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.energy_systems.distribution_system.DistributionSystem + :members: + +Energy Systems Emission System Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.energy_systems.emission_system.EmissionSystem + :members: + +Energy Systems Generation System Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.energy_systems.generation_system.GenerationSystem + :members: + +Energy Systems Energy Systems Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.energy_systems.system.System + :members: + +.. raw:: latex + + \clearpage + +Usage +************ + +Usage Catalog Factory +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.usage_catalog_factory.UsageCatalogFactory + :members: + :private-members: + +Usage Content Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.usages.content.Content + :members: + +Usage Appliances Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.usages.appliances.Appliances + :members: + +Usage Content Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.usages.content.Content + :members: + +Usage Domestic Hot Water Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.usages.domestic_hot_water.DomesticHotWater + :members: + +Usage Internal Gain Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.usages.internal_gain.InternalGain + :members: + +Usage Lighting Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.usages.lighting.Lighting + :members: + +Usage Occupancy Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.usages.occupancy.Occupancy + :members: + +Usage Schedule Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.usages.schedule.Schedule + :members: + +Usage Thermal Control Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.usages.thermal_control.ThermalControl + :members: + +Usage Usage Data Model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autocercclass:: hub.catalog_factories.data_models.usages.usage.Usage + :members: + +.. raw:: latex + + \clearpage + + +Helpers +======= + +CERC hub provides a set of *helpers* that will simplify certain operations; these helpers are mean to be freely used at any point and therefore could be consumed from several places. + +Folder structure +****************** + +.. image:: ./helpers.png + :width: 300 + +.. raw:: latex + + \clearpage + +Configuration Helper +******************** +.. autocercclass:: hub.helpers.configuration_helper.ConfigurationHelper + :members: + +.. raw:: latex + + \clearpage + +Constants +******************** +.. include:: constants.rst + +Geometry Helper +******************** +.. autocercclass:: hub.helpers.geometry_helper.GeometryHelper + :members: + +Location +******************** +.. autocercclass:: hub.helpers.location.Location + :members: + +Dictionaries +******************** +.. autocercclass:: hub.helpers.dictionaries.Dictionaries + :members: + +Additional Files +==================== + +Readme +*********** + +`README.md `_ + +License +************ + +`LICENSE.md `_ + +Code of conduct +************************ + +`CODE_OF_CONDUCT.md `_ + +How to contribute +************************ + +`CONTRIBUTING.md `_ + +Coding style +************************ + +`PYGUIDE.md `_ + +.. raw:: latex + + \tiny \ No newline at end of file