This commit is contained in:
Peter Yefi 2022-03-18 11:28:44 -04:00
commit fdbf1817c3
46 changed files with 111515 additions and 949 deletions

32
catalogs/catalog.py Normal file
View File

@ -0,0 +1,32 @@
"""
Catalog base class
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
class Catalog:
"""
Catalog name
"""
@property
def names(self):
"""
Base property to return the catalog entries names
:return: not implemented error
"""
raise NotImplementedError
def entries(self, category=None):
"""
Base property to return the catalog entries
:return: not implemented error
"""
raise NotImplementedError
def get_entry(self, name):
"""
Base property to return the catalog entry matching the given name
:return: not implemented error
"""
raise NotImplementedError

View File

@ -0,0 +1,33 @@
"""
Greenery catalog content
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
class GreeneryContent:
def __init__(self, vegetations, plants, soils):
self._vegetations = vegetations
self._plants = plants
self._soils = soils
@property
def vegetations(self):
"""
All vegetation in the catalog
"""
return self._vegetations
@property
def plants(self):
"""
All plants in the catalog
"""
return self._plants
@property
def soils(self):
"""
All soils in the catalog
"""
return self._soils

View File

@ -0,0 +1,85 @@
"""
Greenery catalog data model Plant class
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
from catalogs.data_model.greenery.soil import Soil as libs_soil
class Plant:
def __init__(self, category, plant):
self._name = plant.name
self._category = category
self._height = plant.height
self._leaf_area_index = plant.leafAreaIndex
self._leaf_reflectivity = plant.leafReflectivity
self._leaf_emissivity = plant.leafEmissivity
self._minimal_stomatal_resistance = plant.minimalStomatalResistance
self._co2_sequestration = plant.co2Sequestration
self._grows_on = []
for soil in plant.growsOn:
self._grows_on.append(libs_soil(soil))
@property
def name(self):
"""
Get plant name
"""
return self._name
@property
def category(self):
"""
Get plant category name
"""
return self._category
@property
def height(self):
"""
Get plant height
"""
return self._height
@property
def leaf_area_index(self):
"""
Get plant leaf area index
"""
return self._leaf_area_index
@property
def leaf_reflectivity(self):
"""
Get plant leaf area index
"""
return self._leaf_reflectivity
@property
def leaf_emissivity(self):
"""
Get plant leaf emissivity
"""
return self._leaf_emissivity
@property
def minimal_stomatal_resistance(self):
"""
Get plant minimal stomatal resistance
"""
return self._minimal_stomatal_resistance
@property
def co2_sequestration(self):
"""
Get plant co2 sequestration capacity
"""
return self._co2_sequestration
@property
def grows_on(self) -> [libs_soil]:
"""
Get plant compatible soils
"""
return self._grows_on

View File

@ -0,0 +1,17 @@
"""
Greenery catalog data model Plant percentage class
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
from catalogs.data_model.greenery.plant import Plant as libs_plant
class PlantPercentage(libs_plant):
def __init__(self, percentage, plant_category, plant):
super().__init__(plant_category, plant)
self._percentage = percentage
@property
def percentage(self):
return self._percentage

View File

@ -0,0 +1,96 @@
"""
Greenery catalog data model Soil class
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
class Soil:
def __init__(self, soil):
self._name = soil.name
self._roughness = soil.roughness
self._dry_conductivity = soil.conductivityOfDrySoil
self._dry_density = soil.densityOfDrySoil
self._dry_specific_heat = soil.specificHeatOfDrySoil
self._thermal_absorptance = soil.thermalAbsorptance
self._solar_absorptance = soil.solarAbsorptance
self._visible_absorptance = soil.visibleAbsorptance
self._saturation_volumetric_moisture_content = soil.saturationVolumetricMoistureContent
self._residual_volumetric_moisture_content = soil.residualVolumetricMoistureContent
self._initial_volumetric_moisture_content = soil.initialVolumetricMoistureContent
@property
def name(self):
"""
Get soil name
"""
return self._name
@property
def roughness(self):
"""
Get soil roughness
"""
return self._roughness
@property
def dry_conductivity(self):
"""
Get soil dry conductivity
"""
return self._dry_conductivity
@property
def dry_density(self):
"""
Get soil dry density
"""
return self._dry_density
@property
def dry_specific_heat(self):
"""
Get soil dry specific heat
"""
return self._dry_specific_heat
@property
def thermal_absorptance(self):
"""
Get soil thermal absortance
"""
return self._thermal_absorptance
@property
def solar_absorptance(self):
"""
Get soil solar absortance
"""
return self._solar_absorptance
@property
def visible_absorptance(self):
"""
Get soil visible absortance
"""
return self._visible_absorptance
@property
def saturation_volumetric_moisture_content(self):
"""
Get soil saturation volumetric moisture content
"""
return self._saturation_volumetric_moisture_content
@property
def residual_volumetric_moisture_content(self):
"""
Get soil residual volumetric moisture content
"""
return self._residual_volumetric_moisture_content
@property
def initial_volumetric_moisture_content(self):
"""
Get soil initial volumetric moisture content
"""
return self._initial_volumetric_moisture_content

View File

@ -0,0 +1,151 @@
"""
Greenery catalog data model Vegetation class
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
from catalogs.data_model.greenery.plant_percentage import PlantPercentage
class Vegetation:
def __init__(self, category, vegetation, plant_percentages):
self._name = vegetation.name
self._category = category
self._soil_thickness = vegetation.thicknessOfSoil
self._management = vegetation.management
self._air_gap = vegetation.airGap
self._soil_name = vegetation.soil.name
self._soil_roughness = vegetation.soil.roughness
self._dry_soil_conductivity = vegetation.soil.conductivityOfDrySoil
self._dry_soil_density = vegetation.soil.densityOfDrySoil
self._dry_soil_specific_heat = vegetation.soil.specificHeatOfDrySoil
self._soil_thermal_absorptance = vegetation.soil.thermalAbsorptance
self._soil_solar_absorptance = vegetation.soil.solarAbsorptance
self._soil_visible_absorptance = vegetation.soil.visibleAbsorptance
self._soil_saturation_volumetric_moisture_content = vegetation.soil.saturationVolumetricMoistureContent
self._soil_residual_volumetric_moisture_content = vegetation.soil.residualVolumetricMoistureContent
self._soil_initial_volumetric_moisture_content = vegetation.soil.initialVolumetricMoistureContent
self._plant_percentages = plant_percentages
@property
def name(self):
"""
Get vegetation name
"""
return self._name
@property
def category(self):
"""
Get vegetation category
"""
return self._category
@property
def soil_thickness(self):
"""
Get soil thickness
"""
return self._soil_thickness
@property
def management(self):
"""
Get management
"""
return self._management
@property
def air_gap(self):
"""
Get air gap
"""
return self._air_gap
@property
def plant_percentages(self) -> [PlantPercentage]:
"""
Get plant percentages
"""
percentage = 0.0
for plant_percentage in self._plant_percentages:
percentage += float(plant_percentage.percentage)
if percentage > 100:
raise ValueError('the plant percentage in this vegetation is over 100%')
return self._plant_percentages
@property
def soil_name(self):
"""
Get soil name
"""
return self._soil_name
@property
def soil_roughness(self):
"""
Get soil roughness
"""
return self._soil_roughness
@property
def dry_soil_conductivity(self):
"""
Get soil dry conductivity
"""
return self._dry_soil_conductivity
@property
def dry_soil_density(self):
"""
Get soil dry density
"""
return self._dry_soil_density
@property
def dry_soil_specific_heat(self):
"""
Get soil dry specific heat
"""
return self._dry_soil_specific_heat
@property
def soil_thermal_absorptance(self):
"""
Get soil thermal absortance
"""
return self._soil_thermal_absorptance
@property
def soil_solar_absorptance(self):
"""
Get soil solar absortance
"""
return self._soil_solar_absorptance
@property
def soil_visible_absorptance(self):
"""
Get soil visible absortance
"""
return self._soil_visible_absorptance
@property
def soil_saturation_volumetric_moisture_content(self):
"""
Get soil saturation volumetric moisture content
"""
return self._soil_saturation_volumetric_moisture_content
@property
def soil_residual_volumetric_moisture_content(self):
"""
Get soil residual volumetric moisture content
"""
return self._soil_residual_volumetric_moisture_content
@property
def soil_initial_volumetric_moisture_content(self):
"""
Get soil initial volumetric moisture content
"""
return self._soil_initial_volumetric_moisture_content

View File

@ -0,0 +1,268 @@
<?xml version="1.0" encoding="UTF-8"?>
<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="greenerycatalog" nsURI="http://ca.concordia/greenerycatalog"
nsPrefix="greenery">
<eClassifiers xsi:type="ecore:EClass" name="Soil">
<eAnnotations source="http://www.eclipse.org/emf/2002/Ecore">
<details key="constraints" value="nonNegative"/>
</eAnnotations>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
defaultValueLiteral=""/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="roughness" eType="#//Roughness"
defaultValueLiteral="MediumRough">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="defines the relative roughness of a particular material layer. This parameter only influences the convection coefficients, more specifically the exterior convection coefficient. A nominal value is expected in with the options being &quot;VeryRough&quot;, &quot;Rough&quot;, &quot;MediumRough&quot;, &quot;MediumSmooth&quot;, &quot;Smooth&quot;, and &quot;VerySmooth&quot; in order of roughest to smoothest options."/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="conductivityOfDrySoil"
lowerBound="1" eType="ecore:EDataType platform:/plugin/de.hftstuttgart.cityunits.model/model/Quantities.ecore#//Quantity"
defaultValueLiteral="1.0 W/(m*K)">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="Thermal conductivity W/(m-K). Range: 0.2 to 1.5"/>
</eAnnotations>
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0.2"/>
<details key="max" value="1.5"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="densityOfDrySoil" eType="ecore:EDataType platform:/plugin/de.hftstuttgart.cityunits.model/model/Quantities.ecore#//Quantity"
defaultValueLiteral="1100 kg/m³">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="Density in kg/m³. "/>
</eAnnotations>
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0.1"/>
<details key="max" value="10000"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="specificHeatOfDrySoil"
eType="ecore:EDataType platform:/plugin/de.hftstuttgart.cityunits.model/model/Quantities.ecore#//Quantity"
defaultValueLiteral="1200 J/(kg*K)">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="in units of J/(kg-K). Range(300 to 2000)"/>
</eAnnotations>
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0.2"/>
<details key="max" value="2000"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="thermalAbsorptance" eType="ecore:EDataType platform:/plugin/de.hftstuttgart.cityunits.model/model/Quantities.ecore#//Quantity"
defaultValueLiteral="0.9">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="the fraction of incident long wavelength (>2.5 microns) radiation that is absorbed by the material. This parameter is used when calculating the long wavelength radiant exchange between various surfaces and affects the surface heat balances (both inside and outside as appropriate). For long wavelength radiant exchange, thermal emissivity and thermal emittance are equal to thermal absorptance. Range: 0 to 1"/>
</eAnnotations>
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0.0"/>
<details key="max" value="1.0"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="solarAbsorptance" eType="ecore:EDataType platform:/plugin/de.hftstuttgart.cityunits.model/model/Quantities.ecore#//Quantity"
defaultValueLiteral="0.7">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="the fraction of incident solar radiation that is absorbed by the material.&#xA;Solar radiation (0.3 to 2.537 microns) includes the visible spectrum as well as infrared and ultraviolet wavelengths. This parameter is used when calculating the amount of incident solar radiation absorbed by various surfaces and affects the surface heat balances (both inside and outside as appropriate). If solar reflectance (or reflectivity) data is available, then absorptance is equal to 1.0 minus reflectance (for opaque materials).&#xA;Range: 0 to 1"/>
</eAnnotations>
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0.0"/>
<details key="max" value="1.0"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="visibleAbsorptance" eType="ecore:EDataType platform:/plugin/de.hftstuttgart.cityunits.model/model/Quantities.ecore#//Quantity"
defaultValueLiteral="0.75">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="The visible absorptance field in the Material input syntax represents the fraction of incident visible wavelength radiation that is absorbed by the material.&#xA;Visible wavelength radiation (0.37 to 0.78 microns weighted by photopic response) is slightly different than solar radiation in that the visible band of wavelengths is much more narrow while solar radiation includes the visible spectrum as well as infrared and ultraviolet wavelengths.&#xA;This parameter is used when calculating the amount of incident visible radiation absorbed by various surfaces and affects the surface heat balances (both inside and outside as appropriate) as well as the daylighting calculations. If visible reflectance (or reflectivity) data is available, then absorptance is equal to 1.0 minus reflectance (for opaque materials).&#xA;Range: 0.5 to 1.0"/>
</eAnnotations>
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0.5"/>
<details key="max" value="1.0"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="saturationVolumetricMoistureContent"
eType="ecore:EDataType platform:/plugin/de.hftstuttgart.cityunits.model/model/Quantities.ecore#//Quantity"
defaultValueLiteral="0.0">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="input of the saturation moisture content of the soil layer. Range: 0.1 to 0.5"/>
</eAnnotations>
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0.1"/>
<details key="max" value="0.5"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="residualVolumetricMoistureContent"
eType="ecore:EDataType platform:/plugin/de.hftstuttgart.cityunits.model/model/Quantities.ecore#//Quantity"
defaultValueLiteral="0.05">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="Input of the residual moisture content of the soil layer. Range: 0.01 to 0.1"/>
</eAnnotations>
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0.01"/>
<details key="max" value="0.1"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="initialVolumetricMoistureContent"
eType="ecore:EDataType platform:/plugin/de.hftstuttgart.cityunits.model/model/Quantities.ecore#//Quantity"
defaultValueLiteral="0.1">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="Range: 0.05 to 0.5"/>
</eAnnotations>
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0.05"/>
<details key="max" value="0.5"/>
</eAnnotations>
</eStructuralFeatures>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="Plant">
<eStructuralFeatures xsi:type="ecore:EAttribute" name="name" lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="height" lowerBound="1"
eType="ecore:EDataType platform:/plugin/de.hftstuttgart.cityunits.model/model/Quantities.ecore#//Quantity"
defaultValueLiteral="0.1 m">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="Maximum height of plants. Range: 0.005 to 1 m"/>
</eAnnotations>
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0.005"/>
<details key="max" value="1.0"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="leafAreaIndex" lowerBound="1"
eType="ecore:EDataType platform:/plugin/de.hftstuttgart.cityunits.model/model/Quantities.ecore#//Quantity"
defaultValueLiteral="2.5">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="Leaf area per unit area of soil surface. Range: 0.001 to 5.0 m²/m²"/>
</eAnnotations>
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0.001"/>
<details key="max" value="5.0"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="leafReflectivity" lowerBound="1"
eType="ecore:EDataType platform:/plugin/de.hftstuttgart.cityunits.model/model/Quantities.ecore#//Quantity"
defaultValueLiteral="0.1">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="Represents the fraction of incident solar radiation that is reflected by the individual leaf surfaces (albedo).&#xA;Range: 0.05 to 0.5"/>
</eAnnotations>
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0.05"/>
<details key="max" value="0.5"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="leafEmissivity" lowerBound="1"
eType="ecore:EDataType platform:/plugin/de.hftstuttgart.cityunits.model/model/Quantities.ecore#//Quantity"
defaultValueLiteral="0.9">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="Ratio of thermal radiation emitted from leaf surfaces to that emitted by an ideal black body at the same temperature.&#xA;This parameter is used when calculating the long wavelength radiant exchange at the leaf surfaces.&#xA;Range: 0.8 to 1"/>
</eAnnotations>
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0.8"/>
<details key="max" value="1.0"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="minimalStomatalResistance"
lowerBound="1" eType="ecore:EDataType platform:/plugin/de.hftstuttgart.cityunits.model/model/Quantities.ecore#//Quantity"
defaultValueLiteral="100.0 s/m">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="Resistance of the plants to moisture transport.&#xA;Plants with low values of stomatal resistance will result in higher evapotranspiration rates than plants with high resistance.&#xA;Range: 50 to 300 m/s"/>
</eAnnotations>
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="50.0"/>
<details key="max" value="300.0"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EReference" name="growsOn" lowerBound="1"
upperBound="-1" eType="#//Soil"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="co2Sequestration" eType="ecore:EDataType platform:/plugin/de.hftstuttgart.cityunits.model/model/Quantities.ecore#//Quantity"
defaultValueLiteral="kgCO₂eq"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="SupportEnvelope">
<eStructuralFeatures xsi:type="ecore:EAttribute" name="roughness" eType="#//Roughness"
defaultValueLiteral="MediumRough"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="solarAbsorptance" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDouble"
defaultValueLiteral="0.0"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="conductivity" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDouble"
defaultValueLiteral="0.0"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="visibleAbsorptance" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDouble"
defaultValueLiteral="0.0"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="specificHeat" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDouble"
defaultValueLiteral="0.0"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="density" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDouble"
defaultValueLiteral="0.0"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="thermalAbsorptance" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDouble"
defaultValueLiteral="0.0"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="GreeneryCatalog">
<eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="description" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="source" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
<eStructuralFeatures xsi:type="ecore:EReference" name="plantCategories" lowerBound="1"
upperBound="-1" eType="#//PlantCategory" containment="true"/>
<eStructuralFeatures xsi:type="ecore:EReference" name="vegetationCategories" lowerBound="1"
upperBound="-1" eType="#//VegetationCategory" containment="true"/>
<eStructuralFeatures xsi:type="ecore:EReference" name="soils" upperBound="-1"
eType="#//Soil" containment="true"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="PlantCategory">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="Excluding (that is non-overlapping) categories like Trees, Hedeges, Grasses that help users finding a specific biol. plant species."/>
</eAnnotations>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
<eStructuralFeatures xsi:type="ecore:EReference" name="plants" upperBound="-1"
eType="#//Plant" containment="true"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="IrrigationSchedule">
<eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="Vegetation">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="Plant life or total plant cover (as of an area)"/>
</eAnnotations>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="name" lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="thicknessOfSoil" lowerBound="1"
eType="ecore:EDataType platform:/plugin/de.hftstuttgart.cityunits.model/model/Quantities.ecore#//Quantity"
defaultValueLiteral="20 cm">
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0"/>
<details key="max" value="1000"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EReference" name="soil" lowerBound="1" eType="#//Soil"/>
<eStructuralFeatures xsi:type="ecore:EReference" name="plants" lowerBound="1"
upperBound="-1" eType="#//PlantPercentage" containment="true"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="management" lowerBound="1"
eType="#//Management" defaultValueLiteral="NA"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="airGap" lowerBound="1"
eType="ecore:EDataType platform:/plugin/de.hftstuttgart.cityunits.model/model/Quantities.ecore#//Quantity"
defaultValueLiteral="0.0 cm"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="VegetationCategory">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="Excluding (that is non-overlapping) categories to help users finding a specific vegetation template."/>
</eAnnotations>
<eStructuralFeatures xsi:type="ecore:EReference" name="vegetationTemplates" upperBound="-1"
eType="#//Vegetation" containment="true"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EEnum" name="Management">
<eLiterals name="Intensive"/>
<eLiterals name="Extensive" value="1"/>
<eLiterals name="SemiIntensive" value="2"/>
<eLiterals name="NA" value="3"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="PlantPercentage">
<eStructuralFeatures xsi:type="ecore:EAttribute" name="percentage" lowerBound="1"
eType="ecore:EDataType platform:/plugin/de.hftstuttgart.cityunits.model/model/Quantities.ecore#//Quantity"
defaultValueLiteral="100">
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0"/>
<details key="max" value="100"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EReference" name="plant" lowerBound="1" eType="#//Plant"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EEnum" name="Roughness">
<eLiterals name="VeryRough"/>
<eLiterals name="Rough" value="1"/>
<eLiterals name="MediumRough" value="2"/>
<eLiterals name="MediumSmooth" value="3"/>
<eLiterals name="Smooth" value="4"/>
<eLiterals name="VerySmooth" value="5"/>
</eClassifiers>
</ecore:EPackage>

View File

@ -0,0 +1,318 @@
"""Definition of meta model 'greenerycatalog'."""
from functools import partial
import pyecore.ecore as Ecore
from pyecore.ecore import *
name = 'greenerycatalog'
nsURI = 'http://ca.concordia/greenerycatalog'
nsPrefix = 'greenery'
eClass = EPackage(name=name, nsURI=nsURI, nsPrefix=nsPrefix)
eClassifiers = {}
getEClassifier = partial(Ecore.getEClassifier, searchspace=eClassifiers)
Management = EEnum('Management', literals=['Intensive', 'Extensive', 'SemiIntensive', 'NA'])
Roughness = EEnum('Roughness', literals=['VeryRough', 'Rough',
'MediumRough', 'MediumSmooth', 'Smooth', 'VerySmooth'])
class Soil(EObject, metaclass=MetaEClass):
name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
roughness = EAttribute(eType=Roughness, unique=True, derived=False,
changeable=True, default_value=Roughness.MediumRough)
conductivityOfDrySoil = EAttribute(
eType=EString, unique=True, derived=False, changeable=True, default_value='1.0 W/(m*K)')
densityOfDrySoil = EAttribute(eType=EString, unique=True, derived=False,
changeable=True, default_value='1100 kg/m³')
specificHeatOfDrySoil = EAttribute(
eType=EString, unique=True, derived=False, changeable=True, default_value='1200 J/(kg*K)')
thermalAbsorptance = EAttribute(eType=EString, unique=True,
derived=False, changeable=True, default_value='0.9')
solarAbsorptance = EAttribute(eType=EString, unique=True,
derived=False, changeable=True, default_value='0.7')
visibleAbsorptance = EAttribute(eType=EString, unique=True,
derived=False, changeable=True, default_value='0.75')
saturationVolumetricMoistureContent = EAttribute(
eType=EString, unique=True, derived=False, changeable=True, default_value='0.0')
residualVolumetricMoistureContent = EAttribute(
eType=EString, unique=True, derived=False, changeable=True, default_value='0.05')
initialVolumetricMoistureContent = EAttribute(
eType=EString, unique=True, derived=False, changeable=True, default_value='0.1')
def __init__(self, *, name=None, roughness=None, conductivityOfDrySoil=None, densityOfDrySoil=None, specificHeatOfDrySoil=None, thermalAbsorptance=None, solarAbsorptance=None, visibleAbsorptance=None, saturationVolumetricMoistureContent=None, residualVolumetricMoistureContent=None, initialVolumetricMoistureContent=None):
# if kwargs:
# raise AttributeError('unexpected arguments: {}'.format(kwargs))
super().__init__()
if name is not None:
self.name = name
if roughness is not None:
self.roughness = roughness
if conductivityOfDrySoil is not None:
self.conductivityOfDrySoil = conductivityOfDrySoil
if densityOfDrySoil is not None:
self.densityOfDrySoil = densityOfDrySoil
if specificHeatOfDrySoil is not None:
self.specificHeatOfDrySoil = specificHeatOfDrySoil
if thermalAbsorptance is not None:
self.thermalAbsorptance = thermalAbsorptance
if solarAbsorptance is not None:
self.solarAbsorptance = solarAbsorptance
if visibleAbsorptance is not None:
self.visibleAbsorptance = visibleAbsorptance
if saturationVolumetricMoistureContent is not None:
self.saturationVolumetricMoistureContent = saturationVolumetricMoistureContent
if residualVolumetricMoistureContent is not None:
self.residualVolumetricMoistureContent = residualVolumetricMoistureContent
if initialVolumetricMoistureContent is not None:
self.initialVolumetricMoistureContent = initialVolumetricMoistureContent
class Plant(EObject, metaclass=MetaEClass):
name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
height = EAttribute(eType=EString, unique=True, derived=False,
changeable=True, default_value='0.1 m')
leafAreaIndex = EAttribute(eType=EString, unique=True, derived=False,
changeable=True, default_value='2.5')
leafReflectivity = EAttribute(eType=EString, unique=True,
derived=False, changeable=True, default_value='0.1')
leafEmissivity = EAttribute(eType=EString, unique=True, derived=False,
changeable=True, default_value='0.9')
minimalStomatalResistance = EAttribute(
eType=EString, unique=True, derived=False, changeable=True, default_value='100.0 s/m')
co2Sequestration = EAttribute(eType=EString, unique=True, derived=False,
changeable=True, default_value='kgCO₂eq')
growsOn = EReference(ordered=True, unique=True, containment=False, derived=False, upper=-1)
def __init__(self, *, name=None, height=None, leafAreaIndex=None, leafReflectivity=None, leafEmissivity=None, minimalStomatalResistance=None, growsOn=None, co2Sequestration=None):
# if kwargs:
# raise AttributeError('unexpected arguments: {}'.format(kwargs))
super().__init__()
if name is not None:
self.name = name
if height is not None:
self.height = height
if leafAreaIndex is not None:
self.leafAreaIndex = leafAreaIndex
if leafReflectivity is not None:
self.leafReflectivity = leafReflectivity
if leafEmissivity is not None:
self.leafEmissivity = leafEmissivity
if minimalStomatalResistance is not None:
self.minimalStomatalResistance = minimalStomatalResistance
if co2Sequestration is not None:
self.co2Sequestration = co2Sequestration
if growsOn:
self.growsOn.extend(growsOn)
class SupportEnvelope(EObject, metaclass=MetaEClass):
roughness = EAttribute(eType=Roughness, unique=True, derived=False,
changeable=True, default_value=Roughness.MediumRough)
solarAbsorptance = EAttribute(eType=EDouble, unique=True,
derived=False, changeable=True, default_value=0.0)
conductivity = EAttribute(eType=EDouble, unique=True, derived=False,
changeable=True, default_value=0.0)
visibleAbsorptance = EAttribute(eType=EDouble, unique=True,
derived=False, changeable=True, default_value=0.0)
specificHeat = EAttribute(eType=EDouble, unique=True, derived=False,
changeable=True, default_value=0.0)
density = EAttribute(eType=EDouble, unique=True, derived=False,
changeable=True, default_value=0.0)
thermalAbsorptance = EAttribute(eType=EDouble, unique=True,
derived=False, changeable=True, default_value=0.0)
def __init__(self, *, roughness=None, solarAbsorptance=None, conductivity=None, visibleAbsorptance=None, specificHeat=None, density=None, thermalAbsorptance=None):
# if kwargs:
# raise AttributeError('unexpected arguments: {}'.format(kwargs))
super().__init__()
if roughness is not None:
self.roughness = roughness
if solarAbsorptance is not None:
self.solarAbsorptance = solarAbsorptance
if conductivity is not None:
self.conductivity = conductivity
if visibleAbsorptance is not None:
self.visibleAbsorptance = visibleAbsorptance
if specificHeat is not None:
self.specificHeat = specificHeat
if density is not None:
self.density = density
if thermalAbsorptance is not None:
self.thermalAbsorptance = thermalAbsorptance
class GreeneryCatalog(EObject, metaclass=MetaEClass):
name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
description = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
source = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
plantCategories = EReference(ordered=True, unique=True,
containment=True, derived=False, upper=-1)
vegetationCategories = EReference(ordered=True, unique=True,
containment=True, derived=False, upper=-1)
soils = EReference(ordered=True, unique=True, containment=True, derived=False, upper=-1)
def __init__(self, *, name=None, description=None, source=None, plantCategories=None, vegetationCategories=None, soils=None):
# if kwargs:
# raise AttributeError('unexpected arguments: {}'.format(kwargs))
super().__init__()
if name is not None:
self.name = name
if description is not None:
self.description = description
if source is not None:
self.source = source
if plantCategories:
self.plantCategories.extend(plantCategories)
if vegetationCategories:
self.vegetationCategories.extend(vegetationCategories)
if soils:
self.soils.extend(soils)
class PlantCategory(EObject, metaclass=MetaEClass):
"""Excluding (that is non-overlapping) categories like Trees, Hedeges, Grasses that help users finding a specific biol. plant species."""
name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
plants = EReference(ordered=True, unique=True, containment=True, derived=False, upper=-1)
def __init__(self, *, name=None, plants=None):
# if kwargs:
# raise AttributeError('unexpected arguments: {}'.format(kwargs))
super().__init__()
if name is not None:
self.name = name
if plants:
self.plants.extend(plants)
class IrrigationSchedule(EObject, metaclass=MetaEClass):
name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
def __init__(self, *, name=None):
# if kwargs:
# raise AttributeError('unexpected arguments: {}'.format(kwargs))
super().__init__()
if name is not None:
self.name = name
class Vegetation(EObject, metaclass=MetaEClass):
"""Plant life or total plant cover (as of an area)"""
name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
thicknessOfSoil = EAttribute(eType=EString, unique=True, derived=False,
changeable=True, default_value='20 cm')
management = EAttribute(eType=Management, unique=True, derived=False,
changeable=True, default_value=Management.NA)
airGap = EAttribute(eType=EString, unique=True, derived=False,
changeable=True, default_value='0.0 cm')
soil = EReference(ordered=True, unique=True, containment=False, derived=False)
plants = EReference(ordered=True, unique=True, containment=True, derived=False, upper=-1)
def __init__(self, *, name=None, thicknessOfSoil=None, soil=None, plants=None, management=None, airGap=None):
# if kwargs:
# raise AttributeError('unexpected arguments: {}'.format(kwargs))
super().__init__()
if name is not None:
self.name = name
if thicknessOfSoil is not None:
self.thicknessOfSoil = thicknessOfSoil
if management is not None:
self.management = management
if airGap is not None:
self.airGap = airGap
if soil is not None:
self.soil = soil
if plants:
self.plants.extend(plants)
class VegetationCategory(EObject, metaclass=MetaEClass):
"""Excluding (that is non-overlapping) categories to help users finding a specific vegetation template."""
name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
vegetationTemplates = EReference(ordered=True, unique=True,
containment=True, derived=False, upper=-1)
def __init__(self, *, vegetationTemplates=None, name=None):
# if kwargs:
# raise AttributeError('unexpected arguments: {}'.format(kwargs))
super().__init__()
if name is not None:
self.name = name
if vegetationTemplates:
self.vegetationTemplates.extend(vegetationTemplates)
class PlantPercentage(EObject, metaclass=MetaEClass):
percentage = EAttribute(eType=EString, unique=True, derived=False,
changeable=True, default_value='100')
plant = EReference(ordered=True, unique=True, containment=False, derived=False)
def __init__(self, *, percentage=None, plant=None):
# if kwargs:
# raise AttributeError('unexpected arguments: {}'.format(kwargs))
super().__init__()
if percentage is not None:
self.percentage = percentage
if plant is not None:
self.plant = plant

View File

@ -0,0 +1,268 @@
<?xml version="1.0" encoding="UTF-8"?>
<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="greenerycatalog" nsURI="http://ca.concordia/greenerycatalog"
nsPrefix="greenery">
<eClassifiers xsi:type="ecore:EClass" name="Soil">
<eAnnotations source="http://www.eclipse.org/emf/2002/Ecore">
<details key="constraints" value="nonNegative"/>
</eAnnotations>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
defaultValueLiteral=""/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="roughness" eType="#//Roughness"
defaultValueLiteral="MediumRough">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="defines the relative roughness of a particular material layer. This parameter only influences the convection coefficients, more specifically the exterior convection coefficient. A nominal value is expected in with the options being &quot;VeryRough&quot;, &quot;Rough&quot;, &quot;MediumRough&quot;, &quot;MediumSmooth&quot;, &quot;Smooth&quot;, and &quot;VerySmooth&quot; in order of roughest to smoothest options."/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="conductivityOfDrySoil"
lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
defaultValueLiteral="1.0 W/(m*K)">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="Thermal conductivity W/(m-K). Range: 0.2 to 1.5"/>
</eAnnotations>
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0.2"/>
<details key="max" value="1.5"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="densityOfDrySoil" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
defaultValueLiteral="1100 kg/m³">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="Density in kg/m³. "/>
</eAnnotations>
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0.1"/>
<details key="max" value="10000"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="specificHeatOfDrySoil"
eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
defaultValueLiteral="1200 J/(kg*K)">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="in units of J/(kg-K). Range(300 to 2000)"/>
</eAnnotations>
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0.2"/>
<details key="max" value="2000"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="thermalAbsorptance" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
defaultValueLiteral="0.9">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="the fraction of incident long wavelength (>2.5 microns) radiation that is absorbed by the material. This parameter is used when calculating the long wavelength radiant exchange between various surfaces and affects the surface heat balances (both inside and outside as appropriate). For long wavelength radiant exchange, thermal emissivity and thermal emittance are equal to thermal absorptance. Range: 0 to 1"/>
</eAnnotations>
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0.0"/>
<details key="max" value="1.0"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="solarAbsorptance" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
defaultValueLiteral="0.7">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="the fraction of incident solar radiation that is absorbed by the material.&#xA;Solar radiation (0.3 to 2.537 microns) includes the visible spectrum as well as infrared and ultraviolet wavelengths. This parameter is used when calculating the amount of incident solar radiation absorbed by various surfaces and affects the surface heat balances (both inside and outside as appropriate). If solar reflectance (or reflectivity) data is available, then absorptance is equal to 1.0 minus reflectance (for opaque materials).&#xA;Range: 0 to 1"/>
</eAnnotations>
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0.0"/>
<details key="max" value="1.0"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="visibleAbsorptance" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
defaultValueLiteral="0.75">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="The visible absorptance field in the Material input syntax represents the fraction of incident visible wavelength radiation that is absorbed by the material.&#xA;Visible wavelength radiation (0.37 to 0.78 microns weighted by photopic response) is slightly different than solar radiation in that the visible band of wavelengths is much more narrow while solar radiation includes the visible spectrum as well as infrared and ultraviolet wavelengths.&#xA;This parameter is used when calculating the amount of incident visible radiation absorbed by various surfaces and affects the surface heat balances (both inside and outside as appropriate) as well as the daylighting calculations. If visible reflectance (or reflectivity) data is available, then absorptance is equal to 1.0 minus reflectance (for opaque materials).&#xA;Range: 0.5 to 1.0"/>
</eAnnotations>
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0.5"/>
<details key="max" value="1.0"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="saturationVolumetricMoistureContent"
eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
defaultValueLiteral="0.0">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="input of the saturation moisture content of the soil layer. Range: 0.1 to 0.5"/>
</eAnnotations>
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0.1"/>
<details key="max" value="0.5"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="residualVolumetricMoistureContent"
eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
defaultValueLiteral="0.05">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="Input of the residual moisture content of the soil layer. Range: 0.01 to 0.1"/>
</eAnnotations>
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0.01"/>
<details key="max" value="0.1"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="initialVolumetricMoistureContent"
eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
defaultValueLiteral="0.1">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="Range: 0.05 to 0.5"/>
</eAnnotations>
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0.05"/>
<details key="max" value="0.5"/>
</eAnnotations>
</eStructuralFeatures>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="Plant">
<eStructuralFeatures xsi:type="ecore:EAttribute" name="name" lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="height" lowerBound="1"
eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
defaultValueLiteral="0.1 m">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="Maximum height of plants. Range: 0.005 to 1 m"/>
</eAnnotations>
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0.005"/>
<details key="max" value="1.0"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="leafAreaIndex" lowerBound="1"
eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
defaultValueLiteral="2.5">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="Leaf area per unit area of soil surface. Range: 0.001 to 5.0 m²/m²"/>
</eAnnotations>
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0.001"/>
<details key="max" value="5.0"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="leafReflectivity" lowerBound="1"
eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
defaultValueLiteral="0.1">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="Represents the fraction of incident solar radiation that is reflected by the individual leaf surfaces (albedo).&#xA;Range: 0.05 to 0.5"/>
</eAnnotations>
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0.05"/>
<details key="max" value="0.5"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="leafEmissivity" lowerBound="1"
eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
defaultValueLiteral="0.9">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="Ratio of thermal radiation emitted from leaf surfaces to that emitted by an ideal black body at the same temperature.&#xA;This parameter is used when calculating the long wavelength radiant exchange at the leaf surfaces.&#xA;Range: 0.8 to 1"/>
</eAnnotations>
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0.8"/>
<details key="max" value="1.0"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="minimalStomatalResistance"
lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
defaultValueLiteral="100.0 s/m">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="Resistance of the plants to moisture transport.&#xA;Plants with low values of stomatal resistance will result in higher evapotranspiration rates than plants with high resistance.&#xA;Range: 50 to 300 m/s"/>
</eAnnotations>
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="50.0"/>
<details key="max" value="300.0"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EReference" name="growsOn" lowerBound="1"
upperBound="-1" eType="#//Soil"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="co2Sequestration" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
defaultValueLiteral="kgCO₂eq"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="SupportEnvelope">
<eStructuralFeatures xsi:type="ecore:EAttribute" name="roughness" eType="#//Roughness"
defaultValueLiteral="MediumRough"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="solarAbsorptance" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDouble"
defaultValueLiteral="0.0"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="conductivity" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDouble"
defaultValueLiteral="0.0"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="visibleAbsorptance" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDouble"
defaultValueLiteral="0.0"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="specificHeat" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDouble"
defaultValueLiteral="0.0"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="density" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDouble"
defaultValueLiteral="0.0"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="thermalAbsorptance" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDouble"
defaultValueLiteral="0.0"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="GreeneryCatalog">
<eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="description" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="source" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
<eStructuralFeatures xsi:type="ecore:EReference" name="plantCategories" lowerBound="1"
upperBound="-1" eType="#//PlantCategory" containment="true"/>
<eStructuralFeatures xsi:type="ecore:EReference" name="vegetationCategories" lowerBound="1"
upperBound="-1" eType="#//VegetationCategory" containment="true"/>
<eStructuralFeatures xsi:type="ecore:EReference" name="soils" upperBound="-1"
eType="#//Soil" containment="true"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="PlantCategory">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="Excluding (that is non-overlapping) categories like Trees, Hedeges, Grasses that help users finding a specific biol. plant species."/>
</eAnnotations>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
<eStructuralFeatures xsi:type="ecore:EReference" name="plants" upperBound="-1"
eType="#//Plant" containment="true"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="IrrigationSchedule">
<eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="Vegetation">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="Plant life or total plant cover (as of an area)"/>
</eAnnotations>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="name" lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="thicknessOfSoil" lowerBound="1"
eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
defaultValueLiteral="20 cm">
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0"/>
<details key="max" value="1000"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EReference" name="soil" lowerBound="1" eType="#//Soil"/>
<eStructuralFeatures xsi:type="ecore:EReference" name="plants" lowerBound="1"
upperBound="-1" eType="#//PlantPercentage" containment="true"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="management" lowerBound="1"
eType="#//Management" defaultValueLiteral="NA"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="airGap" lowerBound="1"
eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
defaultValueLiteral="0.0 cm"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="VegetationCategory">
<eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
<details key="documentation" value="Excluding (that is non-overlapping) categories to help users finding a specific vegetation template."/>
</eAnnotations>
<eStructuralFeatures xsi:type="ecore:EReference" name="vegetationTemplates" upperBound="-1"
eType="#//Vegetation" containment="true"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EEnum" name="Management">
<eLiterals name="Intensive"/>
<eLiterals name="Extensive" value="1"/>
<eLiterals name="SemiIntensive" value="2"/>
<eLiterals name="NA" value="3"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="PlantPercentage">
<eStructuralFeatures xsi:type="ecore:EAttribute" name="percentage" lowerBound="1"
eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
defaultValueLiteral="100">
<eAnnotations source="http://www.hft-stuttgart.de/UomQuantities">
<details key="min" value="0"/>
<details key="max" value="100"/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EReference" name="plant" lowerBound="1" eType="#//Plant"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EEnum" name="Roughness">
<eLiterals name="VeryRough"/>
<eLiterals name="Rough" value="1"/>
<eLiterals name="MediumRough" value="2"/>
<eLiterals name="MediumSmooth" value="3"/>
<eLiterals name="Smooth" value="4"/>
<eLiterals name="VerySmooth" value="5"/>
</eClassifiers>
</ecore:EPackage>

View File

@ -0,0 +1,115 @@
"""
Greenery catalog
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
from pyecore.resources import ResourceSet, URI
from catalogs.greenery.ecore_greenery.greenerycatalog import GreeneryCatalog as gc
from catalogs.catalog import Catalog
from pathlib import Path
from catalogs.data_model.greenery.vegetation import Vegetation as libs_vegetation
from catalogs.data_model.greenery.plant import Plant as libs_plant
from catalogs.data_model.greenery.soil import Soil as libs_soil
from catalogs.data_model.greenery.plant_percentage import PlantPercentage as libs_pp
from catalogs.data_model.greenery.greenery_content import GreeneryContent
class GreeneryCatalog(Catalog):
def __init__(self, path):
base_path = Path(Path(__file__).parent / 'ecore_greenery' / 'greenerycatalog_no_quantities.ecore')
resource_set = ResourceSet()
data_model = resource_set.get_resource(URI(str(base_path)))
data_model_root = data_model.contents[0]
resource_set.metamodel_registry[data_model_root.nsURI] = data_model_root
resource = resource_set.get_resource(URI(str(path)))
catalog_data: gc = resource.contents[0]
plants = []
for plant_category in catalog_data.plantCategories:
name = plant_category.name
for plant in plant_category.plants:
plants.append(libs_plant(name, plant))
vegetations = []
for vegetation_category in catalog_data.vegetationCategories:
name = vegetation_category.name
for vegetation in vegetation_category.vegetationTemplates:
plant_percentages = []
for plant_percentage in vegetation.plants:
plant_category = "Unknown"
for plant in plants:
if plant.name == plant_percentage.plant.name:
plant_category = plant.category
break
plant_percentages.append(libs_pp(plant_percentage.percentage,plant_category, plant_percentage.plant))
vegetations.append(libs_vegetation(name, vegetation, plant_percentages))
plants = []
for plant_category in catalog_data.plantCategories:
name = plant_category.name
for plant in plant_category.plants:
plants.append(libs_plant(name, plant))
soils = []
for soil in catalog_data.soils:
soils.append(libs_soil(soil))
self._data = GreeneryContent(vegetations, plants, soils)
def names(self, category=None):
"""
Get the catalog elements names
:parm: optional category filter
"""
if category is None:
_names = {'vegetations': [], 'plants': [], 'soils': []}
for vegetation in self._data.vegetations:
_names['vegetations'].append(vegetation.name)
for plant in self._data.plants:
_names['plants'].append(plant.name)
for soil in self._data.soils:
_names['soils'].append(soil.name)
else:
_names = {category: []}
if category.lower() == 'vegetations':
for vegetation in self._data.vegetations:
_names[category].append(vegetation.name)
elif category.lower() == 'plants':
for plant in self._data.plants:
_names[category].append(plant.name)
elif category.lower() == 'soils':
for soil in self._data.soils:
_names[category].append(soil.name)
else:
raise ValueError(f'Unknown category [{category}]')
return _names
def get_entry(self, name):
"""
Get one complete entry from the greenery catalog
"""
for entry in self._data.vegetations:
if entry.name.lower() == name.lower():
return entry
for entry in self._data.plants:
if entry.name.lower() == name.lower():
return entry
for entry in self._data.soils:
if entry.name.lower() == name.lower():
return entry
raise IndexError(f"{name} doesn't exists in the catalog")
def entries(self, category=None):
if category is None:
return self._data
else:
if category.lower() == 'vegetations':
return self._data.vegetations
elif category.lower() == 'plants':
return self._data.plants
elif category.lower() == 'soils':
return self._data.soils
else:
raise ValueError(f'Unknown category [{category}]')

View File

@ -0,0 +1,43 @@
"""
Greenery catalog publish the greenery information
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
from pathlib import Path
from catalogs.greenery.greenery_catalog import GreeneryCatalog
class GreeneryCatalogFactory:
"""
GeometryFactory class
"""
def __init__(self, file_type, base_path=None):
if base_path is None:
base_path = Path(Path(__file__).parent.parent / 'data/greenery')
self._file_type = '_' + file_type.lower()
self._path = base_path
@property
def _nrel(self) -> GreeneryCatalog:
"""
Return a greenery catalog using ecore as datasource
:return: GreeneryCatalog
"""
return GreeneryCatalog((self._path / 'ecore_greenery_catalog.xml').resolve())
@property
def catalog(self) -> GreeneryCatalog:
"""
Enrich the city given to the class using the class given handler
:return: City
"""
return getattr(self, self._file_type, lambda: None)
@property
def catalog_debug(self) -> GreeneryCatalog:
"""
Enrich the city given to the class using the class given handler
:return: City
"""
return GreeneryCatalog((self._path / 'ecore_greenery_catalog.xml').resolve())

View File

@ -17,10 +17,10 @@ from city_model_structure.building import Building
from city_model_structure.city_object import CityObject
from city_model_structure.city_objects_cluster import CityObjectsCluster
from city_model_structure.buildings_cluster import BuildingsCluster
from city_model_structure.parts_consisting_building import PartsConsistingBuilding
from city_model_structure.subway_entrance import SubwayEntrance
from city_model_structure.fuel import Fuel
from city_model_structure.machine import Machine
from city_model_structure.parts_consisting_building import PartsConsistingBuilding
from city_model_structure.subway_entrance import SubwayEntrance
from helpers.geometry_helper import GeometryHelper
from helpers.location import Location
from city_model_structure.energy_system import EnergySystem
@ -154,6 +154,9 @@ class City:
if self.subway_entrances is not None:
for subway_entrance in self.subway_entrances:
self._city_objects.append(subway_entrance)
if self.energy_systems is not None:
for energy_system in self.energy_systems:
self._city_objects.append(energy_system)
return self._city_objects
@property

View File

@ -1,12 +1,13 @@
"""
EnergySystem module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Contributor Peter Yefi peteryefi@gmail.com
"""
from city_model_structure.city_object import CityObject
from city_model_structure.energy_systems.heat_pump import HeatPump
from city_model_structure.energy_systems.air_source_hp import AirSourceHP
from city_model_structure.energy_systems.water_to_water_hp import WaterToWaterHP
class EnergySystem(CityObject):
@ -16,25 +17,43 @@ class EnergySystem(CityObject):
def __init__(self, name, lod, surfaces, city_lower_corner):
super().__init__(name, lod, surfaces, city_lower_corner)
self._heat_pump = None
self._air_source_hp = None
self._water_to_water_hp = None
self._type = 'energy_system'
@property
def heat_pump(self) -> HeatPump:
def air_source_hp(self) -> AirSourceHP:
"""
Heat pump energy system
:return:
"""
return self._heat_pump
return self._air_source_hp
@heat_pump.setter
def heat_pump(self, value):
@air_source_hp.setter
def air_source_hp(self, value):
"""
Set heat pumm for energy system
:param value: HeatPump
Set heat pump for energy system
:param value: AirSourceHP
"""
if self._heat_pump is None:
self._heat_pump = value
if self._air_source_hp is None:
self._air_source_hp = value
@property
def water_to_water_hp(self) -> WaterToWaterHP:
"""
Water to water heat pump energy system
:return:
"""
return self._water_to_water_hp
@water_to_water_hp.setter
def water_to_water_hp(self, value):
"""
Set water to water heat pump for energy system
:param value: WaterToWaterHP
"""
if self._water_to_water_hp is None:
self._water_to_water_hp = value
@property
def type(self) -> str:

View File

@ -0,0 +1,131 @@
"""
air_source_hp module defines an air source heat pump
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Contributor Peter Yefi peteryefi@gmail.com
"""
from typing import List
from city_model_structure.energy_systems.heat_pump import HeatPump
class AirSourceHP(HeatPump):
"""
AirSourceHP class
"""
def __init__(self):
super().__init__()
self._cooling_capacity = None
self._cooling_comp_power = None
self._cooling_capacity_coff = None # a coefficients for insel
self._heating_capacity = None
self._heating_comp_power = None
self._heating_capacity_coff = None
@property
def cooling_capacity(self) -> List[float]:
"""
Get cooling capacity in kW
:return: [[float]]
"""
return self._cooling_capacity
@cooling_capacity.setter
def cooling_capacity(self, value):
"""
Set cooling capacity in kW
:param value: [[float]]
"""
if self._cooling_capacity is None:
self._cooling_capacity = value
@property
def cooling_comp_power(self) -> List[float]:
"""
Get cooling compressor power input in kW
:return: [[float]]
"""
return self._cooling_comp_power
@cooling_comp_power.setter
def cooling_comp_power(self, value):
"""
Set the cooling compressor in kW
:param value: [[float]]
:return:
"""
if self._cooling_comp_power is None:
self._cooling_comp_power = value
@property
def cooling_capacity_coff(self) -> List[float]:
"""
Get cooling capacity coefficients
:return: [float]
"""
return self._cooling_capacity_coff
@cooling_capacity_coff.setter
def cooling_capacity_coff(self, value):
"""
Set the value for cooling capacity coefficients
:param value: [float]
:return:
"""
if self._cooling_capacity_coff is None:
self._cooling_capacity_coff = value
@property
def heating_capacity(self) -> List[float]:
"""
Get heating capacity kW
:return: [[float]]
"""
return self._heating_capacity
@heating_capacity.setter
def heating_capacity(self, value):
"""
Set the heating capacity in kW
:param value: [[float]]
:return:
"""
if self._heating_capacity is None:
self._heating_capacity = value
@property
def heating_comp_power(self) -> List[float]:
"""
Get heating compressor power kW
:return: [[float]]
"""
return self._heating_comp_power
@heating_comp_power.setter
def heating_comp_power(self, value):
"""
Set the heating compressor power in kW
:param value: [[float]]
:return:
"""
if self._heating_comp_power is None:
self._heating_comp_power = value
@property
def heating_capacity_coff(self) -> List[float]:
"""
Get heating capacity coefficients
:return: [float]
"""
return self._heating_capacity_coff
@heating_capacity_coff.setter
def heating_capacity_coff(self, value):
"""
Set the value for heating capacity coefficients
:param value: [float]
:return:
"""
if self._heating_capacity_coff is None:
self._heating_capacity_coff = value

View File

@ -1,13 +1,9 @@
"""
heat_pump module defines a heat pump
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Contributor Peter Yefi peteryefi@gmail.com
Copyright © 2021 Project Author Peter Yefi peteryefi@gmail.com
"""
from typing import List
from typing import Dict
class HeatPump:
"""
@ -16,14 +12,6 @@ class HeatPump:
def __init__(self):
self._model = None
self._cooling_capacity = None
self._cooling_comp_power = None
self._cooling_capacity_coff = None
self._cooling_comp_power_coff = None
self._heating_capacity = None
self._heating_comp_power = None
self._heating_capacity_coff = None
self._heating_comp_power_coff = None
@property
def model(self) -> str:
@ -41,150 +29,3 @@ class HeatPump:
"""
if self._model is None:
self._model = value
@property
def cooling_capacity(self) -> List[float]:
"""
Get cooling capacity in kW
:return: [[float]]
"""
return self._cooling_capacity
@cooling_capacity.setter
def cooling_capacity(self, value):
"""
Set cooling capacity in kW
:param value: [[float]]
"""
if self._cooling_capacity is None:
self._cooling_capacity = value
@property
def cooling_comp_power(self) -> List[float]:
"""
Get cooling compressor power input in kW
:return: [[float]]
"""
return self._cooling_comp_power
@cooling_comp_power.setter
def cooling_comp_power(self, value):
"""
Set the cooling compressor in kW
:param value: [[float]]
:return:
"""
if self._cooling_comp_power is None:
self._cooling_comp_power = value
@property
def cooling_capacity_coff(self) -> List[float]:
"""
Get cooling capacity coefficients
:return: [float]
"""
return self._cooling_capacity_coff
@cooling_capacity_coff.setter
def cooling_capacity_coff(self, value):
"""
Set the value for cooling capacity coefficients
:param value: [float]
:return:
"""
if self._cooling_capacity_coff is None:
self._cooling_capacity_coff = value
@property
def cooling_comp_power_coff(self) -> List[float]:
"""
Get cooling compressor power coefficients
:return: [float]
"""
return self._cooling_comp_power_coff
@cooling_comp_power_coff.setter
def cooling_comp_power_coff(self, value):
"""
Set the value for cooling compressor power coefficients
:param value: [float]
:return:
"""
if self._cooling_comp_power_coff is None:
self._cooling_comp_power_coff = value
@property
def heating_capacity(self) -> List[float]:
"""
Get heating capacity kW
:return: [[float]]
"""
return self._heating_capacity
@heating_capacity.setter
def heating_capacity(self, value):
"""
Set the heating capacity in kW
:param value: [[float]]
:return:
"""
if self._heating_capacity is None:
self._heating_capacity = value
@property
def heating_comp_power(self) -> List[float]:
"""
Get heating compressor power kW
:return: [[float]]
"""
return self._heating_comp_power
@heating_comp_power.setter
def heating_comp_power(self, value):
"""
Set the heating compressor power in kW
:param value: [[float]]
:return:
"""
if self._heating_comp_power is None:
self._heating_comp_power = value
@property
def heating_comp_power_coff(self) -> List[float]:
"""
Get heating compressor power coefficients
:return: [float]
"""
return self._heating_comp_power_coff
@heating_comp_power_coff.setter
def heating_comp_power_coff(self, value):
"""
Set the value for heating compressor power coefficients
:param value: [float]
:return:
"""
if self._heating_comp_power_coff is None:
self._heating_comp_power_coff = value
@property
def heating_capacity_coff(self) -> List[float]:
"""
Get heating capacity coefficients
:return: [float]
"""
return self._heating_capacity_coff
@heating_capacity_coff.setter
def heating_capacity_coff(self, value):
"""
Set the value for heating capacity coefficients
:param value: [float]
:return:
"""
if self._heating_capacity_coff is None:
self._heating_capacity_coff = value

View File

@ -0,0 +1,130 @@
"""
water_to_water_hp module defines a water to water heat pump heat pump
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2021 Project Author Peter Yefi peteryefi@gmail.com
"""
from typing import List
from city_model_structure.energy_systems.heat_pump import HeatPump
class WaterToWaterHP(HeatPump):
"""
WaterToWaterHP class
"""
def __init__(self):
super().__init__()
self._entering_water_temp = None
self._leaving_water_temp = None
self._total_cooling_capacity = None
self._power_demand = None
self._flow_rate = None
self._power_demand_coff = None # a coefficients
@property
def entering_water_temp(self) -> List[float]:
"""
Get entering water temperature in degree celsius
:return: [[float]]
"""
return self._entering_water_temp
@entering_water_temp.setter
def entering_water_temp(self, value):
"""
Set entering water temperature in degree celsius
:param value: [[float]]
"""
if self._entering_water_temp is None:
self._entering_water_temp = value
@property
def leaving_water_temp(self) -> List[float]:
"""
Get leaving water temperature in degree celsius
:return: [[float]]
"""
return self._leaving_water_temp
@leaving_water_temp.setter
def leaving_water_temp(self, value):
"""
Set the leaving water temperature in degree celsius
:param value: [[float]]
:return:
"""
if self._leaving_water_temp is None:
self._leaving_water_temp = value
@property
def total_cooling_capacity(self) -> List[float]:
"""
Get total cooling capacity
:return: [float]
"""
return self._total_cooling_capacity
@total_cooling_capacity.setter
def total_cooling_capacity(self, value):
"""
Set the value for total cooling capacity
:param value: [float]
:return:
"""
if self._total_cooling_capacity is None:
self._total_cooling_capacity = value
@property
def power_demand(self) -> List[float]:
"""
Get power demand in kW
:return: [float]
"""
return self._power_demand
@power_demand.setter
def power_demand(self, value):
"""
Set the value for power demand in kW
:param value: [float]
:return:
"""
if self._power_demand is None:
self._power_demand = value
@property
def flow_rate(self) -> List[float]:
"""
Get flow rate in kg/s
:return: [[float]]
"""
return self._flow_rate
@flow_rate.setter
def flow_rate(self, value):
"""
Set flow rate in kW
:param value: [[float]]
:return:
"""
if self._flow_rate is None:
self._flow_rate = value
@property
def power_demand_coff(self) -> List[float]:
"""
Get power demand coefficients
:return: [float]
"""
return self._power_demand_coff
@power_demand_coff.setter
def power_demand_coff(self, value):
"""
Set the value for power demand coefficients
:param value: [float]
:return:
"""
if self._power_demand_coff is None:
self._power_demand_coff = value

View File

@ -0,0 +1,23 @@
"""
LifeCycleAssessment retrieve the specific Life Cycle Assessment module for the given region
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Atiya
"""
from city_model_structure.machine import Machine
class LcaCalculations:
"""
LCA Calculations class
"""
def __init__(self):
print("lca calculations class")
def emission_disposal_machines(self, ):
return Machine.work_efficiency * Machine.energy_consumption_rate * Machine.carbon_emission_factor
def emission_transportation(self, weight, distance ):
return weight * distance * Machine.energy_consumption_rate * Machine.carbon_emission_factor

View File

@ -0,0 +1,118 @@
"""
LifeCycleAssessment retrieve the specific Life Cycle Assessment module for the given region
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Atiya
"""
class Material:
"""
LCA Material class
"""
def __init__(self, material_name, material_id, type, density, density_unit, embodied_carbon, embodied_carbon_unit, recycling_ratio,
onsite_recycling_ratio, company_recycling_ratio, landfilling_ratio, cost, cost_unit):
self._material_name = material_name
self._material_id = material_id
self._type = type
self._density = density
self._density_unit = density_unit
self._embodied_carbon = embodied_carbon
self._embodied_carbon_unit = embodied_carbon_unit
self._recycling_ratio = recycling_ratio
self._onsite_recycling_ratio = onsite_recycling_ratio
self._company_recycling_ratio = company_recycling_ratio
self._landfilling_ratio = landfilling_ratio
self._cost = cost
self._cost_unit = cost_unit
@property
def material_name(self):
"""
Get material name
"""
return self._material_name
@property
def id(self):
"""
Get material id
"""
return self._material_id
@property
def type(self):
"""
Get material type
"""
return self._type
@property
def density(self):
"""
Get material density
"""
return self._density
@property
def density_unit(self):
"""
Get material density unit
"""
return self._density_unit
@property
def embodied_carbon(self):
"""
Get material embodied carbon
"""
return self._embodied_carbon
@property
def embodied_carbon_unit(self):
"""
Get material embodied carbon unit
"""
return self._embodied_carbon_unit
@property
def recycling_ratio(self):
"""
Get material recycling ratio
"""
return self._recycling_ratio
@property
def onsite_recycling_ratio(self):
"""
Get material onsite recycling ratio
"""
return self._onsite_recycling_ratio
@property
def company_recycling_ratio(self):
"""
Get material company recycling ratio
"""
return self._company_recycling_ratio
@property
def landfilling_ratio(self):
"""
Get material landfilling ratio
"""
return self._landfilling_ratio
@property
def cost(self):
"""
Get material cost
"""
return self._cost
@property
def cost_unit(self):
"""
Get material cost unit
"""
return self._cost_unit

View File

@ -0,0 +1,786 @@
B 17 CONST
P 17
12 % Constant value
B 18 CONST
P 18
$a5 % Constant value
B 19 CONST
P 19
1 % Constant value
B 20 CONST
P 20
$HPSupTemp % Constant value
B 21 CONST
P 21
$AuxHeaterEfficiency % Constant value
B 22 CONST
P 22
$ElecGridEF % Constant value
B 23 CONST
P 23
2 % Constant value
B 24 CONST
P 24
$Cp % Constant value
B 25 CONST
P 25
9 % Constant value
B 26 CONST
P 26
2 % Constant value
B 27 CONST
P 27
$BuildingSuppTemp % Constant value
B 28 CONST
P 28
$a2 % Constant value
B 29 CONST
P 29
$a3 % Constant value
B 30 CONST
P 30
$MaximumHPEnergyInput % Constant value
B 31 CONST
P 31
12 % Constant value
B 32 CONST
P 32
12 % Constant value
B 33 CONST
P 33
$a6 % Constant value
B 34 CONST
P 34
10 % Constant value
B 35 CONST
P 35
1 % Constant value
B 36 CONST
P 36
$TemperatureDifference % Constant value
B 37 CONST
P 37
$ElectricityPrice % Constant value
B 38 CONST
P 38
$FuelPrice % Constant value
B 39 CONST
P 39
40 % Constant value
B 40 CONST
P 40
$Cp % Constant value
B 41 CONST
P 41
$HPDisactivationTemperature % Constant value
B 42 CONST
P 42
$FuelEF % Constant value
B 43 CONST
P 43
$HPReactivationTemperature % Constant value
B 44 CONST
P 44
$HPNominalCapacity % Constant value
B 45 CONST
P 45
0 % Constant value
B 46 CONST
P 46
$FuelLHV % Constant value
B 47 CONST
P 47
5 % Constant value
B 48 CONST
P 48
$TemperatureDifference % Constant value
B 49 CONST
P 49
$Cp % Constant value
B 50 CONST
P 50
$BuildingSuppTemp % Constant value
B 51 CONST
P 51
$a1 % Constant value
B 52 CONST
P 52
$a4 % Constant value
B 53 NOP
120.1
B 54 NOP
68.2
B 55 NOP
217.1
B 56 NOP
136.1
B 57 NOP
20.1
B 58 NOP
57.1
B 59 NOP
165.1
B 60 NOP
57.1
B 61 NOP
177.1
B 62 NOP
119.1
B 63 NOP
136.1
B 64 NOP
120.1
B 65 NOP
58.1
B 66 NOP
54.1
B 67 MIXER % Point 11
217.4
119.1
56.1
132.1
B 68 MIXER % Point 5
60.1
134.1
55.1
64.1
B 105 MUL
40.1
131.1
B 106 MUL
171.1
22.1
B 107 MUL
221.1
175.1
129.1
130.1
B 108 MUL
18.1
169.1
B 109 MUL
68.1
138.1
B 110 MUL
20.1
52.1
B 111 MUL
205.1
212.1
140.1
B 112 MUL
207.1
48.1
B 113 MUL
210.1
19.1
42.1
B 114 MUL
51.1
168.1
B 115 MUL
208.1
35.1
38.1
B 116 MUL
205.1
111.1
B 117 MUL
203.1
50.1
B 118 MUL
185.2
20.1
29.1
B 119 MUL
139.1
127.1
B 120 MUL
214.1
133.1
B 121 MUL
172.1
37.1
B 122 MUL
215.1
24.1
68.2
216.1
126.1
B 123 MUL
185.2
28.1
B 124 MUL
221.1
44.1
129.1
130.1
B 125 SUM
34.1
185.2
B 126 SUM
27.1
197.1
B 127 SUM
61.1
200.1
B 128 SUM
109.1
117.1
B 129 SUM
213.1
141.1
B 130 SUM
116.1
204.1
B 131 SUM
20.1
196.1
B 132 SUM
66.1
198.1
B 133 SUM
202.1
179.1
B 134 SUM
61.1
201.1
B 135 SUM
114.1
123.1
118.1
110.1
108.1
33.1
B 136 SUM
128.1
199.1
B 137 MTM
167.2
P 137
'Montreal' % Location
B 138 GT
68.1
50.1
B 139 GT
61.1
179.1
B 140 GT
164.1
45.1
B 141 GT
167.2
25.1
B 142 CUMC
167.3
107.1
B 143 CUMC
167.2
206.1
B 144 CUMC
167.3
106.1
113.1
B 145 CUMC
167.2
106.1
113.1
B 146 CUMC
167.3
206.1
B 147 CUMC
167.2
107.1
B 148 CUMC
167.3
121.1
115.1
B 149 CUMC
167.2
121.1
115.1
B 150 CUMC
167.4
107.1
B 158 CUM
113.1
B 159 CUM
106.1
B 160 CUM
115.1
B 161 CUM
206.1
B 162 CUM
121.1
B 163 CUM
124.1
107.1
B 164 DELAY
124.1
P 164
0 % Initial value
B 165 DELAY
67.1
P 165
25 % Initial value
B 166 MAXX
221.1
B 167 CLOCK
P 167
$StartYear % Start year
$StartMonth % Start month
$StartDay % Start day
$StartHour % Start hour
$StartMinute % Start minute
$StartSecond % Start second
$EndYear % End year
$EndMonth % End month
$EndDay % End day
$EndHour % End hour
$EndMinute % End minute
$EndSecond % End second
5 % Increment
'm' % Unit
B 168 EXPG
185.2
23.1
B 169 EXPG
20.1
26.1
B 170 DIV
209.1
32.1
B 171 DIV
107.1
17.1
B 172 DIV
107.1
31.1
B 173 DIV
180.1
46.1
B 174 DIV
124.1
107.1
B 175 DIV
44.1
135.1
B 176 DIV
30.1
44.1
B 177 DIV
218.1
105.1
B 178 DIV
163.1
163.2
B 179 DIV
220.1
112.1
B 180 DIV
170.1
21.1
B 185 GENGT
137.1
137.3
137.4
137.5
137.7
137.8
167.1
167.2
167.3
167.4
P 185
45.5 % Latitude
73.62 % Longitude
5 % Time zone
1 % Variance factor of the Gordon Reddy correlation
0 % Year-to-year variability
0.3 % Autocorrelation coefficient lag one
0.171 % Autocorrelation coefficient lag two
4711 % Initialisation of random number generator
2 % Maximum allowed mean temperature deviation
100 % Maximum number of iterations
B 186 WRITE
147.1
147.2
P 186
2 % Mode
0 % Suppress FNQ inputs
$fileOut8 % File name
'*' % Fortran format
B 187 WRITE
145.1
145.2
145.3
P 187
2 % Mode
0 % Suppress FNQ inputs
$fileOut5 % File name
'*' % Fortran format
B 188 WRITE
148.1
148.2
148.3
P 188
2 % Mode
0 % Suppress FNQ inputs
$fileOut7 % File name
'*' % Fortran format
B 189 WRITE
144.1
144.2
144.3
P 189
2 % Mode
0 % Suppress FNQ inputs
$fileOut2 % File name
'*' % Fortran format
B 190 WRITE
143.1
143.2
P 190
2 % Mode
0 % Suppress FNQ inputs
$fileOut4 % File name
'*' % Fortran format
B 191 WRITE
149.1
149.2
149.3
P 191
2 % Mode
0 % Suppress FNQ inputs
$fileOut3 % File name
'*' % Fortran format
B 192 WRITE
142.1
142.2
P 192
2 % Mode
0 % Suppress FNQ inputs
$fileOut6 % File name
'*' % Fortran format
B 193 WRITE
167.1
167.2
167.3
167.4
167.5
124.1
220.1
177.1
179.1
119.1
134.1
60.1
64.1
55.1
68.2
68.1
173.1
209.1
54.1
128.1
136.1
53.1
63.1
132.1
56.1
62.1
217.4
67.2
67.1
217.1
217.2
217.3
217.4
217.5
107.1
174.1
185.2
121.1
115.1
106.1
113.1
P 193
2 % Mode
0 % Suppress FNQ inputs
$fileOut1 % File name
'*' % Fortran format
B 194 WRITE
146.1
146.2
P 194
2 % Mode
0 % Suppress FNQ inputs
$fileOut9 % File name
'*' % Fortran format
B 195 WRITE
167.1
167.2
167.3
150.1
150.2
P 195
2 % Mode
0 % Suppress FNQ inputs
$fileOut10 % File name
'*' % Fortran format
B 196 CHS
59.1
B 197 CHS
68.1
B 198 CHS
53.1
B 199 CHS
36.1
B 200 CHS
179.1
B 201 CHS
62.1
B 202 CHS
177.1
B 203 INV
138.1
B 204 INV
212.1
B 205 INV
211.1
B 206 ATT
173.1
P 206
$FuelDensity % Attenuation factor a
B 207 ATT
49.1
P 207
1000 % Attenuation factor a
B 208 ATT
173.1
P 208
$FuelDensity % Attenuation factor a
B 209 ATT
122.1
P 209
1000 % Attenuation factor a
B 210 ATT
173.1
P 210
$FuelDensity % Attenuation factor a
B 211 GE
217.1
41.1
P 211
0 % Error tolerance
B 212 GE
217.1
43.1
P 212
0 % Error tolerance
B 213 LT
167.2
47.1
B 214 LT
177.1
179.1
B 215 LT
177.1
179.1
B 216 LT
68.1
39.1
B 217 TANKST
65.1
62.1
63.1
53.1
125.1
219.1
P 217
$TESCapacity % Tank volume
4 % Number of temperature nodes
$TESDiameter % Tank diameter
$Cp % Specfic heat of fluid
$Rhow % Fluid density
0 % Overall heat-loss coefficient
1 % Effective heat conductivity
30 % Initial tank temperature
B 218 GAIN
124.1
P 218
1000 % Gain factor g
B 219 SOY
167.1
167.2
167.3
167.4
167.5
167.6
B 220 READ
P 220
1 % Number of values to be read per record
0 % Number of records to be skipped on the first call
$HeatingDemand % File name
'*' % Fortran format
B 221 INT
176.1

View File

@ -18,3 +18,11 @@ AuxHeaterEfficiency: 0.9
ElecGridEF: 0.5
ElectricityPrice: 0.073
# Water to Water HP constants
HPNominalCapacity: 256
LowestPossibleLoadFlow: 4.73
HighestPossibleLoadFlow: 9.46

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<greenery:GreeneryCatalog xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:greenery="http://ca.concordia/greenerycatalog">
<plantCategories name="Flowers">
<plants name="Camellia Sasanqua" height="0.4 m" leafAreaIndex="2.18" leafReflectivity="0.2" leafEmissivity="0.9" minimalStomatalResistance="288 s/m" growsOn="//@soils.0 //@soils.2 //@soils.4 //@soils.3 //@soils.1"/>
<plants name="Rhododendron" height="0.5 m" leafAreaIndex="1.85" minimalStomatalResistance="161 s/m" growsOn="//@soils.0 //@soils.3"/>
<plants name="Ligustrum Japonicum 'Howardii' " height="0.48 m" leafAreaIndex="4.93" minimalStomatalResistance="172 s/m" growsOn="//@soils.0 //@soils.3"/>
<plants name="Viburnum Dilatatum (Thunb)" height="0.7 m" leafAreaIndex="5" minimalStomatalResistance="212 s/m" growsOn="//@soils.0 //@soils.3 //@soils.2 //@soils.4 //@soils.1"/>
<plants name="Lorpetalum Chinense var. Rubrum" height="0.7 m" leafAreaIndex="2" leafReflectivity="0.1" minimalStomatalResistance="228 s/m" growsOn="//@soils.0 //@soils.2 //@soils.3 //@soils.1"/>
<plants name="Buxus sinica" height="0.45 m" leafAreaIndex="4.03" minimalStomatalResistance="165 s/m" growsOn="//@soils.2 //@soils.0 //@soils.3 //@soils.5 //@soils.1"/>
<plants name="Sedum acre" height="0.1 m" leafAreaIndex="3.5" leafReflectivity="0.36" leafEmissivity="0.9" growsOn="//@soils.2 //@soils.0 //@soils.1 //@soils.3"/>
<plants name="Frankenia thymifolia" height="0.15 m" leafAreaIndex="3.6" leafReflectivity="0.32" leafEmissivity="0.83" growsOn="//@soils.2 //@soils.1 //@soils.0 //@soils.3"/>
<plants name="Vinca major" leafAreaIndex="2.7" leafReflectivity="0.25" leafEmissivity="0.78" growsOn="//@soils.2 //@soils.0 //@soils.3 //@soils.1"/>
<plants name="Ivy (hedera helix)" height="0.1 m" leafAreaIndex="5" growsOn="//@soils.4 //@soils.1 //@soils.2 //@soils.0 //@soils.3"/>
</plantCategories>
<plantCategories name="Grass">
<plants name="Lawn" height="0.06 m" leafAreaIndex="1.4" leafReflectivity="0.1" minimalStomatalResistance="50 s/m" growsOn="//@soils.2"/>
</plantCategories>
<plantCategories name="Farming">
<plants name="Strawberry" growsOn="//@soils.2"/>
<plants name="Tomato" leafEmissivity="0.8" growsOn="//@soils.2 //@soils.3"/>
<plants name="Lettuce" growsOn="//@soils.2"/>
</plantCategories>
<vegetationCategories name="Urban Greening">
<vegetationTemplates name="Grass" soil="//@soils.1" management="Extensive">
<plants plant="//@plantCategories.1/@plants.0"/>
</vegetationTemplates>
</vegetationCategories>
<vegetationCategories name="Green Facade">
<vegetationTemplates name="Green Facade" soil="//@soils.2">
<plants percentage="100" plant="//@plantCategories.0/@plants.9"/>
</vegetationTemplates>
</vegetationCategories>
<vegetationCategories name="GreenRoof">
<vegetationTemplates name="Green Roof" thicknessOfSoil="20 cm" soil="//@soils.2">
<plants percentage="10" plant="//@plantCategories.0/@plants.5"/>
<plants percentage="10" plant="//@plantCategories.0/@plants.0"/>
<plants percentage="10" plant="//@plantCategories.0/@plants.8"/>
<plants percentage="10" plant="//@plantCategories.0/@plants.2"/>
<plants percentage="10" plant="//@plantCategories.0/@plants.4"/>
<plants percentage="10" plant="//@plantCategories.0/@plants.6"/>
<plants percentage="10" plant="//@plantCategories.0/@plants.1"/>
<plants percentage="10" plant="//@plantCategories.0/@plants.3"/>
<plants percentage="20" plant="//@plantCategories.0/@plants.7"/>
</vegetationTemplates>
</vegetationCategories>
<vegetationCategories name="Rooftop Farming">
<vegetationTemplates name="Rooftop Farming" thicknessOfSoil="30 cm" soil="//@soils.2">
<plants percentage="19" plant="//@plantCategories.2/@plants.0"/>
<plants percentage="60" plant="//@plantCategories.2/@plants.1"/>
<plants percentage="21" plant="//@plantCategories.2/@plants.2"/>
</vegetationTemplates>
</vegetationCategories>
<soils name="Sand" conductivityOfDrySoil="1.26 W/(m·K)" saturationVolumetricMoistureContent="0.43" residualVolumetricMoistureContent="0.045"/>
<soils name="Loamy sand" conductivityOfDrySoil="0.35 W/(m·K)" saturationVolumetricMoistureContent="0.41" residualVolumetricMoistureContent="0.057"/>
<soils name="Loam" conductivityOfDrySoil="0.67 W/(m·K)" specificHeatOfDrySoil="900 J/(kg·K)" thermalAbsorptance="0.9" saturationVolumetricMoistureContent="0.43" residualVolumetricMoistureContent="0.078"/>
<soils name="Sandy Loam" conductivityOfDrySoil="1.06 W/(m·K)" saturationVolumetricMoistureContent="0.41" residualVolumetricMoistureContent="0.065"/>
<soils name="Clay loam" conductivityOfDrySoil="0.7 W/(m·K)" saturationVolumetricMoistureContent="0.41" residualVolumetricMoistureContent="0.095"/>
<soils name="Silt" conductivityOfDrySoil="0.35 W/(m·K)" saturationVolumetricMoistureContent="0.46" residualVolumetricMoistureContent="0.034"/>
</greenery:GreeneryCatalog>

