Skip to content

Instantly share code, notes, and snippets.

@jmarrec
Created April 9, 2025 11:18
Show Gist options
  • Save jmarrec/38782cd213c06241293b028dbf9367c3 to your computer and use it in GitHub Desktop.
Save jmarrec/38782cd213c06241293b028dbf9367c3 to your computer and use it in GitHub Desktop.
Comparing models and prototyping space_set_ach
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "cb7b226f",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'3.8.0+f953b6fcaf'"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#Import modules\n",
"import pandas as pd\n",
"import numpy as np\n",
"import json\n",
"import re\n",
"\n",
"from pathlib import Path\n",
"\n",
"import sys\n",
"sys.path.insert(0, '/usr/local/openstudio-3.8.0/Python')\n",
"import openstudio\n",
"sys.path.pop(0)\n",
"openstudio.openStudioLongVersion()"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "a73f62cd",
"metadata": {},
"outputs": [],
"source": [
"DATA_DIR = Path('../test/data/simulation')\n",
"ORI_INPUT_PATH = DATA_DIR / 'base/input_data_office.json'\n",
"NEW_INPUT_PATH = DATA_DIR / 'dynamic_attributes/input_data_office_custom-lpd.json'\n",
"assert ORI_INPUT_PATH.is_file()\n",
"assert NEW_INPUT_PATH.is_file()\n",
"ori_input = json.loads(ORI_INPUT_PATH.read_text())\n",
"new_input = json.loads(NEW_INPUT_PATH.read_text())"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "28c57d8c",
"metadata": {},
"outputs": [],
"source": [
"def compare_other(ori_o, new_o, do_print=False) -> bool:\n",
" result = ori_o == new_o\n",
" if do_print and not result:\n",
" print(\"{ori_o} - {new_o}\")\n",
" return result\n",
"\n",
"def compare_list(ori_l, new_l):\n",
" result = True\n",
" assert isinstance(ori_l, list)\n",
" assert isinstance(new_l, list)\n",
" if len(ori_l) != len(new_l):\n",
" print(f\"Diff in List size: {ori_l} versus {new_l}\")\n",
" for i, (ori_o, new_o) in enumerate(zip(ori_l, new_l)):\n",
" if not compare_object(ori_o, new_o):\n",
" print(f\"Diff at element {i}\")\n",
" result = False\n",
" return result\n",
" \n",
"def compare_dict(ori_dict, new_dict):\n",
" assert isinstance(ori_dict, dict)\n",
" assert isinstance(new_dict, dict)\n",
" \n",
" result = True\n",
" ori_keys = set(ori_dict.keys())\n",
" new_keys = set(new_dict.keys())\n",
" deleted_keys = ori_keys - new_keys\n",
" if deleted_keys:\n",
" print(\"Some keys were deleted\")\n",
" print(json.dumps({k: ori_dict[k] for k in deleted_keys}, indent=2))\n",
" added_keys = new_keys - ori_keys\n",
" if added_keys:\n",
" print(\"Some keys were added\")\n",
" print(json.dumps({k: new_dict[k] for k in added_keys}, indent=2))\n",
" common_keys = ori_keys.intersection(new_keys)\n",
" for k in common_keys:\n",
" if not compare_object(ori_dict[k], new_dict[k]):\n",
" print(f\"Diff at key={k}\")\n",
" result = False\n",
" return result\n",
" \n",
"def compare_object(ori_o, new_o):\n",
" if isinstance(ori_o, dict):\n",
" return compare_dict(ori_o, new_o)\n",
" elif isinstance(ori_o, list):\n",
" return compare_list(ori_o, new_o)\n",
" else:\n",
" return compare_other(ori_o, new_o)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "49a4d421",
"metadata": {
"scrolled": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Some keys were added\n",
"{\n",
" \"heritage_designation\": \"https://mapmortar.io/#heritage-none\",\n",
" \"heating_source\": \"https://mapmortar.io/#gas-boiler\",\n",
" \"lighting_power_density\": 10.0,\n",
" \"longitude\": -0.07984748653345086,\n",
" \"latitude\": 51.5478814,\n",
" \"natural_gas_is_available\": true,\n",
" \"occupancy_classification\": \"https://bedes.lbl.gov/bedes-online/office\",\n",
" \"simulation_engine_version\": \"2024-06-18-A\",\n",
" \"epcs\": []\n",
"}\n",
"Some keys were deleted\n",
"{\n",
" \"equipment_power_density\": null\n",
"}\n",
"Diff at key=lighting_power_density\n",
"Diff at element 1\n",
"Some keys were deleted\n",
"{\n",
" \"equipment_power_density\": null\n",
"}\n",
"Diff at key=lighting_power_density\n",
"Diff at element 2\n",
"Some keys were deleted\n",
"{\n",
" \"equipment_power_density\": null\n",
"}\n",
"Diff at key=lighting_power_density\n",
"Diff at element 5\n",
"Diff at key=sections\n"
]
},
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"compare_object(ori_input, new_input)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "04e21a70",
"metadata": {},
"outputs": [],
"source": [
"from copy import deepcopy"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "4418fb7c",
"metadata": {},
"outputs": [],
"source": [
"ori_sections = []\n",
"for x in deepcopy(ori_input['sections']):\n",
" x.pop('resources')\n",
" x.pop('fenestration_system')\n",
" x.pop('occupancy_classification')\n",
" ori_sections.append(x)\n",
" \n",
"new_sections = []\n",
"for x in deepcopy(new_input['sections']):\n",
" x.pop('resources')\n",
" x.pop('fenestration_system')\n",
" x.pop('occupancy_classification')\n",
" new_sections.append(x)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "48c3982b",
"metadata": {},
"outputs": [],
"source": [
"df_input = pd.concat({\n",
" 'ori': pd.DataFrame(ori_sections).set_index('story'),\n",
" 'new': pd.DataFrame(new_sections).set_index('story'),\n",
"}, axis=1) #.swaplevel(0, 1, axis=1).sort_index(axis=1)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "60eab8b3",
"metadata": {},
"outputs": [],
"source": [
"df_input = df_input.fillna('-')"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "e36de620",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"OccupancyLevels False\n",
"wwr False\n",
"people_per_floor_area False\n",
"lighting_power_density True\n",
"equipment_power_density False\n",
"dtype: bool"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"diffs = (df_input['ori'] != df_input['new']).any()\n",
"diffs"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f7dbbf45",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 10,
"id": "cf87821a",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead tr th {\n",
" text-align: left;\n",
" }\n",
"\n",
" .dataframe thead tr:last-of-type th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr>\n",
" <th></th>\n",
" <th colspan=\"2\" halign=\"left\">OccupancyLevels</th>\n",
" <th colspan=\"2\" halign=\"left\">equipment_power_density</th>\n",
" <th colspan=\"2\" halign=\"left\">lighting_power_density</th>\n",
" <th colspan=\"2\" halign=\"left\">people_per_floor_area</th>\n",
" <th colspan=\"2\" halign=\"left\">wwr</th>\n",
" </tr>\n",
" <tr>\n",
" <th></th>\n",
" <th>new</th>\n",
" <th>ori</th>\n",
" <th>new</th>\n",
" <th>ori</th>\n",
" <th>new</th>\n",
" <th>ori</th>\n",
" <th>new</th>\n",
" <th>ori</th>\n",
" <th>new</th>\n",
" <th>ori</th>\n",
" </tr>\n",
" <tr>\n",
" <th>story</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>0.3</td>\n",
" <td>0.3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>10.0</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>0.3</td>\n",
" <td>0.3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>20.0</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>0.3</td>\n",
" <td>0.3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>0.3</td>\n",
" <td>0.3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>0.3</td>\n",
" <td>0.3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>34.0</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" <td>0.3</td>\n",
" <td>0.3</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" OccupancyLevels equipment_power_density lighting_power_density \\\n",
" new ori new ori new \n",
"story \n",
"0 - - - - - \n",
"1 - - - - 10.0 \n",
"2 - - - - 20.0 \n",
"3 - - - - - \n",
"4 - - - - - \n",
"5 - - - - 34.0 \n",
"\n",
" people_per_floor_area wwr \n",
" ori new ori new ori \n",
"story \n",
"0 - - - 0.3 0.3 \n",
"1 - - - 0.3 0.3 \n",
"2 - - - 0.3 0.3 \n",
"3 - - - 0.3 0.3 \n",
"4 - - - 0.3 0.3 \n",
"5 - - - 0.3 0.3 "
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_input = df_input.swaplevel(0, 1, axis=1).sort_index(axis=1)\n",
"df_input"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "bcb11eed",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead tr th {\n",
" text-align: left;\n",
" }\n",
"\n",
" .dataframe thead tr:last-of-type th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr>\n",
" <th></th>\n",
" <th colspan=\"2\" halign=\"left\">lighting_power_density</th>\n",
" </tr>\n",
" <tr>\n",
" <th></th>\n",
" <th>new</th>\n",
" <th>ori</th>\n",
" </tr>\n",
" <tr>\n",
" <th>story</th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>10.0</td>\n",
" <td>-</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>20.0</td>\n",
" <td>-</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>-</td>\n",
" <td>-</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>34.0</td>\n",
" <td>-</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" lighting_power_density \n",
" new ori\n",
"story \n",
"0 - -\n",
"1 10.0 -\n",
"2 20.0 -\n",
"3 - -\n",
"4 - -\n",
"5 34.0 -"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_input.loc[:, diffs.index[diffs].tolist()].sort_index(axis=1)"
]
},
{
"cell_type": "markdown",
"id": "8da70deb",
"metadata": {},
"source": [
"# Model compare"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "a7239833",
"metadata": {},
"outputs": [],
"source": [
"ORI_DIR = Path('office')\n",
"NEW_DIR = Path('office_custom-lpd')\n",
"\n",
"RUN_DIRS = {\n",
" 'ori': ORI_DIR,\n",
" 'new': NEW_DIR,\n",
"}\n",
"\n",
"def get_file(test_case: str, rel_p: Path | str) -> Path:\n",
" p = RUN_DIRS[test_case] / rel_p\n",
" assert p.is_file()\n",
" return p"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "6e2840ad",
"metadata": {},
"outputs": [],
"source": [
"m_ori = openstudio.model.Model.load(get_file(test_case='ori', rel_p='run/in.osm')).get()\n",
"m_new = openstudio.model.Model.load(get_file(test_case='new', rel_p='run/in.osm')).get()"
]
},
{
"cell_type": "markdown",
"id": "17f6806a",
"metadata": {},
"source": [
"## Object Counts"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "62aba69f",
"metadata": {},
"outputs": [],
"source": [
"OBJECTS = [\n",
" 'SpaceType',\n",
" 'Space',\n",
" 'People',\n",
" 'PeopleDefinition',\n",
" 'Lights',\n",
" 'LightsDefinition',\n",
" 'ElectricEquipment',\n",
" 'ElectricEquipmentDefinition'\n",
"]\n",
"def object_counts(m: openstudio.model.Model):\n",
" count = {'Total': len(m.objects())}\n",
" for o in OBJECTS:\n",
" count[o] = len(getattr(m, f\"get{o}s\")())\n",
" return count"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "9ed81c7f",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>ori</th>\n",
" <th>new</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>Total</th>\n",
" <td>575</td>\n",
" <td>593</td>\n",
" </tr>\n",
" <tr>\n",
" <th>SpaceType</th>\n",
" <td>1</td>\n",
" <td>4</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Space</th>\n",
" <td>6</td>\n",
" <td>6</td>\n",
" </tr>\n",
" <tr>\n",
" <th>People</th>\n",
" <td>1</td>\n",
" <td>4</td>\n",
" </tr>\n",
" <tr>\n",
" <th>PeopleDefinition</th>\n",
" <td>2</td>\n",
" <td>2</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Lights</th>\n",
" <td>1</td>\n",
" <td>4</td>\n",
" </tr>\n",
" <tr>\n",
" <th>LightsDefinition</th>\n",
" <td>2</td>\n",
" <td>5</td>\n",
" </tr>\n",
" <tr>\n",
" <th>ElectricEquipment</th>\n",
" <td>1</td>\n",
" <td>4</td>\n",
" </tr>\n",
" <tr>\n",
" <th>ElectricEquipmentDefinition</th>\n",
" <td>2</td>\n",
" <td>2</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" ori new\n",
"Total 575 593\n",
"SpaceType 1 4\n",
"Space 6 6\n",
"People 1 4\n",
"PeopleDefinition 2 2\n",
"Lights 1 4\n",
"LightsDefinition 2 5\n",
"ElectricEquipment 1 4\n",
"ElectricEquipmentDefinition 2 2"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_counts = pd.DataFrame({\n",
" 'ori': object_counts(m_ori),\n",
" 'new': object_counts(m_new),\n",
"})\n",
"df_counts"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "4a3ff427",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>ori</th>\n",
" <th>new</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>Total</th>\n",
" <td>575</td>\n",
" <td>593</td>\n",
" </tr>\n",
" <tr>\n",
" <th>SpaceType</th>\n",
" <td>1</td>\n",
" <td>4</td>\n",
" </tr>\n",
" <tr>\n",
" <th>People</th>\n",
" <td>1</td>\n",
" <td>4</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Lights</th>\n",
" <td>1</td>\n",
" <td>4</td>\n",
" </tr>\n",
" <tr>\n",
" <th>LightsDefinition</th>\n",
" <td>2</td>\n",
" <td>5</td>\n",
" </tr>\n",
" <tr>\n",
" <th>ElectricEquipment</th>\n",
" <td>1</td>\n",
" <td>4</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" ori new\n",
"Total 575 593\n",
"SpaceType 1 4\n",
"People 1 4\n",
"Lights 1 4\n",
"LightsDefinition 2 5\n",
"ElectricEquipment 1 4"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_counts.loc[df_counts['ori'] != df_counts['new']]"
]
},
{
"cell_type": "markdown",
"id": "5a87b97d",
"metadata": {},
"source": [
"## Space Loads"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "b279fd06",
"metadata": {},
"outputs": [],
"source": [
"def space_loads(s: openstudio.model.Space, absolute: bool = False) -> dict[str, float]:\n",
" if absolute:\n",
" return {\n",
" 'name': s.nameString(),\n",
" 'area': s.floorArea(),\n",
" 'people': s.numberOfPeople(),\n",
" 'light': s.lightingPower(),\n",
" 'elec': s.electricEquipmentPower(),\n",
" 'ach': s.infiltrationDesignFlowRate(),\n",
" }\n",
" else:\n",
" return {\n",
" 'name': s.nameString(),\n",
" 'area': s.floorArea(),\n",
" 'people': s.peoplePerFloorArea(),\n",
" 'light': s.lightingPowerPerFloorArea(),\n",
" 'elec': s.electricEquipmentPowerPerFloorArea(),\n",
" 'ach': s.infiltrationDesignAirChangesPerHour(),\n",
" }\n",
"\n",
"def model_space_loads(m: openstudio.model.Model) -> pd.DataFrame:\n",
" df = pd.DataFrame([space_loads(s) for s in m.getSpaces()])\n",
" df.set_index('name', inplace=True)\n",
" df.sort_index(axis=0, inplace=True)\n",
" return df"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "951f40a3",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead tr th {\n",
" text-align: left;\n",
" }\n",
"\n",
" .dataframe thead tr:last-of-type th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr>\n",
" <th></th>\n",
" <th colspan=\"5\" halign=\"left\">ori</th>\n",
" <th colspan=\"5\" halign=\"left\">new</th>\n",
" </tr>\n",
" <tr>\n",
" <th></th>\n",
" <th>area</th>\n",
" <th>people</th>\n",
" <th>light</th>\n",
" <th>elec</th>\n",
" <th>ach</th>\n",
" <th>area</th>\n",
" <th>people</th>\n",
" <th>light</th>\n",
" <th>elec</th>\n",
" <th>ach</th>\n",
" </tr>\n",
" <tr>\n",
" <th>name</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>Level 0</th>\n",
" <td>1968.713084</td>\n",
" <td>0.05382</td>\n",
" <td>8.826407</td>\n",
" <td>8.072933</td>\n",
" <td>0.25</td>\n",
" <td>1968.713084</td>\n",
" <td>0.05382</td>\n",
" <td>8.826407</td>\n",
" <td>8.072933</td>\n",
" <td>0.25</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Level 1</th>\n",
" <td>1968.713084</td>\n",
" <td>0.05382</td>\n",
" <td>8.826407</td>\n",
" <td>8.072933</td>\n",
" <td>0.25</td>\n",
" <td>1968.713084</td>\n",
" <td>0.05382</td>\n",
" <td>10.000000</td>\n",
" <td>8.072933</td>\n",
" <td>0.25</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Level 2</th>\n",
" <td>1968.713084</td>\n",
" <td>0.05382</td>\n",
" <td>8.826407</td>\n",
" <td>8.072933</td>\n",
" <td>0.25</td>\n",
" <td>1968.713084</td>\n",
" <td>0.05382</td>\n",
" <td>20.000000</td>\n",
" <td>8.072933</td>\n",
" <td>0.25</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Level 3</th>\n",
" <td>1968.713084</td>\n",
" <td>0.05382</td>\n",
" <td>8.826407</td>\n",
" <td>8.072933</td>\n",
" <td>0.25</td>\n",
" <td>1968.713084</td>\n",
" <td>0.05382</td>\n",
" <td>8.826407</td>\n",
" <td>8.072933</td>\n",
" <td>0.25</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Level 4</th>\n",
" <td>1968.713084</td>\n",
" <td>0.05382</td>\n",
" <td>8.826407</td>\n",
" <td>8.072933</td>\n",
" <td>0.25</td>\n",
" <td>1968.713084</td>\n",
" <td>0.05382</td>\n",
" <td>8.826407</td>\n",
" <td>8.072933</td>\n",
" <td>0.25</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Level 5</th>\n",
" <td>1968.713084</td>\n",
" <td>0.05382</td>\n",
" <td>8.826407</td>\n",
" <td>8.072933</td>\n",
" <td>0.25</td>\n",
" <td>1968.713084</td>\n",
" <td>0.05382</td>\n",
" <td>34.000000</td>\n",
" <td>8.072933</td>\n",
" <td>0.25</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" ori new \\\n",
" area people light elec ach area people \n",
"name \n",
"Level 0 1968.713084 0.05382 8.826407 8.072933 0.25 1968.713084 0.05382 \n",
"Level 1 1968.713084 0.05382 8.826407 8.072933 0.25 1968.713084 0.05382 \n",
"Level 2 1968.713084 0.05382 8.826407 8.072933 0.25 1968.713084 0.05382 \n",
"Level 3 1968.713084 0.05382 8.826407 8.072933 0.25 1968.713084 0.05382 \n",
"Level 4 1968.713084 0.05382 8.826407 8.072933 0.25 1968.713084 0.05382 \n",
"Level 5 1968.713084 0.05382 8.826407 8.072933 0.25 1968.713084 0.05382 \n",
"\n",
" \n",
" light elec ach \n",
"name \n",
"Level 0 8.826407 8.072933 0.25 \n",
"Level 1 10.000000 8.072933 0.25 \n",
"Level 2 20.000000 8.072933 0.25 \n",
"Level 3 8.826407 8.072933 0.25 \n",
"Level 4 8.826407 8.072933 0.25 \n",
"Level 5 34.000000 8.072933 0.25 "
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_loads = pd.concat({\n",
" 'ori': model_space_loads(m_ori),\n",
" 'new': model_space_loads(m_new),\n",
"}, axis=1)\n",
"\n",
"df_loads"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "d9825043",
"metadata": {},
"outputs": [],
"source": [
"df_loads = df_loads.stack(future_stack=True)\n",
"df_loads = df_loads[df_loads['ori'] != df_loads['new']]"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "3d81b37f",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th></th>\n",
" <th>ori</th>\n",
" <th>new</th>\n",
" </tr>\n",
" <tr>\n",
" <th>name</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>Level 1</th>\n",
" <th>light</th>\n",
" <td>8.826407</td>\n",
" <td>10.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Level 2</th>\n",
" <th>light</th>\n",
" <td>8.826407</td>\n",
" <td>20.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Level 5</th>\n",
" <th>light</th>\n",
" <td>8.826407</td>\n",
" <td>34.0</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" ori new\n",
"name \n",
"Level 1 light 8.826407 10.0\n",
"Level 2 light 8.826407 20.0\n",
"Level 5 light 8.826407 34.0"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_loads"
]
},
{
"cell_type": "markdown",
"id": "b69190f9",
"metadata": {},
"source": [
"# Prototype space_set_ach"
]
},
{
"cell_type": "code",
"execution_count": 21,
"id": "7868b065",
"metadata": {},
"outputs": [],
"source": [
"def space_get_all_spis(s: openstudio.model.Space) -> float:\n",
" \"\"\"Returns both the SpaceInfiltrationDesignFlowRates defined on the Space and the SpaceType if any.\"\"\"\n",
" all_spis = list(s.spaceInfiltrationDesignFlowRates())\n",
" if sp_ := s.spaceType():\n",
" all_spis += sp_.get().spaceInfiltrationDesignFlowRates()\n",
" return all_spis"
]
},
{
"cell_type": "code",
"execution_count": 22,
"id": "457a9dc3",
"metadata": {},
"outputs": [],
"source": [
"def space_set_ach(s: openstudio.model.Space, ach: float) -> bool:\n",
" if ach < 0:\n",
" return False\n",
" \n",
" # First thing first: if the SpaceType already has SpaceInfiltrationDesignFlowRates, \n",
" # AND that SpaceType is used by more than 1 ParentObject (Space, Building)\n",
" # we must clone it or we'll double count infiltration\n",
" if (sp_ := s.spaceType()).is_initialized():\n",
" sp = sp_.get()\n",
" sp_spis = sp.spaceInfiltrationDesignFlowRates()\n",
" if len(sp_spis) > 0:\n",
"\n",
" sp_sources = (\n",
" list(sp.getSources(openstudio.IddObjectType(\"OS:Space\"))) +\n",
" list(sp.getSources(openstudio.IddObjectType(\"OS:Building\")))\n",
" )\n",
" if len(sp_sources) > 1:\n",
" print(f\"Cloning SpaceType because it has {len(sp_spis)} spis and is used by {len(sp_sources) } sources\")\n",
" sp_clone = sp.clone(s.model()).to_SpaceType().get()\n",
" sp_clone.setName(f\"{sp.nameString()} - {s.nameString()}\")\n",
" s.setSpaceType(sp_clone)\n",
" # Remove all spis\n",
" [spi.remove() for spi in sp_clone.spaceInfiltrationDesignFlowRates()]\n",
" \n",
" \n",
" spis = s.spaceInfiltrationDesignFlowRates()\n",
" spi = None\n",
" if not spis:\n",
" spi = openstudio.model.SpaceInfiltrationDesignFlowRate(s.model())\n",
" else:\n",
" spi = spis[0]\n",
" if len(spis) > 1:\n",
" # Remove all but the one we keep\n",
" [spi.remove() for spi in spis[1:]]\n",
" \n",
" spi.setName(f\"{s.nameString()} Infiltration {round(ach, 2)} ach\")\n",
" spi.setAirChangesperHour(ach)\n",
" spi.setSpace(s)\n",
" return True"
]
},
{
"cell_type": "code",
"execution_count": 23,
"id": "6bd09595",
"metadata": {},
"outputs": [],
"source": [
"m = openstudio.model.Model.load(get_file(test_case='ori', rel_p='run/in.osm')).get()\n",
"s = m.getSpaceByName(\"Level 5\").get()\n",
"sp = s.spaceType().get()"
]
},
{
"cell_type": "code",
"execution_count": 24,
"id": "88b22445",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[]"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"[print(x) for x in s.spaceInfiltrationDesignFlowRates()]"
]
},
{
"cell_type": "code",
"execution_count": 25,
"id": "f6331083",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"OS:SpaceInfiltration:DesignFlowRate,\n",
" {ae86a43d-074c-444d-a699-2cac6fd4d2de}, !- Handle\n",
" MediumOffice Whole Building Infiltration, !- Name\n",
" {13ca7a79-9cf4-4621-aa24-a53079804e7f}, !- Space or SpaceType Name\n",
" , !- Schedule Name\n",
" AirChanges/Hour, !- Design Flow Rate Calculation Method\n",
" , !- Design Flow Rate {m3/s}\n",
" , !- Flow per Space Floor Area {m3/s-m2}\n",
" , !- Flow per Exterior Surface Area {m3/s-m2}\n",
" 0.25, !- Air Changes per Hour {1/hr}\n",
" , !- Constant Term Coefficient\n",
" , !- Temperature Term Coefficient\n",
" , !- Velocity Term Coefficient\n",
" ; !- Velocity Squared Term Coefficient\n",
"\n",
"\n"
]
},
{
"data": {
"text/plain": [
"[None]"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"[print(x) for x in sp.spaceInfiltrationDesignFlowRates()]"
]
},
{
"cell_type": "code",
"execution_count": 26,
"id": "1cac271d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Cloning SpaceType because it has 1 spis and is used by 7 sources\n"
]
},
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"space_set_ach(s=s, ach=0.6)"
]
},
{
"cell_type": "code",
"execution_count": 27,
"id": "19af4043",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'MediumOffice Whole Building - Level 5'"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s.spaceType().get().nameString()"
]
},
{
"cell_type": "code",
"execution_count": 28,
"id": "eae13a86",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"OS:SpaceType,\n",
" {3202b9d5-020b-4059-99e5-6b80a3c692d4}, !- Handle\n",
" MediumOffice Whole Building - Level 5, !- Name\n",
" , !- Default Construction Set Name\n",
" {419906fd-f6da-4473-907a-c4577d2ad291}, !- Default Schedule Set Name\n",
" , !- Group Rendering Name\n",
" {c594eb71-8d2b-4d09-9773-7d31c73107a1}, !- Design Specification Outdoor Air Object Name\n",
" , !- Standards Template\n",
" Office, !- Standards Building Type\n",
" WholeBuilding - Md Office; !- Standards Space Type\n",
"\n",
"\n",
"OS:SpaceType,\n",
" {13ca7a79-9cf4-4621-aa24-a53079804e7f}, !- Handle\n",
" MediumOffice Whole Building, !- Name\n",
" , !- Default Construction Set Name\n",
" {419906fd-f6da-4473-907a-c4577d2ad291}, !- Default Schedule Set Name\n",
" , !- Group Rendering Name\n",
" {c594eb71-8d2b-4d09-9773-7d31c73107a1}, !- Design Specification Outdoor Air Object Name\n",
" , !- Standards Template\n",
" Office, !- Standards Building Type\n",
" WholeBuilding - Md Office; !- Standards Space Type\n",
"\n",
"\n"
]
},
{
"data": {
"text/plain": [
"[None, None]"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"[print(x) for x in m.getSpaceTypes()]"
]
},
{
"cell_type": "code",
"execution_count": 29,
"id": "62539099",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"OS:SpaceInfiltration:DesignFlowRate,\n",
" {dcbf3d92-44cf-4ae4-be49-1149401069fc}, !- Handle\n",
" Level 5 Infiltration 0.6 ach, !- Name\n",
" {daa2d921-33c2-472c-91b9-c05c9a8a013d}, !- Space or SpaceType Name\n",
" , !- Schedule Name\n",
" AirChanges/Hour, !- Design Flow Rate Calculation Method\n",
" , !- Design Flow Rate {m3/s}\n",
" , !- Flow per Space Floor Area {m3/s-m2}\n",
" , !- Flow per Exterior Surface Area {m3/s-m2}\n",
" 0.6, !- Air Changes per Hour {1/hr}\n",
" , !- Constant Term Coefficient\n",
" , !- Temperature Term Coefficient\n",
" , !- Velocity Term Coefficient\n",
" ; !- Velocity Squared Term Coefficient\n",
"\n",
"\n"
]
},
{
"data": {
"text/plain": [
"[None]"
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"[print(x) for x in s.spaceInfiltrationDesignFlowRates()]"
]
},
{
"cell_type": "code",
"execution_count": 30,
"id": "881c2e94",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[]"
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"[print(x) for x in s.spaceType().get().spaceInfiltrationDesignFlowRates()]"
]
},
{
"cell_type": "code",
"execution_count": 31,
"id": "41935439",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Ori is untouched\n",
"OS:SpaceInfiltration:DesignFlowRate,\n",
" {ae86a43d-074c-444d-a699-2cac6fd4d2de}, !- Handle\n",
" MediumOffice Whole Building Infiltration, !- Name\n",
" {13ca7a79-9cf4-4621-aa24-a53079804e7f}, !- Space or SpaceType Name\n",
" , !- Schedule Name\n",
" AirChanges/Hour, !- Design Flow Rate Calculation Method\n",
" , !- Design Flow Rate {m3/s}\n",
" , !- Flow per Space Floor Area {m3/s-m2}\n",
" , !- Flow per Exterior Surface Area {m3/s-m2}\n",
" 0.25, !- Air Changes per Hour {1/hr}\n",
" , !- Constant Term Coefficient\n",
" , !- Temperature Term Coefficient\n",
" , !- Velocity Term Coefficient\n",
" ; !- Velocity Squared Term Coefficient\n",
"\n",
"\n"
]
},
{
"data": {
"text/plain": [
"[None]"
]
},
"execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"print(\"Ori is untouched\")\n",
"[print(x) for x in sp.spaceInfiltrationDesignFlowRates()]"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.2"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment