Skip to content

Commit

Permalink
Merge pull request #3408 from architecture-building-systems/revert-34…
Browse files Browse the repository at this point in the history
…06-revert-3265-mac-arm-native-support

Enable Mac ARM support
  • Loading branch information
reyery committed Jan 16, 2024
2 parents b91cb20 + a9d3750 commit 6b70996
Show file tree
Hide file tree
Showing 33 changed files with 25,233 additions and 205 deletions.
24 changes: 24 additions & 0 deletions .github/workflows/conda_lock.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: conda-lock

on:
pull_request:
types: [opened, synchronize]
branches: [master]

jobs:
test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Install conda-lock with Micromamba
uses: mamba-org/setup-micromamba@v1
with:
environment-name: ci
create-args: conda-lock
init-shell: bash

- name: Run conda-lock
run: conda-lock --mamba -f environment.yml -p osx-64 -p linux-64 -p win-64 --lockfile ${{ runner.temp }}/conda-lock.yml
shell: bash -el {0}
2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@ include cea/workflows/*.yml
include cea/dev/conda.bat

graft cea/resources/radiation/bin

graft cea/lib
2 changes: 1 addition & 1 deletion bin/test_substation_calc_hex_cooling.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def calc_HEX_cooling_orig(Q, UA, thi, tho, tci, ch):
else:
tco = 0
cc = 0
return np.float(tco), np.float(cc)
return float(tco), float(cc)


if __name__ == '__main__':
Expand Down
2 changes: 1 addition & 1 deletion bin/test_substation_calc_hex_heating.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def calc_HEX_heating_orig(Q, UA, thi, tco, tci, cc):
else:
tho = 0
ch = 0
return np.float(tho), np.float(ch)
return float(tho), float(ch)


if __name__ == '__main__':
Expand Down
7 changes: 5 additions & 2 deletions cea/datamanagement/streets_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import osmnx
import osmnx.utils_graph
import pandas as pd
from geopandas import GeoDataFrame as Gdf

import cea.config
Expand All @@ -27,8 +28,10 @@ def calc_bounding_box(locator):
# connect both files and avoid repetition
data_zone, data_dis = get_zone_and_surr_in_projected_crs(locator)
data_dis = data_dis.loc[~data_dis["Name"].isin(data_zone["Name"])]
data = data_zone.append(data_dis, ignore_index=True, sort=True)
data = data.to_crs(get_geographic_coordinate_system())
data = pd.concat([
data_zone.to_crs(get_geographic_coordinate_system()),
data_dis.to_crs(get_geographic_coordinate_system())
], ignore_index=True, sort=True)
result = data.total_bounds # in float
return result

Expand Down
7 changes: 4 additions & 3 deletions cea/datamanagement/terrain_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,13 @@ def request_elevation(lon, lat):


def calc_bounding_box_projected_coordinates(locator):

# connect both files and avoid repetition
data_zone, data_dis = get_zone_and_surr_in_projected_crs(locator)
data_dis = data_dis.loc[~data_dis["Name"].isin(data_zone["Name"])]
data = data_zone.append(data_dis, ignore_index = True, sort=True)
data = data.to_crs(get_geographic_coordinate_system())
data = pd.concat([
data_zone.to_crs(get_geographic_coordinate_system()),
data_dis.to_crs(get_geographic_coordinate_system())
], ignore_index=True, sort=True)
lon = data.geometry[0].centroid.coords.xy[0][0]
lat = data.geometry[0].centroid.coords.xy[1][0]
crs = get_projected_coordinate_system(float(lat), float(lon))
Expand Down
19 changes: 11 additions & 8 deletions cea/datamanagement/zone_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -500,16 +500,19 @@ def polygon_to_zone(buildings_floors, buildings_floors_below_ground, buildings_h
lon = poly.geometry[0].centroid.coords.xy[0][0]
lat = poly.geometry[0].centroid.coords.xy[1][0]
# get all footprints in the district tagged as 'building' or 'building:part' in OSM
shapefile = osmnx.geometries.geometries_from_polygon(polygon=poly['geometry'].values[0], tags={"building": True})
shapefile = osmnx.features.features_from_polygon(polygon=poly['geometry'].values[0], tags={"building": True})
if include_building_parts:
# get all footprints in the district tagged as 'building' or 'building:part' in OSM
building_parts = osmnx.geometries.geometries_from_polygon(polygon=poly['geometry'].values[0],
try:
# get all footprints in the district tagged as 'building' or 'building:part' in OSM
building_parts = osmnx.features.features_from_polygon(polygon=poly['geometry'].values[0],
tags={"building": ["part"]})
shapefile = pd.concat([shapefile, building_parts], ignore_index=True)
# using building:part tags requires fixing overlapping polygons
if not fix_overlapping:
print('Building parts included, fixing overlapping geometries activated.')
fix_overlapping = True
shapefile = pd.concat([shapefile, building_parts], ignore_index=True)
# using building:part tags requires fixing overlapping polygons
if not fix_overlapping:
print('Building parts included, fixing overlapping geometries activated.')
fix_overlapping = True
except osmnx._errors.InsufficientResponseError:
pass

# clean geometries
shapefile = clean_geometries(shapefile)
Expand Down
2 changes: 1 addition & 1 deletion cea/glossary.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def read_glossary_df(plugins):
cd = schemas[lm]["schema"]["columns"][col] # cd: column definition
rows.append(glossary_row(script, file_path, col, lm, cd, worksheet=""))

glossary_df = glossary_df.append(rows, ignore_index=True)
glossary_df = pd.concat([glossary_df, pd.DataFrame(rows)], ignore_index=True)
glossary_df['key'] = glossary_df['FILE_NAME'] + '!!!' + glossary_df['VARIABLE']
glossary_df = glossary_df.set_index(['key'])
glossary_df = glossary_df.sort_values(by=['LOCATOR_METHOD', 'FILE_NAME', 'VARIABLE'])
Expand Down
18 changes: 5 additions & 13 deletions cea/interfaces/dashboard/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,15 @@
import cea.plots
import cea.plots.cache

socketio = None


def main(config):
config.restricted_to = None # allow access to the whole config file
plot_cache = cea.plots.cache.MemoryPlotCache(config.project)
app = Flask(__name__, static_folder='base/static', )
CORS(app)
app.config.from_mapping({'SECRET_KEY': 'secret'})

global socketio
socketio = SocketIO(app, cors_allowed_origins="*")

def shutdown(signum, frame):
print("Shutting Down...")
socketio.stop()
signal.signal(signal.SIGINT, shutdown)

if config.server.browser:
from cea.interfaces.dashboard.frontend import blueprint as frontend
app.register_blueprint(frontend)
Expand All @@ -44,16 +35,17 @@ def shutdown(signum, frame):
app.plot_cache = plot_cache
app.socketio = socketio

print("start socketio.run")

print("start CEA dashboard server")
if config.server.browser:
url = f"http://{config.server.host}:{config.server.port}"
print(f"Open {url} in your browser to access the GUI")
webbrowser.open(url)

print("Press Ctrl+C to stop server")
socketio.run(app, host=config.server.host, port=config.server.port)
print("done socketio.run")
socketio.run(app, host=config.server.host, port=config.server.port, allow_unsafe_werkzeug=True)

print("\nserver exited")


if __name__ == '__main__':
Expand Down
2 changes: 1 addition & 1 deletion cea/interfaces/dashboard/server/streams.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"""

from flask import request, current_app
from flask_restx import Namespace, Resource, fields
from flask_restx import Namespace, Resource

__author__ = "Daren Thomas"
__copyright__ = "Copyright 2019, Architecture and Building Systems - ETH Zurich"
Expand Down
Binary file added cea/lib/Darwin/libepanet.dylib
Binary file not shown.
33 changes: 33 additions & 0 deletions cea/lib/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"""
This only works for wntr v0.2.3
Apple Silicon lib builds from:
WNTR (https://github.com/USEPA/WNTR/tree/0.2.3)
set `use_swig` and `build` to True in setup.py
make sure swig is installed
python setup.py build_ext --inplace
copy _evaluator and _network from build
EPANET (https://github.com/OpenWaterAnalytics/EPANET/tree/v2.0.12)
replace all `malloc.h` with `stdlib.h`
gcc -dynamiclib *.c -o libepanet.dylib
copy libepanet.dylib to Darwin folder
"""

import platform
import sys
import os

if sys.platform == "darwin" and platform.processor() == "arm":
# Add required shared objects to path before importing wntr
sys.path.append(os.path.dirname(__file__))

# Make sure correct version of wntr is installed
import wntr
if wntr.__version__ != '0.2.3':
raise ImportError(f"Require wntr version 0.2.3, found {wntr.__version__}")

print("Applying fix for Apple Silicon")
# Change where wntr looks for libepanet
import wntr.epanet.toolkit
wntr.epanet.toolkit.epanet_toolkit = "cea.lib"
Binary file added cea/lib/_evaluator.cpython-38-darwin.so
Binary file not shown.
Binary file added cea/lib/_network_isolation.cpython-38-darwin.so
Binary file not shown.
22 changes: 12 additions & 10 deletions cea/optimization/preprocessing/decentralized_buildings_cooling.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,12 +233,14 @@ def disconnected_cooling_for_building(building_name, supply_systems, lca, locato
# capacity of cooling technologies
operation_results[2][0] = Qc_nom_AHU_ARU_SCU_W
operation_results[2][4] = Qc_nom_AHU_ARU_SCU_W # 4: ACH_SC_FP
q_total_load = q_chw_single_ACH_Wh[None, :] + q_sc_gen_FP_Wh[None,
:] + q_load_Boiler_FP_to_single_ACH_to_AHU_ARU_SCU_Wh[None, :]
system_COP_list = np.divide(q_total_load, (
el_total_Wh[None, :] + q_gas_Boiler_FP_to_single_ACH_to_AHU_ARU_SCU_Wh[None, :])).flatten()
system_COP = np.nansum(q_total_load * system_COP_list) / np.nansum(
q_total_load) # weighted average of the system efficiency
q_total_load = (q_chw_single_ACH_Wh[None, :] +
q_sc_gen_FP_Wh[None, :] +
q_load_Boiler_FP_to_single_ACH_to_AHU_ARU_SCU_Wh[None, :])
system_COP_list = np.divide(q_total_load,
(el_total_Wh[None, :] + q_gas_Boiler_FP_to_single_ACH_to_AHU_ARU_SCU_Wh[None, :])
).flatten()
system_COP = (np.nansum(q_total_load * system_COP_list) /
np.nansum(q_total_load)) # weighted average of the system efficiency
operation_results[2][9] += system_COP

# 3: SC_ET + single-effect ACH (AHU + ARU + SCU) + CT + Boiler + SC_ET
Expand Down Expand Up @@ -286,8 +288,8 @@ def disconnected_cooling_for_building(building_name, supply_systems, lca, locato
operation_results[3][5] = Qc_nom_AHU_ARU_SCU_W
q_total_load = (q_burner_load_Wh[None, :] + q_chw_single_ACH_Wh[None, :] + q_sc_gen_ET_Wh[None, :])
system_COP_list = np.divide(q_total_load, (el_total_Wh[None, :] + q_gas_for_burner_Wh[None, :])).flatten()
system_COP = np.nansum(q_total_load * system_COP_list) / np.nansum(
q_total_load) # weighted average of the system efficiency
system_COP = (np.nansum(q_total_load * system_COP_list) /
np.nansum(q_total_load)) # weighted average of the system efficiency
operation_results[3][9] += system_COP

# these two configurations are only activated when SCU is in use
Expand Down Expand Up @@ -673,9 +675,9 @@ def get_SC_data(building_name, locator, panel_type):
SC_data = pd.read_csv(locator.SC_results(building_name, panel_type),
usecols=["T_SC_sup_C", "T_SC_re_C", "mcp_SC_kWperC", "Q_SC_gen_kWh", "Area_SC_m2",
"Eaux_SC_kWh"])
q_sc_gen_Wh = SC_data['Q_SC_gen_kWh'] * 1000
q_sc_gen_Wh = (SC_data['Q_SC_gen_kWh'] * 1000).values
q_sc_gen_Wh = np.where(q_sc_gen_Wh < 0.0, 0.0, q_sc_gen_Wh)
el_aux_SC_Wh = SC_data['Eaux_SC_kWh'] * 1000
el_aux_SC_Wh = (SC_data['Eaux_SC_kWh'] * 1000).values
if panel_type == "FP":
T_hw_in_C = [x if x > T_GENERATOR_FROM_FP_C else T_GENERATOR_FROM_FP_C for x in SC_data['T_SC_re_C']]
elif panel_type == "ET":
Expand Down
4 changes: 2 additions & 2 deletions cea/optimization/slave/cooling_resource_activation.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,15 +334,15 @@ def activate_CCandACH_trigen(Q_cooling_unmet_W,
if Qh_CCGT_req_W <= Q_output_CC_max_W: # Normal operation possible within part load regime
Q_CHP_gen_W = float(Qh_CCGT_req_W)
NG_Trigen_req_W = Q_used_prim_CC_fn_W(Q_CHP_gen_W)
E_Trigen_NG_gen_W = np.float(eta_elec_interpol(NG_Trigen_req_W)) * NG_Trigen_req_W
E_Trigen_NG_gen_W = float(eta_elec_interpol(NG_Trigen_req_W)) * NG_Trigen_req_W

else: # Only part of the demand can be delivered as 100% load achieved
# This case should never occur, since it means that another heat source would be required to run
# the absorption chiller at the required capacity.
print("WARNING: Gas turbine can not output enough heat to power the absorption chiller!")
Q_CHP_gen_W = Q_output_CC_max_W
NG_Trigen_req_W = Q_used_prim_CC_fn_W(Q_CHP_gen_W)
E_Trigen_NG_gen_W = np.float(eta_elec_interpol(NG_Trigen_req_W)) * NG_Trigen_req_W
E_Trigen_NG_gen_W = float(eta_elec_interpol(NG_Trigen_req_W)) * NG_Trigen_req_W

# if the operation of the combined cycle is not possible due to its limited capacity, the absorption chiller
# (i.e. the cooling technology of the tri-generation plant) can not be powered either
Expand Down
4 changes: 2 additions & 2 deletions cea/optimization/slave/heating_resource_activation.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@ def heating_source_activator(Q_therm_req_W,
if Q_heat_unmet_W <= Q_output_CC_max_W: # Normal operation Possible within partload regime
Q_CHP_gen_W = Q_heat_unmet_W
NG_CHP_req_W = Q_used_prim_CC_fn_W(Q_CHP_gen_W)
E_CHP_gen_W = np.float(eta_elec_interpol(NG_CHP_req_W)) * NG_CHP_req_W
E_CHP_gen_W = float(eta_elec_interpol(NG_CHP_req_W)) * NG_CHP_req_W
else: # Only part of the demand can be delivered as 100% load achieved
Q_CHP_gen_W = Q_output_CC_max_W
NG_CHP_req_W = Q_used_prim_CC_fn_W(Q_CHP_gen_W)
E_CHP_gen_W = np.float(eta_elec_interpol(NG_CHP_req_W)) * NG_CHP_req_W
E_CHP_gen_W = float(eta_elec_interpol(NG_CHP_req_W)) * NG_CHP_req_W
else:
NG_CHP_req_W = 0.0
E_CHP_gen_W = 0.0
Expand Down
6 changes: 4 additions & 2 deletions cea/optimization_new/building.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def __init__(self, identifier, demands_file_path):
self.identifier = identifier
self.demands_file_path = demands_file_path
self.stand_alone_supply_system = SupplySystem()
self.crs = None
self._demand_flow = EnergyFlow()
self._footprint = None
self._location = None
Expand Down Expand Up @@ -98,6 +99,7 @@ def load_building_location(self, domain_shp_file):
reference system).
"""
if self.location is None:
self.crs = domain_shp_file.crs
self.footprint = domain_shp_file[domain_shp_file.Name == self.identifier].geometry.iloc[0]
self.location = self.footprint.representative_point()
else:
Expand Down Expand Up @@ -190,7 +192,7 @@ def distribute_building_potentials(domain_energy_potentials, domain_buildings):

# group the potentials by energy carriers and sum them up if necessary
for potential in building_scale_energy_potentials:
for building, profile in potential.main_building_profiles.iteritems():
for building, profile in potential.main_building_profiles.items():
if potential.main_potential.energy_carrier.code in building_energy_potentials[building].keys():
building_energy_potentials[building][potential.main_potential.energy_carrier.code] += \
EnergyFlow('source', 'secondary',
Expand All @@ -199,7 +201,7 @@ def distribute_building_potentials(domain_energy_potentials, domain_buildings):
building_energy_potentials[building][potential.main_potential.energy_carrier.code] = \
EnergyFlow('source', 'secondary',
potential.main_potential.energy_carrier.code, profile)
for building, profile in potential.auxiliary_building_profiles.iteritems():
for building, profile in potential.auxiliary_building_profiles.items():
if potential.auxiliary_potential.energy_carrier.code in building_energy_potentials[building].keys():
building_energy_potentials[building][potential.auxiliary_potential.energy_carrier.code] += \
EnergyFlow('source', 'secondary',
Expand Down
9 changes: 6 additions & 3 deletions cea/optimization_new/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
__email__ = "mathias.niffeler@sec.ethz.ch"
__status__ = "Production"

import cea.lib

import os.path
import tempfile

Expand Down Expand Up @@ -245,7 +247,8 @@ def _load_pot_network(domain):
# join building locations (shapely.POINTS) and the corresponding identifiers in a DataFrame
building_identifiers = [building.identifier for building in domain.buildings]
building_locations = [building.location for building in domain.buildings]
buildings_df = pd.DataFrame(list(zip(building_locations, building_identifiers)), columns=['geometry', 'Name'])
buildings_df = Gdf(list(zip(building_locations, building_identifiers)), columns=['geometry', 'Name'],
crs=domain.buildings[0].crs, geometry="geometry")

# create a potential network grid with orthogonal connections between buildings and their closest street
network_grid_shp = calc_connectivity_network(domain.locator.get_street_network(),
Expand Down Expand Up @@ -450,7 +453,7 @@ def _set_plant_next_to_building(self, anchor_building):
plant_terminal = plant_terminal.rename({plant_terminal.index[0]: plant_terminal_node})
plant_terminal['Type'][0] = "PLANT"

self.network_nodes = self.network_nodes.append(plant_terminal)
self.network_nodes = pd.concat([self.network_nodes, plant_terminal])

# create new edge
point1 = (plant_terminal.geometry[0].x, plant_terminal.geometry[0].y)
Expand All @@ -461,7 +464,7 @@ def _set_plant_next_to_building(self, anchor_building):
'end node': plant_terminal_node},
index=['PIPE' + str(len(self.network_edges.index))],
crs=Network._coordinate_reference_system)
self.network_edges = self.network_edges.append(plant_to_network)
self.network_edges = pd.concat([self.network_edges, plant_to_network])

def _run_water_network_model(self):
"""
Expand Down
2 changes: 1 addition & 1 deletion cea/technologies/boiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ def calc_Cop_boiler(q_load_Wh, Q_nom_W, T_return_to_boiler_K):
phi = float(q_load_Wh) / float(Q_nom_W)
if phi >=1.0: # avoid rounding error
phi = 0.98
T_return_C = np.float(T_return_to_boiler_K - 273.15)
T_return_C = float(T_return_to_boiler_K - 273.15)
eff_score = eff_of_phi(phi) / eff_of_phi(1)
boiler_eff = (eff_score * eff_of_T_return([T_return_C]))[0] / 100.0
else:
Expand Down
4 changes: 2 additions & 2 deletions cea/technologies/chiller_absorption.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
import pandas as pd
import numpy as np
from math import log, ceil
import sympy
# import sympy
from cea.constants import HEAT_CAPACITY_OF_WATER_JPERKGK
from cea.analysis.costs.equations import calc_capex_annualized, calc_opex_annualized
from cea.analysis.costs.equations import calc_capex_annualized

__author__ = "Shanshan Hsieh"
__copyright__ = "Copyright 2015, Architecture and Building Systems - ETH Zurich"
Expand Down

0 comments on commit 6b70996

Please sign in to comment.