View File

@ -0,0 +1,59 @@
"""
AirSourceHPExport exports air source values after executing insel.
Multiple files are generated for the export
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2021 Project Author Peter Yefi peteryefi@gmail.com
"""
from exports.energy_systems.heat_pump_export import HeatPumpExport
from typing import List, Tuple, Union
class AirSourceHPExport(HeatPumpExport):
"""
Exports heat pump values as multiple files
after executing insel
"""
def __init__(self, base_path, city, output_path, sim_type):
"""
:param base_path: path to energy system files
:param city: the city object
:param output_path: the file to hold insel simulation results
:param sim_type: the simulation type to run: 1 for series, 0 for parallel
"""
tmp_file = 'heat_pumps/as_series.txt' if sim_type == 0 else 'heat_pumps/as_parallel.txt'
template_path = (base_path / tmp_file)
super().__init__(base_path, city, output_path, template_path)
def _extract_model_coff(self, hp_model: str, data_type='heat') -> Union[Tuple[List, List], None]:
"""
Extracts heat pump coefficient data for a specific
model. e.g 012, 140
:param hp_model: the model type
:param data_type: indicates whether we're extracting cooling
or heating perfarmcn coefficients
:return:
"""
for energy_system in self._city.energy_systems:
if energy_system.air_source_hp.model == hp_model:
if data_type == 'heat':
return energy_system.air_source_hp.heating_capacity_coff
return energy_system.air_source_hp.cooling_capacity_coff
return None
def execute_insel(self, user_input, hp_model, data_type):
"""
Runs insel and produces output files
Runs insel and write the necessary files
:param user_input: a dictionary containing the user
values necessary to run insel
:param hp_model: a string that indicates the heat
pump model to be used e.g. 012, 015
:param data_type: a string that indicates whether
insel should run for heat or cooling performance
:return:
:return:
"""
capacity_coeff = self._extract_model_coff(hp_model, data_type)
super(AirSourceHPExport, self)._run_insel(user_input, capacity_coeff, 'air_source.insel')

View File

@ -1,5 +1,5 @@
"""
HeatPumpExport exports heatpump coefficient into several formats
HeatPumpExport exports heatpump outputs into several files after insel execution
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2021 Project Author Peter Yefi peteryefi@gmail.com
"""
@ -16,8 +16,9 @@ class HeatPumpExport:
of some defined function
"""
def __init__(self, base_path, city, output_path):
self._template_path = (base_path / 'heat_pumps/template.txt')
def __init__(self, base_path, city, output_path, template, water_temp=None):
self._template_path = template
self._water_temp = water_temp
self._constants_path = (base_path / 'heat_pumps/constants.yaml')
# needed to compute max demand.
self._demand_path = (base_path / 'heat_pumps/demand.txt')
@ -26,21 +27,17 @@ class HeatPumpExport:
self._base_path = base_path
self._output_path = output_path
def run_insel(self, user_input: Dict, hp_model: str, data_type: str) -> None:
def _run_insel(self, user_input: Dict, capacity_coeff: List, filename: str) -> None:
"""
Runs insel and write the necessary files
:param user_input: a dictionary containing the user
values necessary to run insel
:param hp_model: a string that indicates the heat
pump model to be used e.g. 012, 015
:param data_type: a string that indicates whether
insel should run for heat or cooling performance
:param capacity_coeff: a list containing capacity coefficients
:param filename: the name of the insel file to be created
:return:
"""
self._input_data = user_input
# update input data with other data necessary to run insel
capacity_coff, comp_power_coff = self._extract_model_coff(hp_model, data_type)
self._update_input_data_with_coff(capacity_coff, comp_power_coff)
self._update_input_data_with_coff(capacity_coeff)
# update input data with constants
self._update_input_data_with_constants()
# update input data with input and output files for insel
@ -53,7 +50,7 @@ class HeatPumpExport:
insel_template_content = insel_template_handler.read()
insel_template = Template(insel_template_content).substitute(self._input_data)
# create the insel file and write the template with substituted values into it
insel_file = (self._base_path / 'heat_pumps/dompark_heat_pump.insel')
insel_file = (self._base_path / 'heat_pumps' / filename)
insel_file_handler = open(insel_file, "w")
insel_file_handler.write(insel_template)
# Now run insel
@ -99,9 +96,15 @@ class HeatPumpExport:
self._input_data['fileOut9']: ['Day', 'Daily Fuel Consumption of Auxiliary Heater (m3)'],
self._input_data['fileOut10']: ['Year', 'Month', 'Day', 'Hour', 'HP Electricity Demand (kWh)']
}
for file_path, header in header_data.items():
file_path = file_path.strip("'")
df = pd.read_csv(file_path, header=None, sep='\s+')
# ignore ambient temperature for air source series run
if df.shape[1] > 25:
df.drop(columns=df.columns[-1],
axis=1,
inplace=True)
df.to_csv(file_path, header=header)
def _update_input_data_with_files(self):
@ -122,6 +125,9 @@ class HeatPumpExport:
self._input_data["fileOut8"] = f"'{str((self._base_path / 'heat_pumps/monthly_hp_electricity_demand.csv'))}'"
self._input_data["fileOut9"] = f"'{str((self._base_path / 'heat_pumps/daily_fossil_fuel_consumption.csv'))}'"
self._input_data["fileOut10"] = f"'{str((self._base_path / 'heat_pumps/hp_hourly_electricity_demand.csv'))}'"
# include water temperature for water to water heat pump
if self._water_temp is not None:
self._input_data['WaterTemperature'] = f"'{str(self._water_temp)}'"
def _delete_existing_output_files(self):
"""
@ -155,47 +161,49 @@ class HeatPumpExport:
constants_dict = yaml.load(file, Loader=yaml.FullLoader)
for key, value in constants_dict.items():
self._input_data[key] = value
# compute water to water HP specific values
if 55 <= self._input_data['HPSupTemp'] <= 60:
self._input_data["HPDisactivationTemperature"] = self._input_data["HPSupTemp"] - 5
self._input_data["HPReactivationTemperature"] = self._input_data["HPSupTemp"] - 18
elif 50 <= self._input_data["HPSupTemp"] < 55:
self._input_data["HPDisactivationTemperature"] = self._input_data["HPSupTemp"] - 5
self._input_data["HPReactivationTemperature"] = self._input_data["HPSupTemp"] - 13
elif 45 <= self._input_data["HPSupTemp"] < 50:
self._input_data["HPDisactivationTemperature"] = self._input_data["HPSupTemp"] - 3
self._input_data["HPReactivationTemperature"] = self._input_data["HPSupTemp"] - 8
elif 35 <= self._input_data["HPSupTemp"] < 40:
self._input_data["HPDisactivationTemperature"] = self._input_data["HPSupTemp"] - 2
self._input_data["HPReactivationTemperature"] = self._input_data["HPSupTemp"] - 4
# compute maximum demand. TODO: This should come from catalog in the future
max_demand = self._compute_max_demand()
# compute TESCapacity
self._input_data["TESCapacity"] = self._input_data["HoursOfStorageAtMaxDemand"] * (max_demand * 3.6) / (
(self._input_data["Cp"] / 1000) * self._input_data["TemperatureDifference"])
def _update_input_data_with_coff(self, capacity_coff: List, comp_power_coff: List):
def _update_input_data_with_coff(self, a_coeff: List):
"""
Updates the user data with coefficients derived from imports
:param capacity_coff: heat or cooling capacity coefficients
:param comp_power_coff: heat or cooling comppressor power coefficients
:param a_coeff: insel a coefficient values
Meaning of a is in the models for air source heat pump
and water to water source heat pump
:return:
"""
self._input_data["a1"] = capacity_coff[0]
self._input_data["a2"] = capacity_coff[1]
self._input_data["a3"] = capacity_coff[2]
self._input_data["a4"] = capacity_coff[3]
self._input_data["a5"] = capacity_coff[4]
self._input_data["a6"] = capacity_coff[5]
self._input_data["b1"] = comp_power_coff[0]
self._input_data["b2"] = comp_power_coff[1]
self._input_data["b3"] = comp_power_coff[2]
self._input_data["b4"] = comp_power_coff[3]
self._input_data["b5"] = comp_power_coff[4]
self._input_data["b6"] = comp_power_coff[5]
def _extract_model_coff(self, hp_model: str, data_type='heat') -> Union[Tuple[List, List], None]:
"""
Extracts heat pump coefficient data for a specific
model. e.g 012, 140
:param hp_model: the model type
:param data_type: indicates whether we're extracting cooling
or heating perfarmcn coefficients
:return:
"""
for energy_system in self._city.energy_systems:
if energy_system.heat_pump.model == hp_model:
if data_type == 'heat':
return energy_system.heat_pump.heating_capacity_coff, energy_system.heat_pump.heating_comp_power_coff
return energy_system.heat_pump.cooling_capacity_coff, energy_system.heat_pump.cooling_comp_power_coff
return None
self._input_data["a1"] = a_coeff[0]
self._input_data["a2"] = a_coeff[1]
self._input_data["a3"] = a_coeff[2]
self._input_data["a4"] = a_coeff[3]
self._input_data["a5"] = a_coeff[4]
self._input_data["a6"] = a_coeff[5]
# additional coefficients for water to water source
if self._water_temp is not None:
self._input_data["a7"] = a_coeff[6]
self._input_data["a8"] = a_coeff[7]
self._input_data["a9"] = a_coeff[8]
self._input_data["a10"] = a_coeff[9]
self._input_data["a11"] = a_coeff[10]
def _get_user_out_put(self):
"""
@ -209,8 +217,7 @@ class HeatPumpExport:
data = [electricity_df, fossil_df]
df = pd.concat(data, axis=1)
df = df.append(df.agg(['sum']))
df = pd.concat([df, df.agg(['sum'])])
s = pd.Series(["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec", "Total"])
df = df.set_index([s])
df.to_csv(self._output_path)

View File

@ -0,0 +1,52 @@
"""
WaterToWaterHPExport exports water to water values after executing insel.
Multiple files are generated for the export
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2021 Project Author Peter Yefi peteryefi@gmail.com
"""
from exports.energy_systems.heat_pump_export import HeatPumpExport
from typing import List, Tuple, Union
class WaterToWaterHPExport(HeatPumpExport):
"""
Exports heat pump values as multiple output files
after executing insel
"""
def __init__(self, base_path, city, output_path, sim_type):
"""
:param base_path: path to energy system files
:param city: the city object
:param output_path: the file to hold insel simulation results
:param sim_type: the simulation type to run: 1 for series, 0 for parallel
"""
tmp_file = 'heat_pumps/w2w_series.txt' if sim_type == 0 else 'heat_pumps/w2w_parallel.txt'
template_path = (base_path / tmp_file)
water_temp = (base_path / 'heat_pumps/wt_hourly3.txt')
super().__init__(base_path, city, output_path, template_path, water_temp)
def _extract_model_coff(self, hp_model: str) -> Union[List, None]:
"""
Extracts heat pump coefficient data for a specific
model. e.g ClimateMaster 156 kW, etc
:param hp_model: the model type
:return:
"""
for energy_system in self._city.energy_systems:
if energy_system.water_to_water_hp.model == hp_model:
return energy_system.water_to_water_hp.power_demand_coff
return None
def execute_insel(self, user_input, hp_model):
"""
Runs insel and produces output files
Runs insel and write the necessary files
:param user_input: a dictionary containing the user
values necessary to run insel
:param hp_model: a string that indicates the heat
pump model to be used e.g. 012, 015
:return:
"""
pow_demand_coeff = self._extract_model_coff(hp_model)
super(WaterToWaterHPExport, self)._run_insel(user_input, pow_demand_coeff, 'w2w.insel')

View File

@ -6,6 +6,8 @@ Copyright © 2020 Project Author Peter Yefi peteryefi@gmail.com
from pathlib import Path
from exports.energy_systems.heat_pump_export import HeatPumpExport
from exports.energy_systems.air_source_hp_export import AirSourceHPExport
from exports.energy_systems.water_to_water_hp_export import WaterToWaterHPExport
class EnergySystemsExportFactory:
@ -13,28 +15,43 @@ class EnergySystemsExportFactory:
Exports factory class for energy systems
"""
def __init__(self, city, user_input, hp_model, output_path, data_type='heat', base_path=None):
def __init__(self, city, user_input, hp_model, output_path, sim_type=0, data_type='heat', base_path=None):
"""
:param city: the city object
:param user_input: user provided input from UI
:param hp_model: the heat pump model to run
:param output_path: the file to hold simulation results
:param sim_type: the simulation type, 0 for series 1 for parallel
:param data_type: indicates whether cooling or heating data is used
:param base_path: the data directory of energy systems
"""
self._city = city
if base_path is None:
base_path = base_path = Path(Path(__file__).parent.parent / 'data/energy_systems')
base_path = Path(Path(__file__).parent.parent / 'data/energy_systems')
self._base_path = base_path
self._user_input = user_input
self._hp_model = hp_model
self._data_type = data_type
self._output_path = output_path
self._sim_type = sim_type
def _export_heat_pump(self):
def _export_heat_pump(self, source):
"""
Exports heat pump performance data as coefficients
of some objective function
:return: None
"""
HeatPumpExport(self._base_path, self._city, self._output_path)\
.run_insel(self._user_input, self._hp_model, self._data_type)
if source == 'air':
AirSourceHPExport(self._base_path, self._city, self._output_path, self._sim_type)\
.execute_insel(self._user_input, self._hp_model, self._data_type)
elif source == 'water':
WaterToWaterHPExport(self._base_path, self._city, self._output_path, self._sim_type)\
.execute_insel(self._user_input, self._hp_model)
def export(self):
def export(self, source='air'):
"""
Export the city given to the class using the given export type handler
:return: None
"""
return getattr(self, '_export_heat_pump', lambda: None)()
return getattr(self, '_export_heat_pump', lambda: None)(source)

View File

