Spaces:
Sleeping
Sleeping
intiial commit
Browse files- .DS_Store +0 -0
- Dockerfile +24 -0
- Dockerfile.dev +9 -0
- LICENSE +21 -0
- README.md +45 -6
- app/.DS_Store +0 -0
- app/__pycache__/branch_and_bound.cpython-310.pyc +0 -0
- app/__pycache__/core.cpython-310.pyc +0 -0
- app/__pycache__/example_data.cpython-310.pyc +0 -0
- app/app.py +228 -0
- app/assets/.DS_Store +0 -0
- app/assets/hackatos.png +0 -0
- app/core.py +99 -0
- app/dashboard.ipynb +294 -0
- app/example_data.py +140 -0
- app/requirements.txt +6 -0
- dashboard.py +125 -0
.DS_Store
ADDED
Binary file (6.15 kB). View file
|
|
Dockerfile
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM python:3.10
|
2 |
+
# Set up a new user named "user" with user ID 1000
|
3 |
+
RUN useradd -m -u 1000 user
|
4 |
+
|
5 |
+
# Switch to the "user" user
|
6 |
+
USER user
|
7 |
+
# Set home to the user's home directory
|
8 |
+
ENV HOME=/home/user \
|
9 |
+
PATH=/home/user/.local/bin:$PATH
|
10 |
+
|
11 |
+
# Set the working directory to the user's home directory
|
12 |
+
WORKDIR $HOME/app
|
13 |
+
|
14 |
+
# Copy the current directory contents into the container at $HOME/app setting the owner to the user
|
15 |
+
COPY --chown=user ./app $HOME/app
|
16 |
+
|
17 |
+
|
18 |
+
ENV DASH_DEBUG_MODE False
|
19 |
+
#COPY ./app /app
|
20 |
+
#WORKDIR /app
|
21 |
+
RUN set -ex && \
|
22 |
+
pip install -r requirements.txt
|
23 |
+
EXPOSE 8050
|
24 |
+
CMD ["gunicorn", "-b", "0.0.0.0:8050", "--reload", "app:server"]
|
Dockerfile.dev
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM python:3.10
|
2 |
+
|
3 |
+
ENV DASH_DEBUG_MODE True
|
4 |
+
COPY ./app /app
|
5 |
+
WORKDIR /app
|
6 |
+
RUN set -ex && \
|
7 |
+
pip install -r requirements.txt
|
8 |
+
EXPOSE 8050
|
9 |
+
CMD ["python", "app.py"]
|
LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
MIT License
|
2 |
+
|
3 |
+
Copyright (c) 2019 Jucy Technologies, Inc.
|
4 |
+
|
5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6 |
+
of this software and associated documentation files (the "Software"), to deal
|
7 |
+
in the Software without restriction, including without limitation the rights
|
8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9 |
+
copies of the Software, and to permit persons to whom the Software is
|
10 |
+
furnished to do so, subject to the following conditions:
|
11 |
+
|
12 |
+
The above copyright notice and this permission notice shall be included in all
|
13 |
+
copies or substantial portions of the Software.
|
14 |
+
|
15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21 |
+
SOFTWARE.
|
README.md
CHANGED
@@ -1,11 +1,50 @@
|
|
1 |
---
|
2 |
-
title: Smart Shower
|
3 |
-
emoji:
|
4 |
-
colorFrom:
|
5 |
colorTo: gray
|
6 |
sdk: docker
|
7 |
-
|
8 |
-
license: mit
|
9 |
---
|
|
|
10 |
|
11 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
---
|
2 |
+
title: Smart Shower Dashboard
|
3 |
+
emoji: 📈
|
4 |
+
colorFrom: purple
|
5 |
colorTo: gray
|
6 |
sdk: docker
|
7 |
+
app_port: 8050
|
|
|
8 |
---
|
9 |
+
# Docker Dash (Plotly)
|
10 |
|
11 |
+
Dockerize a Python Dash app for quick prototyping.
|
12 |
+
|
13 |
+
## Build and run
|
14 |
+
|
15 |
+
`prod` version is served by `gunicorn` instead of the `flask` dev server.
|
16 |
+
|
17 |
+
```sh
|
18 |
+
# dev
|
19 |
+
docker build -f Dockerfile.dev -t docker-dash-example-dev .
|
20 |
+
docker run -p 8050:8050 -v "$(pwd)"/app:/app --rm docker-dash-example-dev
|
21 |
+
|
22 |
+
# prod
|
23 |
+
docker build -f Dockerfile -t docker-dash-example-prod .
|
24 |
+
docker run -p 8050:8050 -v "$(pwd)"/app:/app --rm docker-dash-example-prod
|
25 |
+
```
|
26 |
+
|
27 |
+
## Access the page
|
28 |
+
|
29 |
+
Go to `http://localhost:8050` in browser.
|
30 |
+
|
31 |
+
## Switch debug mode in Dockerfile
|
32 |
+
|
33 |
+
```dockerfile
|
34 |
+
ENV DASH_DEBUG_MODE True # False
|
35 |
+
```
|
36 |
+
|
37 |
+
## Development
|
38 |
+
|
39 |
+
Install the app requirements for development to get better editor support.
|
40 |
+
|
41 |
+
```sh
|
42 |
+
poetry install
|
43 |
+
```
|
44 |
+
|
45 |
+
Optional: clean initialization of `poetry`:
|
46 |
+
|
47 |
+
```sh
|
48 |
+
poetry init
|
49 |
+
cat app/requirements.txt | xargs poetry add
|
50 |
+
```
|
app/.DS_Store
ADDED
Binary file (6.15 kB). View file
|
|
app/__pycache__/branch_and_bound.cpython-310.pyc
ADDED
Binary file (6.23 kB). View file
|
|
app/__pycache__/core.cpython-310.pyc
ADDED
Binary file (1.79 kB). View file
|
|
app/__pycache__/example_data.cpython-310.pyc
ADDED
Binary file (2.42 kB). View file
|
|
app/app.py
ADDED
@@ -0,0 +1,228 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import plotly.express as px
|
3 |
+
import plotly.graph_objects as go
|
4 |
+
import pandas as pd
|
5 |
+
from dash import Dash, html, dcc, Input, Output, callback
|
6 |
+
import plotly.express as px
|
7 |
+
import numpy as np
|
8 |
+
import example_data
|
9 |
+
import core
|
10 |
+
|
11 |
+
|
12 |
+
outside_temp = example_data.ExampleDailyOutsideTemperature
|
13 |
+
energy_price = example_data.ExampleDailyEnergyCost
|
14 |
+
boiler_temperature = example_data.ExampleBoilerTemperature
|
15 |
+
|
16 |
+
|
17 |
+
|
18 |
+
data = pd.DataFrame(columns=['hour', 'energy_consumption', 'confort', 'policy_readable'])
|
19 |
+
data = pd.concat([data, pd.DataFrame({'hour': np.arange(0, 24), 'energy_consumption': energy_price.value, 'confort': np.random.rand(24),
|
20 |
+
'policy_readable': np.random.choice(['A', 'B', 'C', 'D', 'E'], 24)
|
21 |
+
})])
|
22 |
+
debug = False
|
23 |
+
|
24 |
+
|
25 |
+
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
|
26 |
+
|
27 |
+
app = Dash(__name__, external_stylesheets=external_stylesheets)
|
28 |
+
|
29 |
+
app.layout = html.Div([
|
30 |
+
dcc.Location(id='url', refresh=False),
|
31 |
+
html.Div(id='page-content')
|
32 |
+
])
|
33 |
+
|
34 |
+
server = app.server
|
35 |
+
|
36 |
+
|
37 |
+
# SOlution options
|
38 |
+
solution_options = [
|
39 |
+
"Discrete Optimization",
|
40 |
+
"Continuous Optimization",
|
41 |
+
"Reinforcement Learning"
|
42 |
+
]
|
43 |
+
solution_options_default_value = solution_options[0]
|
44 |
+
|
45 |
+
# provide a scalar value to enable the slider to select ideal temperature
|
46 |
+
ideal_temperature = 50
|
47 |
+
|
48 |
+
dashboard_layout = html.Div([
|
49 |
+
dcc.Link('About this project', href='/wiki'),
|
50 |
+
|
51 |
+
html.H1('System Evaluation'),
|
52 |
+
#small subtitle that says of solution is possible or not
|
53 |
+
html.Div(id='solution-status', children='', style={'color': 'lighrgrey'}),
|
54 |
+
html.Div([
|
55 |
+
html.Div([
|
56 |
+
html.H3('Solution'),
|
57 |
+
dcc.Dropdown(
|
58 |
+
id='solution-dropdown',
|
59 |
+
options=solution_options,
|
60 |
+
value=solution_options_default_value,
|
61 |
+
)
|
62 |
+
], className='three columns'),
|
63 |
+
html.Div([
|
64 |
+
html.H3('Ideal Shower Temperature'),
|
65 |
+
dcc.Slider(
|
66 |
+
id='ideal-temperature-slider',
|
67 |
+
min=0,
|
68 |
+
max=100,
|
69 |
+
step=1,
|
70 |
+
value=ideal_temperature,
|
71 |
+
marks={
|
72 |
+
0: '0°C',
|
73 |
+
25: '25°C',
|
74 |
+
50: '50°C',
|
75 |
+
75: '75°C',
|
76 |
+
100: '100°C'
|
77 |
+
},
|
78 |
+
)
|
79 |
+
], className='three columns'),
|
80 |
+
|
81 |
+
|
82 |
+
], className='row'),
|
83 |
+
html.Div(
|
84 |
+
[
|
85 |
+
html.Div(
|
86 |
+
[
|
87 |
+
html.H3('Policy'),
|
88 |
+
dcc.Graph(id='policy_readable-graph')
|
89 |
+
], className='six columns',
|
90 |
+
),
|
91 |
+
html.Div(
|
92 |
+
[
|
93 |
+
html.H3('Energy Consumption'),
|
94 |
+
dcc.Graph(id='energy-comsumption-graph')
|
95 |
+
], className='six columns'
|
96 |
+
)
|
97 |
+
], className='row'),
|
98 |
+
html.Div(
|
99 |
+
[
|
100 |
+
html.Div(
|
101 |
+
[
|
102 |
+
html.H3('Confort'),
|
103 |
+
dcc.Graph(id='confort-graph')
|
104 |
+
], className='six columns'
|
105 |
+
)
|
106 |
+
], className='row'),
|
107 |
+
],
|
108 |
+
#add background image from local file and make it transparent
|
109 |
+
#, style={'background-image':'url(/assets/background_1.png)'}
|
110 |
+
style={'background-color': '#4B5320', 'font-family': 'Fantasy', 'color': '#8F9779', 'padding': '10px'}
|
111 |
+
)
|
112 |
+
|
113 |
+
|
114 |
+
|
115 |
+
wiki_layout = html.Div([
|
116 |
+
dcc.Link('Dashboard', href='/'),
|
117 |
+
|
118 |
+
html.H1('About this project'),
|
119 |
+
|
120 |
+
html.Div([
|
121 |
+
html.Div([
|
122 |
+
|
123 |
+
html.H3('What is this project about?'),
|
124 |
+
|
125 |
+
html.P('This project is a simulation of a shower system. The goal is to find the best policy for the boiler to heat the water for the shower. The policy is a function that takes the current hour of the day and the current temperature of the water in the boiler and returns the temperature that the boiler should heat the water to.'),
|
126 |
+
html.P('The best policy is the one that maximizes the confort of the shower and minimizes the energy consumption of the boiler.'),
|
127 |
+
|
128 |
+
html.H3('How does it work?'),
|
129 |
+
|
130 |
+
#Insert image of the system
|
131 |
+
|
132 |
+
html.H3('\'Bout us'),
|
133 |
+
html.Img(src='/assets/hackatos.png', style={'width': '40%', 'height': 'auto', 'display': 'block', 'margin-left': 'auto', 'margin-right': 'auto'}),
|
134 |
+
html.P('This project was developed by a team of 3, in the context of the Aveiro Tech City 2023 hackathon.'),
|
135 |
+
html.P('The team members are:'),
|
136 |
+
html.H4('Rui Melo'),
|
137 |
+
html.P('Rui Melo is a ....'),
|
138 |
+
html.H4('André Catarino'),
|
139 |
+
html.P('André Catarino is a ....'),
|
140 |
+
html.H4('Francisco Petronilho'),
|
141 |
+
html.P('Francisco Petronilho is a ....'),
|
142 |
+
html.H4('André Tomás'),
|
143 |
+
html.P('André Tomás is a ....'),
|
144 |
+
html.H4('Zé Miguel'),
|
145 |
+
html.P('Zé Miguel is a ....'),
|
146 |
+
|
147 |
+
|
148 |
+
html.H3('References'),
|
149 |
+
html.P('The boiler model was based on the following paper:'),
|
150 |
+
|
151 |
+
|
152 |
+
], className='six columns'),], className='row'),
|
153 |
+
],
|
154 |
+
style={'background-color': '#4B5320', 'font-family': 'Fantasy', 'color': '#8F9779', 'padding': '10px'}
|
155 |
+
|
156 |
+
)
|
157 |
+
|
158 |
+
# Update the index
|
159 |
+
@callback(Output('page-content', 'children'), Input('url', 'pathname'))
|
160 |
+
def display_page(pathname):
|
161 |
+
if pathname == '/':
|
162 |
+
return dashboard_layout
|
163 |
+
elif pathname == '/wiki':
|
164 |
+
return wiki_layout
|
165 |
+
else:
|
166 |
+
return '404'
|
167 |
+
# You could also return a 404 "URL not found" page here
|
168 |
+
|
169 |
+
|
170 |
+
|
171 |
+
@app.callback(
|
172 |
+
Output('policy_readable-graph', 'figure'),
|
173 |
+
Output('energy-comsumption-graph', 'figure'),
|
174 |
+
Output('confort-graph', 'figure'),
|
175 |
+
Output('solution-status', 'children'),
|
176 |
+
Input('solution-dropdown', 'value'),
|
177 |
+
Input('ideal-temperature-slider', 'value')
|
178 |
+
)
|
179 |
+
def update_graph(solution, ideal_temperature):
|
180 |
+
energy_consumption = data['energy_consumption'].values
|
181 |
+
confort_obtained = data['confort'].values
|
182 |
+
|
183 |
+
|
184 |
+
policy_readable_graph = px.line(data, x='hour', y='policy_readable',
|
185 |
+
labels={'hour': 'Hour', 'policy_readable': 'Policy'},
|
186 |
+
color_discrete_sequence=['lightgreen'])
|
187 |
+
policy_readable_graph.update_layout(
|
188 |
+
xaxis_title="Hour",
|
189 |
+
yaxis_title="Temperature (°C)",
|
190 |
+
legend_title="Policy"
|
191 |
+
)
|
192 |
+
|
193 |
+
energy_consumption_graph = px.line(data, x='hour',
|
194 |
+
y='energy_consumption',
|
195 |
+
labels={'hour': 'Hour', 'energy_consumption': 'Energy Consumption (kWh)'},
|
196 |
+
color_discrete_sequence=['lightgreen'])
|
197 |
+
energy_consumption_graph.update_layout(
|
198 |
+
xaxis_title="Hour",
|
199 |
+
yaxis_title="Energy Consumption (kWh)",
|
200 |
+
legend_title="Energy Consumption",
|
201 |
+
)
|
202 |
+
#add accumulated energy consumption
|
203 |
+
energy_consumption = np.cumsum(energy_consumption)
|
204 |
+
energy_consumption_graph.add_trace(px.line(data, x='hour',
|
205 |
+
y=energy_consumption,
|
206 |
+
labels={'y': 'Acc. Energy Consumption (kWh)'},
|
207 |
+
color_discrete_sequence=['green']).data[0])
|
208 |
+
|
209 |
+
confort_graph = px.line(data, x='hour', y='confort',
|
210 |
+
labels={'hour': 'Hour', 'confort': 'Confort Score'},
|
211 |
+
color_discrete_sequence=['lightgreen'])
|
212 |
+
|
213 |
+
confort_graph.update_layout(
|
214 |
+
xaxis_title="Hour",
|
215 |
+
yaxis_title="Confort Score",
|
216 |
+
legend_title="Confort"
|
217 |
+
)
|
218 |
+
#add accumulated confort
|
219 |
+
confort_obtained = np.cumsum(confort_obtained)
|
220 |
+
confort_graph.add_trace(px.line(data, x='hour', y=confort_obtained,
|
221 |
+
labels={'y': 'Acc. Confort Score'},
|
222 |
+
color_discrete_sequence=['green']
|
223 |
+
).data[0])
|
224 |
+
result = "No solution found"
|
225 |
+
return policy_readable_graph, energy_consumption_graph, confort_graph, result
|
226 |
+
if __name__ == "__main__":
|
227 |
+
app.run_server(host="0.0.0.0", port="8050", debug=debug)
|
228 |
+
|
app/assets/.DS_Store
ADDED
Binary file (6.15 kB). View file
|
|
app/assets/hackatos.png
ADDED
![]() |
app/core.py
ADDED
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Electric cost(Euros) = energy_price(Euros/kWh) * wasted_energy(kWh)
|
2 |
+
def custo(energy_price_hour, wasted_energy):
|
3 |
+
return energy_price_hour * wasted_energy
|
4 |
+
|
5 |
+
|
6 |
+
# caldeira 20 litros
|
7 |
+
def spent_energy(
|
8 |
+
temperatura_inicial_caldeira_t, # existente na cadeira, t sendo a hora
|
9 |
+
temperatura_objetivo_caldeira_t_plus_1,
|
10 |
+
outside_temp,
|
11 |
+
pressao_caldeira,
|
12 |
+
litros_gastos_no_banho=0,
|
13 |
+
temperatura_entrada_agua_na_caldeira=15, # Temperatura ambiente da iNOVA
|
14 |
+
capacidade_caldeira=20, # 20 litros
|
15 |
+
):
|
16 |
+
# E = (4.2 kJ/kgoC) ((90 oC) - (20 oC)) (1000 liter) (1 kg/liter)
|
17 |
+
# cp = specific heat of water (kJ/kgoC, Btu/lb oF) (4.2 kJ/kgoC, 1 Btu/lbmoF for water)
|
18 |
+
heat_capacity = 4.2
|
19 |
+
# Energy = heat_capacity * (temperatura_saida_agua_na_caldeira - outside_temp) * capacidade_caldeira * 1\
|
20 |
+
delta_t = temperatura_objetivo_caldeira_t_plus_1 - temperatura_inicial_caldeira_t
|
21 |
+
|
22 |
+
energy = (
|
23 |
+
heat_capacity
|
24 |
+
* (delta_t - outside_temp)
|
25 |
+
* (capacidade_caldeira - litros_gastos_no_banho)
|
26 |
+
* 1
|
27 |
+
) # isto vai ser minimo
|
28 |
+
|
29 |
+
delta_t = (
|
30 |
+
temperatura_objetivo_caldeira_t_plus_1 - temperatura_entrada_agua_na_caldeira
|
31 |
+
)
|
32 |
+
energy_incoming_water = (
|
33 |
+
heat_capacity * (delta_t - outside_temp) * litros_gastos_no_banho * 1
|
34 |
+
)
|
35 |
+
|
36 |
+
# 20 Litros totais
|
37 |
+
# Joao gatou 5 litros
|
38 |
+
# Gastar energia em:
|
39 |
+
# 15 litros para manter a temperatura da caldeira -> minimo
|
40 |
+
# 5 litros para aquecer a agua que entra
|
41 |
+
|
42 |
+
total_energy = energy + energy_incoming_water
|
43 |
+
|
44 |
+
# TODO: Correlação entre pressão e temperatura
|
45 |
+
# https://www.engineeringtoolbox.com/boiling-points-water-altitude-d_1344.html
|
46 |
+
# https://www.engineeringtoolbox.com/boiling-point-water-d_926.html
|
47 |
+
"""
|
48 |
+
That depends on whether the pressure is held constant during the heating. If there is a relief valve which maintains
|
49 |
+
constant pressure as the water heats, then no, the 2 samples will heat at the same rate. However, if the pressurised sample
|
50 |
+
has no pressure relief, then it will heat faster because the pressure will increase, and that increase in pressure will increase
|
51 |
+
the heat in addition to the heat applied.
|
52 |
+
"""
|
53 |
+
# kJ
|
54 |
+
|
55 |
+
# TODO: FIND WHAT SHOULD BE THE RELATION BETWEEN TEMPERATURE OF OUTGOING WATER AND BOILER TEMPERATURE
|
56 |
+
temperatura_saida_agua_na_caldeira = temperatura_objetivo_caldeira_t_plus_1 * 0.87
|
57 |
+
|
58 |
+
return total_energy, temperatura_saida_agua_na_caldeira
|
59 |
+
|
60 |
+
|
61 |
+
def calculate_weights_for_all_hours(
|
62 |
+
temperatura_inicial_caldeira,
|
63 |
+
temperatura_objetivo_caldeira,
|
64 |
+
outside_temp,
|
65 |
+
pressao_caldeira,
|
66 |
+
litros_gastos_no_banho,
|
67 |
+
temperatura_entrada_agua_na_caldeira,
|
68 |
+
capacidade_caldeira,
|
69 |
+
):
|
70 |
+
weights = []
|
71 |
+
temperatures = []
|
72 |
+
for i in range(len(temperatura_inicial_caldeira)):
|
73 |
+
energy, temperature_water = spent_energy(
|
74 |
+
temperatura_inicial_caldeira_t=temperatura_inicial_caldeira[i],
|
75 |
+
temperatura_objetivo_caldeira_t_plus_1=temperatura_objetivo_caldeira,
|
76 |
+
outside_temp=outside_temp[i],
|
77 |
+
pressao_caldeira=pressao_caldeira[i],
|
78 |
+
litros_gastos_no_banho=litros_gastos_no_banho,
|
79 |
+
temperatura_entrada_agua_na_caldeira=temperatura_entrada_agua_na_caldeira[
|
80 |
+
i
|
81 |
+
],
|
82 |
+
capacidade_caldeira=capacidade_caldeira,
|
83 |
+
)
|
84 |
+
weights.append(energy)
|
85 |
+
temperatures.append(temperature_water)
|
86 |
+
return weights, temperatures
|
87 |
+
# Output energy wasted
|
88 |
+
|
89 |
+
|
90 |
+
def calculate_confort(temperatura_given, temperatura_ideal):
|
91 |
+
return abs(temperatura_given - temperatura_ideal)
|
92 |
+
|
93 |
+
|
94 |
+
# create exception for no solution found
|
95 |
+
class NoSolutionFound(Exception):
|
96 |
+
pass
|
97 |
+
|
98 |
+
class SoltionFoundWithLargerConfortValue(Exception):
|
99 |
+
pass
|
app/dashboard.ipynb
ADDED
@@ -0,0 +1,294 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"cells": [
|
3 |
+
{
|
4 |
+
"cell_type": "code",
|
5 |
+
"execution_count": 2,
|
6 |
+
"metadata": {},
|
7 |
+
"outputs": [
|
8 |
+
{
|
9 |
+
"name": "stderr",
|
10 |
+
"output_type": "stream",
|
11 |
+
"text": [
|
12 |
+
"/var/folders/b4/lwfgccm95kqd2skcwvrt2fr00000gn/T/ipykernel_7355/1062829466.py:19: FutureWarning:\n",
|
13 |
+
"\n",
|
14 |
+
"The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n",
|
15 |
+
"\n"
|
16 |
+
]
|
17 |
+
},
|
18 |
+
{
|
19 |
+
"data": {
|
20 |
+
"text/html": [
|
21 |
+
"\n",
|
22 |
+
" <iframe\n",
|
23 |
+
" width=\"100%\"\n",
|
24 |
+
" height=\"650\"\n",
|
25 |
+
" src=\"http://0.0.0.0:8050/\"\n",
|
26 |
+
" frameborder=\"0\"\n",
|
27 |
+
" allowfullscreen\n",
|
28 |
+
" \n",
|
29 |
+
" ></iframe>\n",
|
30 |
+
" "
|
31 |
+
],
|
32 |
+
"text/plain": [
|
33 |
+
"<IPython.lib.display.IFrame at 0x28c80a4d0>"
|
34 |
+
]
|
35 |
+
},
|
36 |
+
"metadata": {},
|
37 |
+
"output_type": "display_data"
|
38 |
+
}
|
39 |
+
],
|
40 |
+
"source": [
|
41 |
+
"import os\n",
|
42 |
+
"import plotly.express as px\n",
|
43 |
+
"import plotly.graph_objects as go\n",
|
44 |
+
"import pandas as pd\n",
|
45 |
+
"from dash import Dash, html, dcc, Input, Output, callback\n",
|
46 |
+
"import plotly.express as px\n",
|
47 |
+
"import numpy as np\n",
|
48 |
+
"import example_data\n",
|
49 |
+
"import core\n",
|
50 |
+
"\n",
|
51 |
+
"\n",
|
52 |
+
"outside_temp = example_data.ExampleDailyOutsideTemperature\n",
|
53 |
+
"energy_price = example_data.ExampleDailyEnergyCost\n",
|
54 |
+
"boiler_temperature = example_data.ExampleBoilerTemperature\n",
|
55 |
+
"\n",
|
56 |
+
"\n",
|
57 |
+
"\n",
|
58 |
+
"data = pd.DataFrame(columns=['hour', 'energy_consumption', 'confort', 'policy_readable'])\n",
|
59 |
+
"data = pd.concat([data, pd.DataFrame({'hour': np.arange(0, 24), 'energy_consumption': energy_price.value, 'confort': np.random.rand(24),\n",
|
60 |
+
" 'policy_readable': np.random.choice(['A', 'B', 'C', 'D', 'E'], 24)\n",
|
61 |
+
" })])\n",
|
62 |
+
"debug = False\n",
|
63 |
+
"\n",
|
64 |
+
"\n",
|
65 |
+
"external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']\n",
|
66 |
+
"\n",
|
67 |
+
"app = Dash(__name__, external_stylesheets=external_stylesheets)\n",
|
68 |
+
"\n",
|
69 |
+
"app.layout = html.Div([\n",
|
70 |
+
" dcc.Location(id='url', refresh=False),\n",
|
71 |
+
" html.Div(id='page-content')\n",
|
72 |
+
"])\n",
|
73 |
+
"\n",
|
74 |
+
"server = app.server\n",
|
75 |
+
"\n",
|
76 |
+
"\n",
|
77 |
+
"# SOlution options\n",
|
78 |
+
"solution_options = [\n",
|
79 |
+
" \"Discrete Optimization\",\n",
|
80 |
+
" \"Continuous Optimization\",\n",
|
81 |
+
" \"Reinforcement Learning\"\n",
|
82 |
+
"]\n",
|
83 |
+
"solution_options_default_value = solution_options[0]\n",
|
84 |
+
"\n",
|
85 |
+
"# provide a scalar value to enable the slider to select ideal temperature\n",
|
86 |
+
"ideal_temperature = 50\n",
|
87 |
+
"\n",
|
88 |
+
"dashboard_layout = html.Div([\n",
|
89 |
+
" dcc.Link('About this project', href='/wiki'),\n",
|
90 |
+
"\n",
|
91 |
+
" html.H1('System Evaluation'),\n",
|
92 |
+
" #small subtitle that says of solution is possible or not\n",
|
93 |
+
" html.Div(id='solution-status', children='', style={'color': 'lighrgrey'}),\n",
|
94 |
+
" html.Div([\n",
|
95 |
+
" html.Div([\n",
|
96 |
+
" html.H3('Solution'),\n",
|
97 |
+
" dcc.Dropdown(\n",
|
98 |
+
" id='solution-dropdown',\n",
|
99 |
+
" options=solution_options,\n",
|
100 |
+
" value=solution_options_default_value,\n",
|
101 |
+
" )\n",
|
102 |
+
" ], className='three columns'),\n",
|
103 |
+
" html.Div([\n",
|
104 |
+
" html.H3('Ideal Shower Temperature'),\n",
|
105 |
+
" dcc.Slider(\n",
|
106 |
+
" id='ideal-temperature-slider',\n",
|
107 |
+
" min=0,\n",
|
108 |
+
" max=100,\n",
|
109 |
+
" step=1,\n",
|
110 |
+
" value=ideal_temperature,\n",
|
111 |
+
" marks={\n",
|
112 |
+
" 0: '0°C',\n",
|
113 |
+
" 25: '25°C',\n",
|
114 |
+
" 50: '50°C',\n",
|
115 |
+
" 75: '75°C',\n",
|
116 |
+
" 100: '100°C'\n",
|
117 |
+
" },\n",
|
118 |
+
" )\n",
|
119 |
+
" ], className='three columns'),\n",
|
120 |
+
"\n",
|
121 |
+
"\n",
|
122 |
+
" ], className='row'),\n",
|
123 |
+
" html.Div(\n",
|
124 |
+
" [\n",
|
125 |
+
" html.Div(\n",
|
126 |
+
" [\n",
|
127 |
+
" html.H3('Policy'),\n",
|
128 |
+
" dcc.Graph(id='policy_readable-graph')\n",
|
129 |
+
" ], className='six columns',\n",
|
130 |
+
" ),\n",
|
131 |
+
" html.Div(\n",
|
132 |
+
" [\n",
|
133 |
+
" html.H3('Energy Consumption'),\n",
|
134 |
+
" dcc.Graph(id='energy-comsumption-graph')\n",
|
135 |
+
" ], className='six columns'\n",
|
136 |
+
" )\n",
|
137 |
+
" ], className='row'),\n",
|
138 |
+
" html.Div(\n",
|
139 |
+
" [\n",
|
140 |
+
" html.Div(\n",
|
141 |
+
" [\n",
|
142 |
+
" html.H3('Confort'),\n",
|
143 |
+
" dcc.Graph(id='confort-graph')\n",
|
144 |
+
" ], className='six columns'\n",
|
145 |
+
" )\n",
|
146 |
+
" ], className='row'),\n",
|
147 |
+
"],\n",
|
148 |
+
"#add background image from local file and make it transparent\n",
|
149 |
+
"#, style={'background-image':'url(/assets/background_1.png)'}\n",
|
150 |
+
"style={'background-color': '#4B5320', 'font-family': 'Fantasy', 'color': '#8F9779', 'padding': '10px'}\n",
|
151 |
+
")\n",
|
152 |
+
"\n",
|
153 |
+
"\n",
|
154 |
+
"\n",
|
155 |
+
"wiki_layout = html.Div([\n",
|
156 |
+
" dcc.Link('Dashboard', href='/'),\n",
|
157 |
+
"\n",
|
158 |
+
" html.H1('About this project'),\n",
|
159 |
+
"\n",
|
160 |
+
" html.Div([\n",
|
161 |
+
" html.Div([\n",
|
162 |
+
" \n",
|
163 |
+
" html.H3('What is this project about?'),\n",
|
164 |
+
"\n",
|
165 |
+
" html.P('This project is a simulation of a shower system. The goal is to find the best policy for the boiler to heat the water for the shower. The policy is a function that takes the current hour of the day and the current temperature of the water in the boiler and returns the temperature that the boiler should heat the water to.'),\n",
|
166 |
+
" html.P('The best policy is the one that maximizes the confort of the shower and minimizes the energy consumption of the boiler.'),\n",
|
167 |
+
"\n",
|
168 |
+
" html.H3('How does it work?'),\n",
|
169 |
+
"\n",
|
170 |
+
" #Insert image of the system\n",
|
171 |
+
"\n",
|
172 |
+
" html.H3('\\'Bout us'),\n",
|
173 |
+
" html.Img(src='/assets/hackatos.png', style={'width': '40%', 'height': 'auto', 'display': 'block', 'margin-left': 'auto', 'margin-right': 'auto'}),\n",
|
174 |
+
" html.P('This project was developed by a team of 3, in the context of the Aveiro Tech City 2023 hackathon.'),\n",
|
175 |
+
" html.P('The team members are:'),\n",
|
176 |
+
" html.H4('Rui Melo'),\n",
|
177 |
+
" html.P('Rui Melo is a ....'),\n",
|
178 |
+
" html.H4('André Catarino'),\n",
|
179 |
+
" html.P('André Catarino is a ....'),\n",
|
180 |
+
" html.H4('Francisco Petronilho'),\n",
|
181 |
+
" html.P('Francisco Petronilho is a ....'),\n",
|
182 |
+
" html.H4('André Tomás'),\n",
|
183 |
+
" html.P('André Tomás is a ....'),\n",
|
184 |
+
" html.H4('Zé Miguel'),\n",
|
185 |
+
" html.P('Zé Miguel is a ....'),\n",
|
186 |
+
"\n",
|
187 |
+
"\n",
|
188 |
+
" html.H3('References'),\n",
|
189 |
+
" html.P('The boiler model was based on the following paper:'),\n",
|
190 |
+
"\n",
|
191 |
+
"\n",
|
192 |
+
" ], className='six columns'),], className='row'),\n",
|
193 |
+
"],\n",
|
194 |
+
"style={'background-color': '#4B5320', 'font-family': 'Fantasy', 'color': '#8F9779', 'padding': '10px'}\n",
|
195 |
+
"\n",
|
196 |
+
")\n",
|
197 |
+
"\n",
|
198 |
+
"# Update the index\n",
|
199 |
+
"@callback(Output('page-content', 'children'), Input('url', 'pathname'))\n",
|
200 |
+
"def display_page(pathname):\n",
|
201 |
+
" if pathname == '/':\n",
|
202 |
+
" return dashboard_layout\n",
|
203 |
+
" elif pathname == '/wiki':\n",
|
204 |
+
" return wiki_layout\n",
|
205 |
+
" else:\n",
|
206 |
+
" return '404'\n",
|
207 |
+
" # You could also return a 404 \"URL not found\" page here\n",
|
208 |
+
"\n",
|
209 |
+
"\n",
|
210 |
+
"\n",
|
211 |
+
"@app.callback(\n",
|
212 |
+
" Output('policy_readable-graph', 'figure'),\n",
|
213 |
+
" Output('energy-comsumption-graph', 'figure'),\n",
|
214 |
+
" Output('confort-graph', 'figure'),\n",
|
215 |
+
" Output('solution-status', 'children'),\n",
|
216 |
+
" Input('solution-dropdown', 'value'),\n",
|
217 |
+
" Input('ideal-temperature-slider', 'value')\n",
|
218 |
+
")\n",
|
219 |
+
"def update_graph(solution, ideal_temperature):\n",
|
220 |
+
" energy_consumption = data['energy_consumption'].values\n",
|
221 |
+
" confort_obtained = data['confort'].values\n",
|
222 |
+
"\n",
|
223 |
+
"\n",
|
224 |
+
" policy_readable_graph = px.line(data, x='hour', y='policy_readable',\n",
|
225 |
+
" labels={'hour': 'Hour', 'policy_readable': 'Policy'},\n",
|
226 |
+
" color_discrete_sequence=['lightgreen'])\n",
|
227 |
+
" policy_readable_graph.update_layout(\n",
|
228 |
+
" xaxis_title=\"Hour\",\n",
|
229 |
+
" yaxis_title=\"Temperature (°C)\",\n",
|
230 |
+
" legend_title=\"Policy\"\n",
|
231 |
+
" )\n",
|
232 |
+
"\n",
|
233 |
+
" energy_consumption_graph = px.line(data, x='hour', \n",
|
234 |
+
" y='energy_consumption', \n",
|
235 |
+
" labels={'hour': 'Hour', 'energy_consumption': 'Energy Consumption (kWh)'},\n",
|
236 |
+
" color_discrete_sequence=['lightgreen'])\n",
|
237 |
+
" energy_consumption_graph.update_layout(\n",
|
238 |
+
" xaxis_title=\"Hour\",\n",
|
239 |
+
" yaxis_title=\"Energy Consumption (kWh)\",\n",
|
240 |
+
" legend_title=\"Energy Consumption\",\n",
|
241 |
+
" )\n",
|
242 |
+
" #add accumulated energy consumption\n",
|
243 |
+
" energy_consumption = np.cumsum(energy_consumption)\n",
|
244 |
+
" energy_consumption_graph.add_trace(px.line(data, x='hour', \n",
|
245 |
+
" y=energy_consumption,\n",
|
246 |
+
" labels={'y': 'Acc. Energy Consumption (kWh)'},\n",
|
247 |
+
" color_discrete_sequence=['green']).data[0])\n",
|
248 |
+
"\n",
|
249 |
+
" confort_graph = px.line(data, x='hour', y='confort',\n",
|
250 |
+
" labels={'hour': 'Hour', 'confort': 'Confort Score'},\n",
|
251 |
+
" color_discrete_sequence=['lightgreen'])\n",
|
252 |
+
"\n",
|
253 |
+
" confort_graph.update_layout(\n",
|
254 |
+
" xaxis_title=\"Hour\",\n",
|
255 |
+
" yaxis_title=\"Confort Score\",\n",
|
256 |
+
" legend_title=\"Confort\"\n",
|
257 |
+
" )\n",
|
258 |
+
" #add accumulated confort\n",
|
259 |
+
" confort_obtained = np.cumsum(confort_obtained)\n",
|
260 |
+
" confort_graph.add_trace(px.line(data, x='hour', y=confort_obtained,\n",
|
261 |
+
" labels={'y': 'Acc. Confort Score'},\n",
|
262 |
+
" color_discrete_sequence=['green']\n",
|
263 |
+
" ).data[0])\n",
|
264 |
+
" result = \"No solution found\"\n",
|
265 |
+
" return policy_readable_graph, energy_consumption_graph, confort_graph, result\n",
|
266 |
+
"if __name__ == \"__main__\":\n",
|
267 |
+
" app.run_server(host=\"0.0.0.0\", port=\"8050\", debug=debug)\n",
|
268 |
+
"\n"
|
269 |
+
]
|
270 |
+
}
|
271 |
+
],
|
272 |
+
"metadata": {
|
273 |
+
"kernelspec": {
|
274 |
+
"display_name": "atc-smart-shower-YhjpRjjr-py3.10",
|
275 |
+
"language": "python",
|
276 |
+
"name": "python3"
|
277 |
+
},
|
278 |
+
"language_info": {
|
279 |
+
"codemirror_mode": {
|
280 |
+
"name": "ipython",
|
281 |
+
"version": 3
|
282 |
+
},
|
283 |
+
"file_extension": ".py",
|
284 |
+
"mimetype": "text/x-python",
|
285 |
+
"name": "python",
|
286 |
+
"nbconvert_exporter": "python",
|
287 |
+
"pygments_lexer": "ipython3",
|
288 |
+
"version": "3.10.13"
|
289 |
+
},
|
290 |
+
"orig_nbformat": 4
|
291 |
+
},
|
292 |
+
"nbformat": 4,
|
293 |
+
"nbformat_minor": 2
|
294 |
+
}
|
app/example_data.py
ADDED
@@ -0,0 +1,140 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from dataclasses import dataclass
|
2 |
+
|
3 |
+
|
4 |
+
@dataclass
|
5 |
+
class ExampleDailyOutsideTemperature:
|
6 |
+
"""Outside temperature in degrees Celsius"""
|
7 |
+
|
8 |
+
value = [
|
9 |
+
9.05,
|
10 |
+
8.38,
|
11 |
+
7.61,
|
12 |
+
6.85,
|
13 |
+
6.41,
|
14 |
+
5.66,
|
15 |
+
5.77,
|
16 |
+
5.02,
|
17 |
+
4.97,
|
18 |
+
5.15,
|
19 |
+
7.26,
|
20 |
+
8.06,
|
21 |
+
8.47,
|
22 |
+
8.59,
|
23 |
+
8.86,
|
24 |
+
8.87,
|
25 |
+
8.86,
|
26 |
+
8.71,
|
27 |
+
8.36,
|
28 |
+
8.11,
|
29 |
+
7.87,
|
30 |
+
7.7,
|
31 |
+
7.98,
|
32 |
+
7.62,
|
33 |
+
]
|
34 |
+
temperatura_entrada_agua = [x * 0.9 for x in value]
|
35 |
+
|
36 |
+
temperatura_saida_agua = 50
|
37 |
+
|
38 |
+
def temperatura_entrada_no_banho(self, potencia):
|
39 |
+
return [value * potencia for value in self.value]
|
40 |
+
|
41 |
+
|
42 |
+
@dataclass
|
43 |
+
class ExampleBoilerTemperature:
|
44 |
+
"""Boiler temperature in degrees Celsius"""
|
45 |
+
|
46 |
+
value = [
|
47 |
+
9.05,
|
48 |
+
8.38,
|
49 |
+
7.61,
|
50 |
+
6.85,
|
51 |
+
6.41,
|
52 |
+
5.66,
|
53 |
+
5.77,
|
54 |
+
5.02,
|
55 |
+
4.97,
|
56 |
+
5.15,
|
57 |
+
7.26,
|
58 |
+
8.06,
|
59 |
+
8.47,
|
60 |
+
8.59,
|
61 |
+
8.86,
|
62 |
+
8.87,
|
63 |
+
8.86,
|
64 |
+
8.71,
|
65 |
+
8.36,
|
66 |
+
8.11,
|
67 |
+
7.87,
|
68 |
+
7.7,
|
69 |
+
7.98,
|
70 |
+
7.62,
|
71 |
+
]
|
72 |
+
|
73 |
+
temperature = [x * 2 for x in value]
|
74 |
+
|
75 |
+
|
76 |
+
@dataclass
|
77 |
+
class ExampleDailyEnergyCost:
|
78 |
+
"""Energy cost in eur per kWh"""
|
79 |
+
|
80 |
+
value = [
|
81 |
+
0.5266399999999999,
|
82 |
+
0.45166399999999995,
|
83 |
+
0.34220000000000006,
|
84 |
+
0.32719999999999994,
|
85 |
+
0.3608,
|
86 |
+
0.45879199999999987,
|
87 |
+
0.4177600000000001,
|
88 |
+
0.43716800000000006,
|
89 |
+
0.4400000000000001,
|
90 |
+
0.44004800000000005,
|
91 |
+
0.440016,
|
92 |
+
0.4400000000000001,
|
93 |
+
0.4400000000000001,
|
94 |
+
0.4412,
|
95 |
+
0.4412,
|
96 |
+
0.44480000000000003,
|
97 |
+
0.44160000000000005,
|
98 |
+
0.44160000000000005,
|
99 |
+
0.45439999999999997,
|
100 |
+
0.45439999999999997,
|
101 |
+
0.4512,
|
102 |
+
0.4400000000000001,
|
103 |
+
0.428208,
|
104 |
+
0.49184000000000005,
|
105 |
+
]
|
106 |
+
|
107 |
+
|
108 |
+
@dataclass
|
109 |
+
class ExampleBoilerPressure:
|
110 |
+
value = [
|
111 |
+
0.5266399999999999,
|
112 |
+
0.45166399999999995,
|
113 |
+
0.34220000000000006,
|
114 |
+
0.32719999999999994,
|
115 |
+
0.3608,
|
116 |
+
0.45879199999999987,
|
117 |
+
0.4177600000000001,
|
118 |
+
0.43716800000000006,
|
119 |
+
0.4400000000000001,
|
120 |
+
0.44004800000000005,
|
121 |
+
0.440016,
|
122 |
+
0.4400000000000001,
|
123 |
+
0.4400000000000001,
|
124 |
+
0.4412,
|
125 |
+
0.4412,
|
126 |
+
0.44480000000000003,
|
127 |
+
0.44160000000000005,
|
128 |
+
0.44160000000000005,
|
129 |
+
0.45439999999999997,
|
130 |
+
0.45439999999999997,
|
131 |
+
0.4512,
|
132 |
+
0.4400000000000001,
|
133 |
+
0.428208,
|
134 |
+
0.49184000000000005,
|
135 |
+
]
|
136 |
+
|
137 |
+
pressure = [x * 4.3 for x in value]
|
138 |
+
|
139 |
+
|
140 |
+
TEMPERATURA_IDEAL = 40
|
app/requirements.txt
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
dash
|
2 |
+
plotly
|
3 |
+
pandas
|
4 |
+
gunicorn
|
5 |
+
wandb==0.15.5
|
6 |
+
scipy
|
dashboard.py
ADDED
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import pandas as pd
|
2 |
+
|
3 |
+
data = pd.DataFrame(columns=["Dataset", "Alpha", "Top K", "Recall", "Precision"])
|
4 |
+
data = pd.concat(
|
5 |
+
[
|
6 |
+
data,
|
7 |
+
pd.DataFrame(
|
8 |
+
[["ml-100k", 0.1, 20, 0.2, 0.2]],
|
9 |
+
columns=["Dataset", "Alpha", "Top K", "Recall", "Precision"],
|
10 |
+
),
|
11 |
+
]
|
12 |
+
)
|
13 |
+
|
14 |
+
import os
|
15 |
+
import plotly.express as px
|
16 |
+
import pandas as pd
|
17 |
+
from dash import Dash, html, dcc, Input, Output, callback
|
18 |
+
import plotly.express as px
|
19 |
+
from dataclasses import dataclass
|
20 |
+
import json
|
21 |
+
|
22 |
+
data = pd.DataFrame(columns=["Dataset", "Alpha", "Top K", "Recall", "Precision"])
|
23 |
+
data = pd.concat(
|
24 |
+
[
|
25 |
+
data,
|
26 |
+
pd.DataFrame(
|
27 |
+
[["ml-100k", 0.1, 20, 0.2, 0.2]],
|
28 |
+
columns=["Dataset", "Alpha", "Top K", "Recall", "Precision"],
|
29 |
+
),
|
30 |
+
]
|
31 |
+
)
|
32 |
+
debug = False
|
33 |
+
|
34 |
+
|
35 |
+
external_stylesheets = ["https://codepen.io/chriddyp/pen/bWLwgP.css"]
|
36 |
+
|
37 |
+
app = Dash(__name__, external_stylesheets=external_stylesheets)
|
38 |
+
|
39 |
+
server = app.server
|
40 |
+
|
41 |
+
|
42 |
+
dataset_options = [
|
43 |
+
{"label": entry, "value": entry} for entry in data["Dataset"].unique()
|
44 |
+
]
|
45 |
+
dataset_options_default_value = data["Dataset"].unique()[0]
|
46 |
+
|
47 |
+
alpha_options = [{"label": entry, "value": entry} for entry in data["Alpha"].unique()]
|
48 |
+
alpha_options_default_value = data["Alpha"].unique()[0]
|
49 |
+
|
50 |
+
top_k_options = [{"label": entry, "value": entry} for entry in data["Top K"].unique()]
|
51 |
+
top_k_options_default_value = data["Top K"].unique()[0]
|
52 |
+
|
53 |
+
app.layout = html.Div(
|
54 |
+
[
|
55 |
+
html.H1("System Evaluation"),
|
56 |
+
html.Div(
|
57 |
+
[
|
58 |
+
html.Div(
|
59 |
+
[
|
60 |
+
html.H3("Dataset"),
|
61 |
+
dcc.Dropdown(
|
62 |
+
id="dataset-dropdown",
|
63 |
+
options=dataset_options,
|
64 |
+
value=dataset_options_default_value,
|
65 |
+
),
|
66 |
+
],
|
67 |
+
className="three columns",
|
68 |
+
),
|
69 |
+
html.Div(
|
70 |
+
[
|
71 |
+
html.H3("Alpha"),
|
72 |
+
dcc.Dropdown(
|
73 |
+
id="alpha-dropdown",
|
74 |
+
options=alpha_options,
|
75 |
+
value=alpha_options_default_value,
|
76 |
+
),
|
77 |
+
],
|
78 |
+
className="three columns",
|
79 |
+
),
|
80 |
+
html.Div(
|
81 |
+
[
|
82 |
+
html.H3("Top K"),
|
83 |
+
dcc.Dropdown(
|
84 |
+
id="top_k-dropdown",
|
85 |
+
options=top_k_options,
|
86 |
+
value=top_k_options_default_value,
|
87 |
+
),
|
88 |
+
],
|
89 |
+
className="three columns",
|
90 |
+
),
|
91 |
+
],
|
92 |
+
className="row",
|
93 |
+
),
|
94 |
+
html.Div(
|
95 |
+
[
|
96 |
+
html.Div([dcc.Graph(id="recall-graph")], className="six columns"),
|
97 |
+
html.Div([dcc.Graph(id="precision-graph")], className="six columns"),
|
98 |
+
],
|
99 |
+
className="row",
|
100 |
+
),
|
101 |
+
]
|
102 |
+
)
|
103 |
+
|
104 |
+
|
105 |
+
@app.callback(
|
106 |
+
Output("recall-graph", "figure"),
|
107 |
+
Output("precision-graph", "figure"),
|
108 |
+
Input("alpha-dropdown", "value"),
|
109 |
+
Input("dataset-dropdown", "value"),
|
110 |
+
Input("top_k-dropdown", "value"),
|
111 |
+
)
|
112 |
+
def update_graph(alpha, dataset, top_k):
|
113 |
+
filtered_data = data[
|
114 |
+
(data["Alpha"] == alpha)
|
115 |
+
& (data["Dataset"] == dataset)
|
116 |
+
& (data["Top K"] == top_k)
|
117 |
+
]
|
118 |
+
recall_fig = px.bar(filtered_data, x="Dataset", y="Recall")
|
119 |
+
precision_fig = px.bar(filtered_data, x="Dataset", y="Precision")
|
120 |
+
return recall_fig, precision_fig
|
121 |
+
|
122 |
+
|
123 |
+
# Run app and display result inline in the notebook
|
124 |
+
if __name__ == "__main__":
|
125 |
+
app.run_server(debug=debug, port=8050)
|