@ -3,6 +3,7 @@ TestOccupancyFactory test and validate the city model structure schedules parame
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Soroush Samareh Abolhassani - soroush.samarehabolhassani@mail.concordia.ca
"""
from geomeppy import IDF
@ -18,6 +19,7 @@ class Idf:
_MATERIAL_NOMASS = 'MATERIAL:NOMASS'
_ROUGHNESS = 'MediumRough'
_HOURLY_SCHEDULE = 'SCHEDULE:DAY:HOURLY'
_COMPACT_SCHEDULE = 'SCHEDULE:COMPACT'
_ZONE = 'ZONE'
_LIGHTS = 'LIGHTS'
_PEOPLE = 'PEOPLE'
@ -28,8 +30,8 @@ class Idf:
_ON_OFF = 'On/Off'
_FRACTION = 'Fraction'
_ANY_NUMBER = 'Any Number'
_CONTINUOUS = 'CONTINUOUS'
_DISCRETE = 'DISCRETE'
_CONTINUOUS = 'Continuous'
_DISCRETE = 'Discrete'
idf_surfaces = {
# todo: make an enum for all the surface types
@ -42,9 +44,18 @@ class Idf:
'residential': 'residential_building'
}
idf_type_limits = {
'on_off': 'on/off',
'fraction': 'Fraction',
'any_number': 'Any Number',
'continuous': 'Continuous',
'discrete': 'Discrete'
}
def __init__(self, city, output_path, idf_file_path, idd_file_path, epw_file_path, export_type="Surfaces"):
self._city = city
self._output_path = str((output_path / f'{city.name}.idf').resolve())
self._output_path = str(output_path.resolve())
self._output_file = str((output_path / f'{city.name}.idf').resolve())
self._export_type = export_type
self._idd_file_path = str(idd_file_path)
self._idf_file_path = str(idf_file_path)
@ -59,10 +70,13 @@ class Idf:
self._export()
@staticmethod
def _matrix_to_list(points):
def _matrix_to_list(points, lower_corner):
lower_x = lower_corner[0]
lower_y = lower_corner[1]
lower_z = lower_corner[2]
points_list = []
for point in points:
point_tuple = (point[0], point[1], point[2])
point_tuple = (point[0]-lower_x, point[1]-lower_y, point[2]-lower_z)
points_list.append(point_tuple)
return points_list
@ -103,41 +117,71 @@ class Idf:
Visible_Absorptance=layer.material.visible_absorptance
)
def _add_schedule(self, usage_zone, schedule_type, limit_name='Any Number'):
def _add_daily_schedule(self, usage_zone, schedule):
_schedule = self._idf.newidfobject(self._COMPACT_SCHEDULE, Name=f'{schedule.type} schedules {usage_zone.usage}')
_val = schedule.values
_schedule.Schedule_Type_Limits_Name = self.idf_type_limits[schedule.data_type.lower()]
_schedule.Field_1 = "Through: 12/31"
_schedule.Field_2 = "For: AllDays"
_schedule.Field_3 = "Until: 01:00"
_schedule.Field_4 = _val[0]
_schedule.Field_5 = "Until: 02:00"
_schedule.Field_6 = _val[1]
_schedule.Field_7 = "Until: 03:00"
_schedule.Field_8 = _val[2]
_schedule.Field_9 = "Until: 04:00"
_schedule.Field_10 = _val[3]
_schedule.Field_11 = "Until: 05:00"
_schedule.Field_12 = _val[4]
_schedule.Field_13 = "Until: 06:00"
_schedule.Field_14 = _val[5]
_schedule.Field_15 = "Until: 07:00"
_schedule.Field_16 = _val[6]
_schedule.Field_17 = "Until: 08:00"
_schedule.Field_18 = _val[7]
_schedule.Field_19 = "Until: 09:00"
_schedule.Field_20 = _val[8]
_schedule.Field_21 = "Until: 10:00"
_schedule.Field_22 = _val[9]
_schedule.Field_23 = "Until: 11:00"
_schedule.Field_24 = _val[10]
_schedule.Field_25 = "Until: 12:00"
_schedule.Field_26 = _val[11]
_schedule.Field_27 = "Until: 13:00"
_schedule.Field_28 = _val[12]
_schedule.Field_29 = "Until: 14:00"
_schedule.Field_30 = _val[13]
_schedule.Field_31 = "Until: 15:00"
_schedule.Field_32 = _val[14]
_schedule.Field_33 = "Until: 16:00"
_schedule.Field_34 = _val[15]
_schedule.Field_35 = "Until: 17:00"
_schedule.Field_36 = _val[16]
_schedule.Field_37 = "Until: 18:00"
_schedule.Field_38 = _val[17]
_schedule.Field_39 = "Until: 19:00"
_schedule.Field_40 = _val[18]
_schedule.Field_41 = "Until: 20:00"
_schedule.Field_42 = _val[19]
_schedule.Field_43 = "Until: 21:00"
_schedule.Field_44 = _val[20]
_schedule.Field_45 = "Until: 22:00"
_schedule.Field_46 = _val[21]
_schedule.Field_47 = "Until: 23:00"
_schedule.Field_48 = _val[22]
_schedule.Field_49 = "Until: 24:00"
_schedule.Field_50 = _val[23]
def _add_schedule(self, usage_zone, schedule_type):
for schedule in self._idf.idfobjects[self._HOURLY_SCHEDULE]:
if schedule.Name == f'{schedule_type} schedules {usage_zone.usage}':
return
if usage_zone.schedules is None or schedule_type not in usage_zone.schedules:
# there are no schedule for this type
return
schedule = self._idf.newidfobject(self._HOURLY_SCHEDULE, Name=f'{schedule_type} schedules {usage_zone.usage}')
schedule.Schedule_Type_Limits_Name = limit_name
schedule.Hour_1 = usage_zone.schedules[schedule_type]["WD"][0]
schedule.Hour_2 = usage_zone.schedules[schedule_type]["WD"][1]
schedule.Hour_3 = usage_zone.schedules[schedule_type]["WD"][2]
schedule.Hour_4 = usage_zone.schedules[schedule_type]["WD"][3]
schedule.Hour_5 = usage_zone.schedules[schedule_type]["WD"][4]
schedule.Hour_6 = usage_zone.schedules[schedule_type]["WD"][5]
schedule.Hour_7 = usage_zone.schedules[schedule_type]["WD"][6]
schedule.Hour_8 = usage_zone.schedules[schedule_type]["WD"][7]
schedule.Hour_9 = usage_zone.schedules[schedule_type]["WD"][8]
schedule.Hour_10 = usage_zone.schedules[schedule_type]["WD"][9]
schedule.Hour_11 = usage_zone.schedules[schedule_type]["WD"][10]
schedule.Hour_12 = usage_zone.schedules[schedule_type]["WD"][11]
schedule.Hour_13 = usage_zone.schedules[schedule_type]["WD"][12]
schedule.Hour_14 = usage_zone.schedules[schedule_type]["WD"][13]
schedule.Hour_15 = usage_zone.schedules[schedule_type]["WD"][14]
schedule.Hour_16 = usage_zone.schedules[schedule_type]["WD"][15]
schedule.Hour_17 = usage_zone.schedules[schedule_type]["WD"][16]
schedule.Hour_18 = usage_zone.schedules[schedule_type]["WD"][17]
schedule.Hour_19 = usage_zone.schedules[schedule_type]["WD"][18]
schedule.Hour_20 = usage_zone.schedules[schedule_type]["WD"][19]
schedule.Hour_21 = usage_zone.schedules[schedule_type]["WD"][20]
schedule.Hour_22 = usage_zone.schedules[schedule_type]["WD"][21]
schedule.Hour_23 = usage_zone.schedules[schedule_type]["WD"][22]
schedule.Hour_24 = usage_zone.schedules[schedule_type]["WD"][23]
for schedule in usage_zone.schedules:
if schedule.type == schedule_type:
if schedule.time_range == "day":
return self._add_daily_schedule(usage_zone, schedule)
return
def _add_construction(self, thermal_boundary):
for construction in self._idf.idfobjects[self._CONSTRUCTION]:
if construction.Name == thermal_boundary.construction_name:
@ -183,7 +227,9 @@ class Idf:
thermostat = self._add_thermostat(usage_zone)
self._idf.newidfobject(self._IDEAL_LOAD_AIR_SYSTEM,
Zone_Name=usage_zone.id,
Cooling_Availability_Schedule_Name=f'Refrigeration schedules {usage_zone.usage}',
System_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {usage_zone.usage}',
Heating_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {usage_zone.usage}',
Cooling_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {usage_zone.usage}',
Template_Thermostat_Name=thermostat.Name)
def _add_occupancy(self, usage_zone):
@ -194,7 +240,7 @@ class Idf:
Number_of_People_Calculation_Method="People",
Number_of_People=500, # todo: get people from where?
Fraction_Radiant=0.3, # todo: howto get this from InternalGains
Activity_Level_Schedule_Name='occupant schedules'
Activity_Level_Schedule_Name=f'Occupancy schedules {usage_zone.usage}'
)
def _add_equipment(self, usage_zone):
@ -227,17 +273,19 @@ class Idf:
Export the idf file into the given path
export type = "Surfaces|Block"
"""
for building in self._city.buildings:
for usage_zone in building.usage_zones:
self._add_schedule(usage_zone, "Infiltration")
self._add_schedule(usage_zone, "Lights")
self._add_schedule(usage_zone, "Occupancy")
self._add_schedule(usage_zone, "Refrigeration", self._ON_OFF)
self._add_schedule(usage_zone, "Refrigeration")
self._add_schedule(usage_zone, "HVAC Avail")
self._add_zone(usage_zone)
self._add_heating_system(usage_zone)
# self._add_infiltration(usage_zone)
# self._add_occupancy(usage_zone)
self._add_infiltration(usage_zone)
self._add_occupancy(usage_zone)
for thermal_zone in building.thermal_zones:
for thermal_boundary in thermal_zone.thermal_boundaries:
self._add_construction(thermal_boundary)
@ -246,8 +294,27 @@ class Idf:
self._add_surfaces(building)
else:
self._add_block(building)
self._idf.newidfobject(
"OUTPUT:VARIABLE",
Variable_Name="Zone Ideal Loads Supply Air Total Heating Energy",
Reporting_Frequency="Hourly",
)
self._idf.newidfobject(
"OUTPUT:VARIABLE",
Variable_Name="Zone Ideal Loads Supply Air Total Cooling Energy",
Reporting_Frequency="Hourly",
)
self._idf.match()
self._idf.saveas(str(self._output_path))
self._idf.intersect_match()
self._idf.saveas(str(self._output_file))
return self._idf
def run(self):
"""
Start the energy plus simulation
"""
self._idf.run(expandobjects=True, readvars=True, output_directory=self._output_path,
output_prefix=f'{self._city.name}_')
def _add_block(self, building):
_points = self._matrix_to_2d_list(building.foot_print.coordinates)
@ -267,6 +334,7 @@ class Idf:
self._idf.intersect_match()
def _add_surfaces(self, building):
for thermal_zone in building.thermal_zones:
for boundary in thermal_zone.thermal_boundaries:
idf_surface_type = self.idf_surfaces[boundary.surface.type]
@ -274,5 +342,5 @@ class Idf:
surface = self._idf.newidfobject(self._SURFACE, Name=f'{boundary.surface.name}',
Surface_Type=idf_surface_type, Zone_Name=usage_zone.id,
Construction_Name=boundary.construction_name)
coordinates = self._matrix_to_list(boundary.surface.solid_polygon.coordinates)
coordinates = self._matrix_to_list(boundary.surface.solid_polygon.coordinates, self._city.lower_corner)
surface.setcoords(coordinates)

View File

@ -122,8 +122,8 @@
No, !- Do Zone Sizing Calculation
No, !- Do System Sizing Calculation
No, !- Do Plant Sizing Calculation
Yes, !- Run Simulation for Sizing Periods
No, !- Run Simulation for Weather File Run Periods
No, !- Run Simulation for Sizing Periods
Yes, !- Run Simulation for Weather File Run Periods
No, !- Do HVAC Sizing Simulation for Sizing Periods
1; !- Maximum Number of HVAC Sizing Simulation Passes
@ -149,3 +149,4 @@
Output:Table:SummaryReports,
AllSummary; !- Report 1 Name
Output:Diagnostics,DisplayUnusedSchedules;

View File

@ -32,7 +32,8 @@ class YearlyFromDailySchedules:
values = []
for month in range(1, 13):
for day in range(1, cal.monthlen(self._year, month)+1):
_, number_days = cal.monthrange(self._year, month)
for day in range(1, number_days+1):
week_day = cal.weekday(self._year, month, day)
values.extend(weekly_schedules[week_day])
yearly_schedule.type = self._daily_schedules[0].type

View File

@ -1,5 +1,5 @@
"""
XlsxHeatPumpParameters import the heat pump information
AirSourceHeatPumpParameters import the heat pump information
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Peter Yefi peteryefi@gmail.com
Contributor Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
@ -7,7 +7,7 @@ Contributor Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
import pandas as pd
from typing import Dict
from city_model_structure.energy_systems.heat_pump import HeatPump
from city_model_structure.energy_systems.air_source_hp import AirSourceHP
from city_model_structure.energy_system import EnergySystem
from scipy.optimize import curve_fit
import numpy as np
@ -15,14 +15,14 @@ from typing import List
import itertools
class XlsxHeatPumpParameters:
class AirSourceHeatPumpParameters:
"""
XlsxHeatPumpParameters class
AirSourceHeatPumpParameters class
"""
def __init__(self, city, base_path):
self._city = city
self._base_path = (base_path / 'heat_pumps/Air Source.xlsx')
self._base_path = (base_path / 'heat_pumps/Air source.xlsx')
def _read_file(self) -> Dict:
"""
@ -31,6 +31,7 @@ class XlsxHeatPumpParameters:
:return : Dict
"""
xl_file = pd.ExcelFile(self._base_path)
heat_pump_dfs = {sheet_name: xl_file.parse(sheet_name)
for sheet_name in xl_file.sheet_names}
@ -38,8 +39,10 @@ class XlsxHeatPumpParameters:
heating_data = {}
for sheet, dataframe in heat_pump_dfs.items():
if sheet == "Summary":
continue
if 'Summary' in sheet:
continue
# Remove nan rows and columns and extract cooling and heating data
# for each sheet
df = heat_pump_dfs[sheet].dropna(axis=1, how='all')
@ -65,24 +68,22 @@ class XlsxHeatPumpParameters:
"""
Enriches the city with information from file
"""
heap_pump_data = self._read_file()
heat_pump_data = self._read_file()
for (k_cool, v_cool), (k_heat, v_heat) in \
zip(heap_pump_data["cooling"].items(), heap_pump_data["heating"].items()):
heat_pump = HeatPump()
zip(heat_pump_data["cooling"].items(), heat_pump_data["heating"].items()):
heat_pump = AirSourceHP()
heat_pump.model = k_cool
h_data = self._extract_heat_pump_data(v_heat)
c_data = self._extract_heat_pump_data(v_cool)
heat_pump.cooling_capacity = c_data[0]
heat_pump.cooling_comp_power = c_data[1]
heat_pump.cooling_capacity_coff = self._compute_coefficients(c_data[0], "cool")
heat_pump.cooling_comp_power_coff = self._compute_coefficients(c_data[1], "cool")
heat_pump.cooling_capacity_coff = self._compute_coefficients(c_data, "cool")
heat_pump.heating_capacity = h_data[0]
heat_pump.heating_comp_power = h_data[1]
heat_pump.heating_capacity_coff = self._compute_coefficients(h_data[0])
heat_pump.heating_comp_power_coff = self._compute_coefficients(h_data[1])
heat_pump.heating_capacity_coff = self._compute_coefficients(h_data)
energy_system = EnergySystem('{} capacity heat pump'.format(heat_pump.model), 0, [], None)
energy_system.heat_pump = heat_pump
energy_system.air_source_hp = heat_pump
self._city.add_city_object(energy_system)
return self._city
@ -121,10 +122,13 @@ class XlsxHeatPumpParameters:
x_values = heat_x_values if data_type == "heat" else cool_x_values
x_values = x_values.tolist()
# convert list of lists to one list
heat_pump_data = list(itertools.chain.from_iterable(heat_pump_data))
hp_data = [i/j for i, j in
zip(list(itertools.chain.from_iterable(heat_pump_data[0])),
list(itertools.chain.from_iterable(heat_pump_data[1])))]
# Compute heat output coefficients
popt, _ = curve_fit(self._objective_function, [x_values, out_temp], heat_pump_data)
popt, _ = curve_fit(self._objective_function, [x_values, out_temp], hp_data)
return popt.tolist()
def _objective_function(self, xdata: List, a1: float, a2: float, a3: float, a4: float, a5: float, a6: float) -> float:

View File

@ -0,0 +1,169 @@
"""
WaterToWaterHPParameters import the heat pump information
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2021 Project Author Peter Yefi peteryefi@gmail.com
"""
import pandas as pd
from typing import Dict
from city_model_structure.energy_systems.water_to_water_hp import WaterToWaterHP
from city_model_structure.energy_system import EnergySystem
from scipy.optimize import curve_fit
import numpy as np
from typing import List
class WaterToWaterHPParameters:
"""
WaterToWaterHPParameters class
"""
def __init__(self, city, base_path):
self._city = city
self._base_path = (base_path / 'heat_pumps/water_to_water.xlsx')
def _read_file(self) -> Dict:
"""
reads xlsx file containing water to water heat pump information
into a dictionary
:return : Dict
"""
xl_file = pd.ExcelFile(self._base_path)
heat_pump_dfs = {sheet_name: xl_file.parse(sheet_name)
for sheet_name in xl_file.sheet_names}
hp_data = {}
flow_rates = {
'156': [2.84, 4.23, 5.68],
'256': [4.73, 7.13, 9.446],
'335': [6.62, 9.97, 12.93],
}
for sheet, dataframe in heat_pump_dfs.items():
df = heat_pump_dfs[sheet].dropna(axis=1, how='all')
df = df.iloc[3:, 6:35]
if '156' in sheet:
hp_data[sheet] = self._extract_required_hp_data(df, [0, 10, 25, 40, 55, 67], flow_rates['156'])
elif '256' in sheet:
hp_data[sheet] = self._extract_required_hp_data(df, [0, 9, 24, 39, 54, 66], flow_rates['256'])
elif '335' in sheet:
hp_data[sheet] = self._extract_required_hp_data(df, [0, 11, 26, 41, 56, 69], flow_rates['335'])
return hp_data
def _extract_required_hp_data(self, dataframe, ranges, flow_rates):
"""
Extracts 156 Kw water to water heat pump data
:param dataframe: dataframe containing all data
:param ranges: the range of values to extract
:param flow_rates: the flow rates of water through pump
:return: Dict
"""
# extract data rows and columns
data = {'tc': self._extract_hp_data(dataframe, [1, 11, 21], ranges),
'pd': self._extract_hp_data(dataframe, [2, 12, 22], ranges),
'lwt': self._extract_hp_data(dataframe, [5, 15, 25], ranges),
'fr': (self._extract_flow_and_ewt(dataframe, ranges, [1, 11, 21], flow_rates))[0],
'ewt': (self._extract_flow_and_ewt(dataframe, ranges, [1, 11, 21], flow_rates))[1]}
# range values for extracting data
return data
def _extract_hp_data(self, df, columns, ranges):
"""
Extract variable specific (LWT, PD or TC) data from water to water hp
:param df: the dataframe
:param columns: the columns to extract data from
:param ranges: the range of values to extract
:return: List
"""
data = df.iloc[ranges[0]:ranges[1], columns[0]].append(df.iloc[ranges[0]:ranges[1], columns[1]])\
.append(df.iloc[ranges[0]:ranges[1], columns[2]])
for i in range(1, 5):
data = data.append(df.iloc[ranges[i]:ranges[i + 1], columns[0]]).append(
df.iloc[ranges[i]:ranges[i + 1], columns[1]]).append(df.iloc[ranges[i]:ranges[i + 1], columns[2]])
return data.dropna().values.tolist()
def _extract_flow_and_ewt(self, df, ranges, columns, flow_rates):
"""
Create the flow and ewt data based on the length of the various
columns for the variables being extracted
:param df: the dataframe
:param ranges: the range of values to extract
:param columns: the columns to extract data from
:param flow_rates: flow rate values
:return:
"""
ewt_values = [-1.111111111, 4.444444444, 10, 15.55555556, 21.11111111]
length = [len(df.iloc[ranges[0]:ranges[1], columns[0]].dropna()),
len(df.iloc[ranges[0]:ranges[1], columns[1]].dropna()),
len(df.iloc[ranges[0]:ranges[1], columns[2]].dropna())]
ewt_data = np.repeat(ewt_values[0], sum(length))
flow_rates_data = np.repeat(flow_rates, length)
for i in range(1, 5):
length = [len(df.iloc[ranges[i]:ranges[i + 1], columns[0]].dropna()),
len(df.iloc[ranges[i]:ranges[i + 1], columns[1]].dropna()),
len(df.iloc[ranges[i]:ranges[i + 1], columns[2]].dropna())]
flow_rates_data = np.append(flow_rates_data, np.repeat(flow_rates, length))
ewt_data = np.append(ewt_data, np.repeat(ewt_values[i], sum(length)))
return flow_rates_data.tolist(), ewt_data.tolist()
def enrich_city(self):
"""
Enriches the city with information from file
"""
heap_pump_data = self._read_file()
for model, data in heap_pump_data.items():
heat_pump = WaterToWaterHP()
heat_pump.model = model.strip()
heat_pump.total_cooling_capacity = data['tc']
heat_pump.power_demand = data['pd']
heat_pump.flow_rate = data['fr']
heat_pump.entering_water_temp = data['ewt']
heat_pump.leaving_water_temp = data['lwt']
heat_pump.power_demand_coff = self._compute_coefficients(data)
energy_system = EnergySystem(heat_pump.model, 0, [], None)
energy_system.water_to_water_hp = heat_pump
self._city.add_city_object(energy_system)
return self._city
def _compute_coefficients(self, heat_pump_data: Dict) -> List[float]:
"""
Compute heat output and electrical demand coefficients
from heating performance data
:param heat_pump_data: a dictionary of heat pump data.
:return: Tuple[Dict, Dict]
"""
demand = [i / j for i, j in zip(heat_pump_data['tc'], heat_pump_data['pd'])]
# Compute heat output coefficients
popt, _ = curve_fit(self._objective_function, [heat_pump_data['ewt'], heat_pump_data['lwt'], heat_pump_data['fr']],
demand)
return popt.tolist()
def _objective_function(self, xdata: List, a1: float, a2: float, a3: float, a4: float, a5: float, a6: float,
a7: float, a8: float, a9: float, a10: float, a11: float) -> float:
"""
Objective function for computing coefficients
:param xdata:
:param a1: float
:param a2: float
:param a3: float
:param a4: float
:param a5: float
:param a6: float
:param a7: float
:param a8: float
:param a9: float
:param a10: float
:param a11: float
:return:
"""
x, y, t = xdata
return (a1 * x ** 2) + (a2 * x) + (a3 * y ** 2) + (a4 * y) + (a5 * t ** 2) + (a6 * t) + (a7 * x * y) + (
a8 * x * t) + (a9 * y * t) + (a10 * x * y * t) + a11

View File

@ -2,9 +2,11 @@
EnergySystemsFactory retrieve the energy system module for the given region
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Pilar Monsalvete pilar.monsalvete@concordi.ca
Contributor Peter Yefi peteryefi@gmail.com
"""
from pathlib import Path
from imports.energy_systems.xlsx_heat_pump_parameters import XlsxHeatPumpParameters
from imports.energy_systems.air_source_hp_parameters import AirSourceHeatPumpParameters
from imports.energy_systems.water_to_water_hp_parameters import WaterToWaterHPParameters
class EnergySystemsFactory:
@ -19,11 +21,17 @@ class EnergySystemsFactory:
self._city = city
self._base_path = base_path
def _xlsx_heat_pump(self):
def _air_source_hp(self):
"""
Enrich the city by using xlsx heat pump information
"""
XlsxHeatPumpParameters(self._city, self._base_path).enrich_city()
AirSourceHeatPumpParameters(self._city, self._base_path).enrich_city()
def _water_to_water_hp(self):
"""
Enrich the city by using water to water heat pump information
"""
WaterToWaterHPParameters(self._city, self._base_path).enrich_city()
def enrich(self):
"""

View File

@ -3,6 +3,7 @@ Rhino module parses rhino files and import the geometry into the city model stru
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
import numpy as np
from numpy import inf
from rhino3dm import *
from rhino3dm._rhino3dm import MeshType

View File

@ -15,4 +15,6 @@ parseidf~=1.0.0
ply~=3.11
rhino3dm~=7.11.1
scipy==1.7.1
PyYAML==6.0
PyYAML==6.0
yaml~=0.2.5
pyecore~=0.12.2

View File

@ -7,7 +7,7 @@ import pandas as pd
from unittest import TestCase
from imports.geometry_factory import GeometryFactory
from imports.energy_systems_factory import EnergySystemsFactory
from city_model_structure.energy_systems.heat_pump import HeatPump
from city_model_structure.energy_systems.air_source_hp import AirSourceHP
from exports.energy_systems_factory import EnergySystemsExportFactory
import os
@ -23,17 +23,17 @@ class TestEnergySystemsFactory(TestCase):
:return: None
"""
city_file = "../unittests/tests_data/C40_Final.gml"
self._output_path = "../unittests/tests_data/user_output.csv"
self._output_path = "../unittests/tests_data/as_user_output.csv"
self._city = GeometryFactory('citygml', city_file).city
EnergySystemsFactory('xlsx heat pump', self._city).enrich()
EnergySystemsFactory('air source hp', self._city).enrich()
def test_heat_pump_import(self):
def test_air_source_heat_pump_import(self):
self.assertIsNotNone(self._city.energy_systems, 'City has energy systems')
self.assertIsInstance(self._city.energy_systems[0].heat_pump, HeatPump)
self.assertEqual(self._city.energy_systems[0].heat_pump.model, '012')
self.assertEqual(self._city.energy_systems[len(self._city.energy_systems) - 1].heat_pump.model, '140')
self.assertIsInstance(self._city.energy_systems[0].air_source_hp, AirSourceHP)
self.assertEqual(self._city.energy_systems[0].air_source_hp.model, '012')
self.assertEqual(self._city.energy_systems[16].air_source_hp.model, '140')
def test_heat_pump_export(self):
def test_air_source_heat_pump_export(self):
# User defined paramenters
user_input = {
'StartYear': 2020,
@ -52,7 +52,7 @@ class TestEnergySystemsFactory(TestCase):
EnergySystemsExportFactory(self._city, user_input, '012', self._output_path).export()
df = pd.read_csv(self._output_path)
self.assertEqual(df.shape, (13, 3))
self.assertEqual(df.iloc[0, 1], 3045398.0)
self.assertEqual(df.iloc[0, 1], 1867715.88)
def tearDown(self) -> None:
try:

View File

@ -0,0 +1,63 @@
"""
Test EnergySystemsFactory and various heatpump models
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2021 Project Author Peter Yefi peteryefi@gmail.com
"""
from unittest import TestCase
from imports.geometry_factory import GeometryFactory
from imports.energy_systems_factory import EnergySystemsFactory
from city_model_structure.energy_systems.water_to_water_hp import WaterToWaterHP
from exports.energy_systems_factory import EnergySystemsExportFactory
import pandas as pd
import os
class TestEnergySystemsFactory(TestCase):
"""
TestEnergySystemsFactory for Water to Water HP
"""
def setUp(self) -> None:
"""
Test setup
:return: None
"""
city_file = "../unittests/tests_data/C40_Final.gml"
self._output_path = "../unittests/tests_data/w2w_user_output.csv"
self._city = GeometryFactory('citygml', city_file).city
EnergySystemsFactory('water to water hp', self._city).enrich()
def test_water_to_water_heat_pump_import(self):
self.assertIsNotNone(self._city.energy_systems, 'City has energy systems')
self.assertIsInstance(self._city.energy_systems[0].water_to_water_hp, WaterToWaterHP)
self.assertEqual(self._city.energy_systems[0].water_to_water_hp.model, 'ClimateMaster 156 kW')
self.assertEqual(self._city.energy_systems[2].water_to_water_hp.model, 'ClimateMaster 335 kW')
def test_water_to_water_heat_pump_export(self):
# User defined paramenters
user_input = {
'StartYear': 2020,
'EndYear': 2021,
'MaximumHPEnergyInput': 8000,
'HoursOfStorageAtMaxDemand': 1,
'BuildingSuppTemp': 40,
'TemperatureDifference': 15,
'FuelLHV': 47100,
'FuelPrice': 0.12,
'FuelEF': 1887,
'FuelDensity': 0.717,
'HPSupTemp': 60
}
EnergySystemsExportFactory(self._city, user_input, 'ClimateMaster 156 kW', self._output_path).export('water')
df = pd.read_csv(self._output_path)
print(df.shape)
#self.assertEqual(df.shape, (13, 3))
#self.assertEqual(df.iloc[0, 1], 3045398.0)
def tearDown(self) -> None:
try:
os.remove(self._output_path)
except OSError:
pass

View File

@ -0,0 +1,37 @@
"""
TestGeometryFactory test and validate the city model structure geometric parameters
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
from unittest import TestCase
from catalogs.greenery_catalog_factory import GreeneryCatalogFactory
class TestGreeneryCatalog(TestCase):
def test_catalog(self):
catalog = GreeneryCatalogFactory('nrel').catalog_debug
catalog_categories = catalog.names()
vegetations = catalog.names('vegetations')
plants = catalog.names('plants')
soils = catalog.names('soils')
self.assertTrue(len(catalog_categories) == 3)
self.assertTrue(len(vegetations['vegetations']) == 4)
self.assertTrue(len(plants['plants']) == 14)
self.assertTrue(len(soils['soils']) == 6)
with self.assertRaises(ValueError):
catalog.names('unknown')
# retrieving all the entries should not raise any exceptions
for category in catalog_categories:
for value in catalog_categories[category]:
catalog.get_entry(value)
with self.assertRaises(IndexError):
catalog.get_entry('unknown')
self.assertTrue(len(catalog.entries().vegetations) == 4)
self.assertTrue(len(catalog.entries().plants) == 14)
self.assertTrue(len(catalog.entries().soils) == 6)

View File

@ -11,6 +11,7 @@ from imports.construction_factory import ConstructionFactory
from imports.usage_factory import UsageFactory
from imports.construction_factory import ConstructionFactory
from imports.geometry.helpers.geometry_helper import GeometryHelper
from imports.construction_factory import ConstructionFactory
class TestUsageFactory(TestCase):

View File

@ -14,8 +14,8 @@
<gen:stringAttribute name="gross_floor_raea_unit">
<gen:value>m2</gen:value>
</gen:stringAttribute>
<bldg:function>1010</bldg:function>
<bldg:yearOfConstruction>1996</bldg:yearOfConstruction>
<bldg:function>residential</bldg:function>
<bldg:measuredHeight>5.3</bldg:measuredHeight>
<bldg:storeysAboveGround>1</bldg:storeysAboveGround>
<bldg:lod2Solid>