Commit b0da5bf6 authored by Rosanny Sihombing's avatar Rosanny Sihombing
Browse files

first commit

parent 7abcb82b
Showing with 1027 additions and 576 deletions
+1027 -576
venv/
__pycache__/
result/
input/
\ No newline at end of file
# disaggregation # disaggregation - web application
This branch is the web app implementation of the master branch, in which the grids are visualized in a 3D globe using CesiumJS.
Source code for disaggregation ### Demo
\ No newline at end of file http://193.196.55.138/ensource2/
\ No newline at end of file
File moved
"""
@author: Andrés Lalama
"""
from locale import atof, setlocale, LC_NUMERIC from locale import atof, setlocale, LC_NUMERIC
import time import time
from typing import List from typing import List
...@@ -16,7 +12,16 @@ import time ...@@ -16,7 +12,16 @@ import time
import os import os
import platform import platform
from datetime import datetime from datetime import datetime
# Flask
from flask import Flask, render_template, request
from werkzeug.utils import secure_filename
# Define the folder of the input data
UPLOAD_FOLDER = 'input'
ALLOWED_EXTENSIONS = {'csv'}
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
class Segment(object): class Segment(object):
def __init__(self, def __init__(self,
...@@ -24,7 +29,7 @@ class Segment(object): ...@@ -24,7 +29,7 @@ class Segment(object):
neighbors=None, neighbors=None,
demand=float, demand=float,
length=None, length=None,
totalDistance=None, totalDistance=None,
isInGrid=False, geometry=None): isInGrid=False, geometry=None):
self.id = id self.id = id
self.neighbors: List[int] = neighbors self.neighbors: List[int] = neighbors
...@@ -35,18 +40,16 @@ class Segment(object): ...@@ -35,18 +40,16 @@ class Segment(object):
self.hasUnusedSegments = True self.hasUnusedSegments = True
self.geometry = geometry self.geometry = geometry
class HeatGrid: class HeatGrid:
def __init__(self, id: int, targetDemand: float = None, segments=[]): def __init__(self, id: int, segmentsFile, targetDemand: float = None, segments=[]):
self.id = id self.id = id
self.c1 = 368 self.c1 = 368
self.c2 = 2602.5 self.c2 = 2602.5
self.a = 0.0725 self.a = 0.0725
# use 'self.targetDemand = targetDemand' in order to use the maximal possible energy demand # use 'self.targetDemand = targetDemand' in order to use the maximal possible energy demand
self.targetDemand = targetDemand self.targetDemand = targetDemand
#self.targetDemand = 33518557 #self.segmentsFile = ".\\heatingDemandAdjusted\\Advanced\\Adjusted_stat_lines_with_industry.csv"
#self.segmentsFile = "ise_files\\stat_lines_with_industry_v2102.csv" self.segmentsFile = segmentsFile
self.segmentsFile = "ise_files\\Rainau_stat_lines_with_industry.csv"
self.accumulatedDemand = 0 self.accumulatedDemand = 0
self.segments = segments self.segments = segments
self.availableSegments = [] self.availableSegments = []
...@@ -66,14 +69,13 @@ class HeatGrid: ...@@ -66,14 +69,13 @@ class HeatGrid:
segmentData = pd.read_excel(self.segmentsFile) segmentData = pd.read_excel(self.segmentsFile)
rightArguments = segmentData rightArguments = segmentData
# setting german locale because of excel files # setting german locale because of excel files
setlocale(LC_NUMERIC, 'German_Germany.1252') setlocale(LC_NUMERIC, 'de_DE')
for index, row in rightArguments.iterrows(): for index, row in rightArguments.iterrows():
length = row['Length'] length = row['Length']
totalDistance = row['Total Distance'] totalDistance = row['Total Distance']
demand = row['Total Yearly Heat+DHW demand'] demand = row['Total Yearly Heat+DHW demand']
if isinstance(length, float) is False: if isinstance(length, float) is False:
length = atof(length) length = atof(length)
if isinstance(totalDistance, float) is False: if isinstance(totalDistance, float) is False:
...@@ -383,7 +385,7 @@ def serialize(obj): ...@@ -383,7 +385,7 @@ def serialize(obj):
segNeighborDic: dict = {} segNeighborDic: dict = {}
grid = HeatGrid(1) #grid = HeatGrid(1)
def gridCost(grid, total_demand_kWh, total_length_m): def gridCost(grid, total_demand_kWh, total_length_m):
...@@ -395,7 +397,7 @@ def gridCost(grid, total_demand_kWh, total_length_m): ...@@ -395,7 +397,7 @@ def gridCost(grid, total_demand_kWh, total_length_m):
# prints all segments of the grid # prints all segments of the grid
def exportResult(): def exportResult(grid):
for segment in grid.segments: for segment in grid.segments:
print(segment.id) print(segment.id)
...@@ -439,508 +441,96 @@ def printResults(grid): ...@@ -439,508 +441,96 @@ def printResults(grid):
print(f'Please Open the the result file in the result Report') print(f'Please Open the the result file in the result Report')
def main(argv): @app.route('/ensource2/', methods = ['GET', 'POST'])
try: def index():
opts, args = getopt.getopt( if request.method == 'GET':
argv, "ht:s:g:k:o:r:", ["target=", "segments=", "grid=", "kommod=", "outfile=", "rabbitmq=", "gui="]) return render_template('form.html')
except getopt.GetoptError: if request.method == 'POST':
print('Did not recognize all of the user arguments. Use \'-h\' for help.') # upload input file
file = request.files['file']
sys.exit(2) filename = secure_filename(file.filename)
print('==================================') file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
print(' ENsource Disaggregation') filepath = UPLOAD_FOLDER+'/'+filename
print('==================================') # define grid
grid.givenGridAvailable = False grid = HeatGrid(1, filepath)
for opt, arg in opts: # set/reset grid segments
if opt == '-h': grid.segments = []
printHelp()
sys.exit() print('==================================')
elif opt in ("-t", "--target"): print(' ENsource Disaggregation')
target = arg print('==================================')
grid.targetDemand = float(target) grid.givenGridAvailable = False
print('Target (kWh) :', target)
elif opt in ("-c1", "--c1"):
grid.c1 = arg
print('Target (kWh) :', target)
elif opt in ("-s", "--segments"):
grid.segmentsFile = arg
print('Segments file :', grid.segmentsFile)
elif opt in ("-g", "--grid"):
givenGridIds = arg
grid.givenGridAvailable = True
print('Grid IDs :', givenGridIds)
elif opt in ("-k", "--kommod"):
komModFile = arg
grid.importKomModFromFile(komModFile)
elif opt in ("-r", "--rabbitmq"):
inputfile = arg
grid.importFromFile()
if grid.givenGridAvailable:
grid.givenGridStr = "True"
for id in givenGridIds.split(","):
grid.addSegmentById(id)
else:
grid.givenGridStr = "False"
givenGridIds = "N/A"
print('==================================')
print(' Running Algorithm')
print('==================================')
maxPossibleDemand = sum(seg.demand for seg in grid.availableSegments) grid.importFromFile()
if grid.targetDemand is None: if grid.givenGridAvailable:
grid.targetDemand = maxPossibleDemand grid.givenGridStr = "True"
print(f'No target demand provided.') for id in givenGridIds.split(","):
print(f'Using max possible demand: {round(maxPossibleDemand,3)}') grid.addSegmentById(id)
if grid.targetDemand > maxPossibleDemand: else:
print(f'---------->> ERROR <<-------------') grid.givenGridStr = "False"
print(f'Target demand : {target}') givenGridIds = "N/A"
print(f'Max possible demand : {round(maxPossibleDemand,3)}')
print('The target demand is higher than given segments allow')
print('==================================') print('==================================')
return print(' Running Algorithm')
start = time.time() print('==================================')
grid.calculateGrid()
end = time.time() maxPossibleDemand = sum(seg.demand for seg in grid.availableSegments)
print('Runtime: ',end - start ) if grid.targetDemand is None:
d = datetime.now() grid.targetDemand = maxPossibleDemand
folderName = f'result_{d.year}{d.month}{d.day}{d.hour}{d.minute}{d.second}' print(f'No target demand provided.')
filepathHtml = f'{folderName}.html' print(f'Using max possible demand: {round(maxPossibleDemand,3)}')
if grid.targetDemand > maxPossibleDemand:
# create folder for files print(f'---------->> ERROR <<-------------')
os.mkdir(folderName) print(f'Target demand : {target}')
print(f'Max possible demand : {round(maxPossibleDemand,3)}')
# write html file print('The target demand is higher than given segments allow')
resultFileHtml = open(folderName+f'/{folderName}.html', 'w') print('==================================')
wholeGrid = json.dumps(grid.availableSegments, return
default=serialize, indent=2) start = time.time()
grid.calculateGrid()
# write csv file end = time.time()
resultFileCsv = open(folderName+f'/{folderName}.csv', 'w') print('Runtime: ',end - start )
# write headers d = datetime.now()
headers = 'Segment ID;Demand (kWh);Length (m);Total Distance (m);Acc. Demand (kWh);Total Grid Length(m);Acc. Grid Cost (EUR);Spec. Grid Cost (EUR/kWh)' #folderName = f'result_{d.year}{d.month}{d.day}{d.hour}{d.minute}{d.second}'
resultFileCsv.write(headers) folderName= 'result'
accDemand = 0 fileName = f'result_{d.year}{d.month}{d.day}{d.hour}{d.minute}{d.second}'
totalGridLength = 0
accCost = 0 # create folder for files
for seg in grid.segments: #os.mkdir(folderName)
accDemand += seg.demand
totalGridLength += (seg.length + seg.totalDistance) wholeGrid = json.dumps(grid.availableSegments,
accCost = gridCost(grid, accDemand, totalGridLength) default=serialize, indent=2)
specCost = accCost / accDemand
resultFileCsv.write("\n") # write csv file
resultFileCsv.write( resultFileCsv = open(folderName+f'/{fileName}.csv', 'w')
f'{seg.id};{seg.demand};{seg.length};{seg.totalDistance};{accDemand};{totalGridLength};{accCost};{specCost}') # write headers
headers = 'Segment ID;Demand (kWh);Length (m);Total Distance (m);Acc. Demand (kWh);Total Grid Length(m);Acc. Grid Cost (EUR);Spec. Grid Cost (EUR/kWh)'
resultFileCsv.close() resultFileCsv.write(headers)
accDemand = 0
# write json file totalGridLength = 0
# delete attributes to avoid cycles in the data accCost = 0
delattr(grid, 'availableSegments') for seg in grid.segments:
delattr(grid, 'komMod') accDemand += seg.demand
jsonResultGrid = json.dumps(grid, default=serialize, indent=2) totalGridLength += (seg.length + seg.totalDistance)
resultFileJson = open(folderName+f'/{folderName}.json', 'w') accCost = gridCost(grid, accDemand, totalGridLength)
resultReport = """<html> specCost = accCost / accDemand
<head> resultFileCsv.write("\n")
<meta charset=\"UTF-8\"> resultFileCsv.write(
<style> f'{seg.id};{seg.demand};{seg.length};{seg.totalDistance};{accDemand};{totalGridLength};{accCost};{specCost}')
h1 {
text-align: center; resultFileCsv.close()
color: #002C55;
} # write json file
# delete attributes to avoid cycles in the data
h2 { delattr(grid, 'availableSegments')
text-align: left; delattr(grid, 'komMod')
font-size: 25px; jsonResultGrid = json.dumps(grid, default=serialize, indent=2)
font-weight: \"bold\"; resultFileJson = open(folderName+f'/{fileName}.json', 'w')
color: #002C55; resultFileJson.write(jsonResultGrid)
} resultFileJson.close()
resultFile = f'{fileName}.json'
h1 span { resultFileCsvFormat = f'{fileName}.csv'
color: #549925;
} return render_template('index.html', givenGridIds=givenGridIds, resultFileJson=resultFile, resultFileCsv=resultFileCsvFormat, wholeGrid=wholeGrid, grid=jsonResultGrid)
table { #if __name__ == "__main__":
border-collapse: collapse; # app.run(host='0.0.0.0')
border: 1px solid #DFDCDC;
border-spacing: 0;
}
th {
background-color: #549925;
color: white;
text-align: left;
padding: 8px;
}
td {
text-align: left;
padding: 8px;
}
tr:nth-child(even) {
background-color: #e7f4d9;
}
table th,
table td {
border-top: 1px #efe9e3;
border-right: 0px #efe9e3;
border-bottom: 0px #efe9e3;
border-left: 1px #efe9e3;
}
input[type=\"file\"] {
z-index: -1;
position: absolute;
visibility: hidden;
}
.button {
float: left;
padding: 12px 18px;
margin-right: 10px;
cursor: pointer;
border-radius: 3px;
background-color: #549925;
font-size: 14px;
font-weight: bold;
color: #fff;
}
.button2 {
float: left;
padding: 6px 9px;
cursor: pointer;
margin-top: 20px;
margin-left: 15px;
border-radius: 5px;
background-color: #549925;
font-size: 12px;
font-weight: bold;
color: #fff;
width: 30px;
}
</style>
</head>
<body>
<h1><span>EN</span>source Disaggregation Report</h1>
<h2 style=\"float:left; width: 100%;\">Run Results</h2>
<table style=\"float:left; width: 49%; margin-right: 10;\">
<tr>
<th>Target Demand (kWh)</th>
<td id=\"target-demand\">N/A</td>
</tr>
<tr>
<th>Results File</th>
<td id=\"file-name\">N/A</td>
</tr>
<tr>
<th>Segments File</th>
<td id=\"segments-file-name\">"""+grid.segmentsFile+"""</td>
</tr>
<tr>
<th>Available Segments</th>
<td id=\"available-segments\">N/A</td>
</tr>
<tr>
<th>Grid provided</th>
<td id=\"grid-provided\">"""+grid.givenGridStr+"""</td>
</tr>
</table>
<table style=\"float:left;width: 49%;\">
<tr>
<th>Accumulated demand (kWh)</th>
<td id=\"accumulated-demand\">N/A</td>
</tr>
<tr>
<th>Investment cost (EUR)</th>
<td id=\"investment-cost\">N/A</td>
</tr>
<tr>
<th>Total grid length (m)</th>
<td id=\"total-length\">N/A</td>
</tr>
<tr>
<th>Used segments</th>
<td id=\"used-segments\">N/A</td>
</tr>
<tr>
<th>Grid provided IDs</th>
<td id=\"grid-provided-ids\">"""+givenGridIds+"""</td>
</tr>
</table>
<h2 id=\"calculate-grid-title\" style=\"float:left;\">Calculated Grid</h2>
<button class=\"button2\" id=\"toggle-table\" onclick=\"toggleItem('result-table','toggle-table')\">-</button>
<table id=\"result-table\" border=1 style=\"width: 99%;\">
<tr>
<th> Segment ID </th>
<th> Demand (kWh)</th>
<th> Length (m)</th>
<th> Acc. Demand (kWh)</th>
<th> Acc. Length (m)</th>
<th> Acc. Grid Cost (EUR)</th>
</table>
<h2 id=\"calculate-grid-title\" style=\"float:left;\">Grid Visualization</h2>
<button class=\"button2\" id=\"toggle-vis\" onclick=\"toggleItem('canvas-wrapper','toggle-vis')\">-</button>
<div id=\"canvas-wrapper\" style=\"width: 100%;float: left\">
<button class=\"button2\" style=\"width: 100px; margin-left:0px\" onclick=\"toggleResult()\">Toggle Result</button>
<canvas id=\"grid-canvas\" width=\"1280\" height=\"720\"></canvas>
</div>
</body>
<script>
const c1 = """+str(grid.c1)+""";
const c2 = """+str(grid.c2)+""";
const a = """+str(grid.a)+""";
function readSingleFile(e) {
var file = e.target.files[0];
if (!file) {
return;
}
var reader = new FileReader();
reader.onload = function (e) {
var contents = e.target.result;
console.log(contents)
setFileName(file);
displayTable(JSON.parse(contents));
drawGrid(JSON.parse(contents))
};
reader.readAsText(file);
}
function setFileName(file) {
const element = document.getElementById('file-name');
element.textContent = file;
}
function rescaleX(x, minMax) {
return ((1270 - 10) * (x - minMax[0]) / (minMax[1] - minMax[0])) + 10
}
function rescaleY(x, minMaY) {
return ((10 - 710) * (x - minMaY[0]) / (minMaY[1] - minMaY[0])) + 710
}
const minMaxX = [Number.POSITIVE_INFINITY, 0];
const minMaxY = [Number.POSITIVE_INFINITY, 0];
function drawBaseGrid(grid) {
const canvas = document.getElementById('grid-canvas');
var ctx = canvas.getContext(\"2d\");
ctx.lineWidth = 1;
ctx.strokeStyle = \"black\";
for (var segment in grid) {
const onlyCoords = grid[segment].geometry.substring(12, grid[segment].geometry.length - 1);
const lines = onlyCoords.split(\",\")
for (var i = 0; i < lines.length; i++) {
lines[i] = lines[i].trim();
const xyCoords = lines[i].split(\" \")
// check x
// check minimal
if (xyCoords[0] < minMaxX[0]) {
minMaxX[0] = xyCoords[0]
}
// check maximal
if (xyCoords[0] > minMaxX[1]) {
minMaxX[1] = xyCoords[0]
}
// check y
// check minimal
if (xyCoords[1] < minMaxY[0]) {
minMaxY[0] = xyCoords[1]
}
// check maximal
if (xyCoords[1] > minMaxY[1]) {
minMaxY[1] = xyCoords[1]
}
}
}
for (var segment in grid) {
const onlyCoords = grid[segment].geometry.substring(12, grid[segment].geometry.length - 1);
const lines = onlyCoords.split(\",\")
for (var i = 0; i < lines.length; i++) {
lines[i] = lines[i].trim();
const xyCoords = lines[i].split(\" \")
// console.log(xyCoords)
// if (i === 0)
// ctx.moveTo(xyCoords[0].substring(3), xyCoords[1].substring(3))
// else
// ctx.lineTo(xyCoords[0].substring(3), xyCoords[1].substring(3))
if (i === 0)
ctx.moveTo(rescaleX(xyCoords[0], minMaxX), rescaleY(
xyCoords[1], minMaxY))
else
ctx.lineTo(rescaleX(xyCoords[0], minMaxX), rescaleY(
xyCoords[1], minMaxY))
}
ctx.stroke();
}
}
function drawGrid(grid) {
const canvas = document.getElementById('grid-canvas');
var ctx = canvas.getContext(\"2d\");
for (var segment in grid.segments) {
const onlyCoords = grid.segments[segment].geometry.substring(12, grid.segments[segment].geometry.length - 1);
const lines = onlyCoords.split(\",\")
ctx.beginPath();
ctx.lineWidth = 5;
ctx.strokeStyle = \"red\";
for (var i = 0; i < lines.length; i++) {
lines[i] = lines[i].trim();
const xyCoords = lines[i].split(\" \")
if (i === 0)
ctx.moveTo(rescaleX(xyCoords[0], minMaxX), rescaleY(
xyCoords[1], minMaxY))
else
ctx.lineTo(rescaleX(xyCoords[0], minMaxX), rescaleY(
xyCoords[1], minMaxY))
}
ctx.stroke();
}
}
function toggleItem(item, source) {
const x = document.getElementById(item);
const btn = document.getElementById(source);
if (x.style.visibility === \"collapse\") {
x.style.visibility = \"visible\";
btn.textContent = \"-\";
} else {
x.style.visibility = \"collapse\";
btn.textContent = \"+\";
}
}
function displayTable(grid) {
const table = document.getElementById('result-table');
table.children = null;
//element.texContent = JSON.stringify(result);
const tblBody = document.createElement(\"tbody\");
let accDemand = 0;
let accLength = 0;
// creating all cells
const target = document.getElementById('target-demand');
target.textContent = grid.targetDemand;
const availSegments = document.getElementById('available-segments');
availSegments.textContent = grid.availableSegmentsCount;
const accumulatedDemand = document.getElementById('accumulated-demand');
accumulatedDemand.textContent = grid.accumulatedDemand;
const investmentCost = document.getElementById('investment-cost');
investmentCost.textContent = grid.investmentCost.toFixed(3);
const totalLength = document.getElementById('total-length');
totalLength.textContent = grid.totalLength;
const calcGridTitle = document.getElementById('used-segments');
calcGridTitle.textContent = `${grid.segments.length}`;
for (var segment in grid.segments) {
var row = document.createElement(\"tr\");
const id = document.createElement(\"td\");
let cellText = document.createTextNode(grid.segments[segment].id);
id.appendChild(cellText);
const demand = document.createElement(\"td\");
cellText = document.createTextNode(grid.segments[segment].demand);
demand.appendChild(cellText);
const length = document.createElement(\"td\");
cellText = document.createTextNode(grid.segments[segment].length);
length.appendChild(cellText);
var accDemandCell = document.createElement(\"td\");
cellText = document.createTextNode(accDemand += grid.segments[segment].demand);
accDemandCell.appendChild(cellText);
var accLengthCell = document.createElement(\"td\");
cellText = document.createTextNode((accLength += grid.segments[segment].length).toFixed(3));
accLengthCell.appendChild(cellText);
var accCostCell = document.createElement(\"td\");
cellText = document.createTextNode(
(gridCost(accDemand,accLength)).toFixed(3));
accCostCell.appendChild(cellText);
row.appendChild(id);
row.appendChild(demand);
row.appendChild(length);
row.appendChild(accDemandCell);
row.appendChild(accLengthCell);
row.appendChild(accCostCell);
// add the row to the end of the table body
tblBody.appendChild(row);
}
// put the <tbody> in the <table>
if (table.children[1]) table.children[1].replaceWith(tblBody);
else table.appendChild(tblBody);
}
function gridCost(total_demand_kWh, total_length_m){
const q_s = (total_demand_kWh/(10**6))*3600;
const d_a = 0.0486 * Math.log(q_s / total_length_m) + 0.0007;
grid_investment_cost_EUR = a*(c1 + c2 * d_a) * total_length_m;
return grid_investment_cost_EUR;
}
function init() {
setFileName(\""""+f'{folderName}.json'+"""\");
displayTable(grid);
drawBaseGrid(wholeGrid);
drawGrid(grid)
};
// clear the canvas
var resultVisible = true;
function toggleResult(){
const canvas = document.getElementById('grid-canvas');
var ctx = canvas.getContext(\"2d\");
ctx.clearRect(0,0,canvas.width,canvas.height);
drawBaseGrid(wholeGrid);
if(resultVisible){
resultVisible = false;
}else {
drawGrid(grid);
resultVisible = true;
}
}
const grid = """+jsonResultGrid+""";
const wholeGrid = """+wholeGrid+""";
window.onload = init();
</script>
</html>"""
resultFileHtml.write(resultReport)
resultFileHtml.close()
resultFileJson.write(jsonResultGrid)
resultFileJson.close()
# open results file
# if platform.system() == 'Darwin': # macOS
# subprocess.call(('open', filepathHtml))
# elif platform.system() == 'Windows': # Windows
# os.startfile(folderName+f'/{filepathHtml}')
# else: # linux variants
# subprocess.call(('xdg-open', filepathHtml))
if __name__ == "__main__":
main(sys.argv[1:])
This source diff could not be displayed because it is too large. You can view the blob instead.
<html>
<head>
<title>ENsource Disaggregation Report</title>
<meta charset="UTF-8">
<style>
h1 {
text-align: center;
color: #002C55;
}
h2 {
text-align: left;
font-size: 25px;
font-weight: "bold";
color: #002C55;
}
h1 span {
color: #549925;
}
</style>
</head>
<body>
<h1><span>EN</span>source Disaggregation Report</h1>
<h2 style="float:left; width: 100%;">Run Results</h2>
<!-- TO BE ADDED: HELP? -->
<form action = "http://127.0.0.1:5000/ensource2/" method = "POST" enctype = "multipart/form-data">
<p>Input CSV file:
<input type=file name=file required>
</p>
<input type=submit value=Run>
</form>
<br/>
<p><a href="data/sample.csv">Download a sample of input CSV file</a></p>
<p><small><strong>IMPORTANT:</strong> The header of the CSV input file MUST BE named as the following:
<ul>
<li>ID</li>
<li>GMLId</li>
<li>Stat PrimaryUsageZoneType</li>
<li>Stat Class year of construction</li>
<li>Building Count</li>
<li>Total Yearly Heat+DHW demand</li>
<li>January Heating Demand</li>
<li>February Heating Demand</li>
<li>March Heating Demand</li>
<li>April Heating Demand</li>
<li>May Heating Demand</li>
<li>June Heating Demand</li>
<li>July Heating Demand</li>
<li>August Heating Demand</li>
<li>September Heating Demand</li>
<li>October Heating Demand</li>
<li>November Heating Demand</li>
<li>December Heating Demand</li>
<li>Total Distance</li>
<li>Length</li>
<li>geometry</li>
<li>neighbor</li>
</ul>
</small></p>
</body>
</html>
<html>
<head>
<title>ENsource Disaggregation Report</title>
<meta charset="UTF-8">
<!-- Include the CesiumJS JavaScript and CSS files -->
<script src="https://cesium.com/downloads/cesiumjs/releases/1.78/Build/Cesium/Cesium.js"></script>
<link href="https://cesium.com/downloads/cesiumjs/releases/1.78/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
<!-- Terraformer and WKT Parser -->
<script src="https://unpkg.com/terraformer@1.0.7/terraformer.js"></script>
<script src="https://unpkg.com/terraformer-wkt-parser@1.1.2/terraformer-wkt-parser.js"></script>
<!-- proj4js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.7.2/proj4.min.js" integrity="sha512-dNFx8aqYHHdVRrTfm7fzMSakZd+cD8Bf24ZqvAIh799ORCeyVdzN1w4wiqLtLON7VPkZ1vQmMi+CJRF/b3v/7A==" crossorigin="anonymous"></script>
<style>
h1 {
text-align: center;
color: #002C55;
}
h2 {
text-align: left;
font-size: 25px;
font-weight: "bold";
color: #002C55;
}
h1 span {
color: #549925;
}
table {
border-collapse: collapse;
border: 1px solid #DFDCDC;
border-spacing: 0;
}
th {
background-color: #549925;
color: white;
text-align: left;
padding: 8px;
}
td {
text-align: left;
padding: 8px;
}
tr:nth-child(even) {
background-color: #e7f4d9;
}
table th,
table td {
border-top: 1px #efe9e3;
border-right: 0px #efe9e3;
border-bottom: 0px #efe9e3;
border-left: 1px #efe9e3;
}
.button {
float: left;
padding: 6px 9px;
cursor: pointer;
margin-top: 20px;
margin-left: 15px;
border-radius: 5px;
background-color: #549925;
font-size: 12px;
font-weight: bold;
color: #fff;
width: 30px;
}
.collapsible {
background-color: #549925;
color: #002C55;
cursor: pointer;
padding: 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 25px;
font-weight: bold;
}
.active, .collapsible:hover {
background-color: #BAD6A7;
}
.collapsible:after {
content: '\002B'; /* Unicode character for "plus" sign (+) */
color: #002C55;
font-weight: bold;
float: right;
margin-left: 5px;
}
.active:after {
content: "\2212"; /* Unicode character for "minus" sign (-) */
}
.content {
padding: 0 18px;
display: none;
overflow: hidden;
}
</style>
</head>
<body>
<h1><span>EN</span>source Disaggregation Report</h1>
<h2 style="float:left; width: 100%;">Run Results</h2>
<form action = "http://127.0.0.1:5000//ensource2/" method = "POST" enctype = "multipart/form-data">
<input type=file name=file required>
<input type=submit value=Run>
</form>
<table style="float:left; width: 49%; margin-right: 10;">
<tr>
<th>Target Demand (kWh)</th>
<td id="target-demand">N/A</td>
</tr>
<tr>
<th>Results Files</th>
<td id="file-name"><a id="jsonResult" href=#></a> | <a id="csvResult" href=#></a></td>
</tr>
<tr>
<th>Segments File</th>
<td id="segments-file-name">N/A</td>
</tr>
<tr>
<th>Available Segments</th>
<td id="available-segments">N/A</td>
</tr>
<tr>
<th>Grid provided</th>
<td id="grid-provided">N/A</td>
</tr>
</table>
<table style="float:left;width: 49%;">
<tr>
<th>Accumulated demand (kWh)</th>
<td id="accumulated-demand">N/A</td>
</tr>
<tr>
<th>Investment cost (EUR)</th>
<td id="investment-cost">N/A</td>
</tr>
<tr>
<th>Total grid length (m)</th>
<td id="total-length">N/A</td>
</tr>
<tr>
<th>Used segments</th>
<td id="used-segments">N/A</td>
</tr>
<tr>
<th>Grid provided IDs</th>
<td id="grid-provided-ids">{{ givenGridIds }}</td>
</tr>
</table>
<button type="button" class="collapsible">Calculated Grid</button>
<div class="content">
<table id="result-table" border=1 style="width: 99%;">
<tr>
<th> Segment ID </th>
<th> Demand (kWh)</th>
<th> Length (m)</th>
<th> Acc. Demand (kWh)</th>
<th> Acc. Length (m)</th>
<th> Acc. Grid Cost (EUR)</th>
</table>
</div>
<button type="button" class="collapsible">Grid Visualization</button> <!-- span>+</span -->
<div class="content">
<div id="toolbar" style="position: absolute; padding: 25px; z-index: 1;">
<!-- select id="myColor" onchange="doStyling()">
<option value="1">Show/hide grids</option>
<option value="2">Color grids by segment demand (kWh)</option>
<option value="0">Show/hide buildings</option>
</select -->
</div>
<div id="cesiumContainer"></div>
</div>
<script>
//var myViewer
var myWholeGrid
var myGrid
// collapsible
var coll = document.getElementsByClassName("collapsible")
var i
for (i = 0; i < coll.length; i++) {
coll[i].addEventListener("click", function() {
this.classList.toggle("active")
var content = this.nextElementSibling
if (content.style.display === "block") {
content.style.display = "none"
} else {
content.style.display = "block"
}
})
}
/*
function doStyling() {
let id = document.getElementById("myColor").value
if (id == 0) {
// show/hide buildings
} else if(id == 1) {
// show/hide grids
} else if(id == 2) {
for (var segment in myGrid.segments) {
let linesReprojected = myGrid.segments[segment].geometryReprojected
for (let i = 0; i < (linesReprojected.length-1); i++) {
myViewer.entities.add({
polyline: {
positions: Cesium.Cartesian3.fromDegreesArray([linesReprojected[i][0], linesReprojected[i][1], linesReprojected[i+1][0], linesReprojected[i+1][1]]),
width: 5,
material: Cesium.Color.GREEN,
clampToGround: true,
}
});
}
}
}
} */
function gridCost(total_demand_kWh, total_length_m, a, c1, c2){
const q_s = (total_demand_kWh/(10**6))*3600;
const d_a = 0.0486 * Math.log(q_s / total_length_m) + 0.0007;
grid_investment_cost_EUR = a*(c1 + c2 * d_a) * total_length_m;
return grid_investment_cost_EUR;
}
function displayTable(grid) {
const table = document.getElementById('result-table');
table.children = null;
//element.texContent = JSON.stringify(result);
const tblBody = document.createElement("tbody");
let accDemand = 0;
let accLength = 0;
// creating all cells
const target = document.getElementById('target-demand');
target.textContent = grid.targetDemand;
const segmentsFile = document.getElementById('segments-file-name');
segmentsFile.textContent = grid.segmentsFile;
const availSegments = document.getElementById('available-segments');
availSegments.textContent = grid.availableSegmentsCount;
const gridProvided = document.getElementById('grid-provided');
gridProvided.textContent = grid.givenGridStr;
const accumulatedDemand = document.getElementById('accumulated-demand');
accumulatedDemand.textContent = grid.accumulatedDemand;
const investmentCost = document.getElementById('investment-cost');
investmentCost.textContent = grid.investmentCost.toFixed(3);
const totalLength = document.getElementById('total-length');
totalLength.textContent = grid.totalLength;
const calcGridTitle = document.getElementById('used-segments');
//calcGridTitle.textContent = `${grid.segments.length}`;
calcGridTitle.textContent = grid.segments.length;
for (var segment in grid.segments) {
var row = document.createElement("tr");
const id = document.createElement("td");
let cellText = document.createTextNode(grid.segments[segment].id);
id.appendChild(cellText);
const demand = document.createElement("td");
cellText = document.createTextNode(grid.segments[segment].demand);
demand.appendChild(cellText);
const length = document.createElement("td");
cellText = document.createTextNode(grid.segments[segment].length);
length.appendChild(cellText);
var accDemandCell = document.createElement("td");
cellText = document.createTextNode(accDemand += grid.segments[segment].demand);
accDemandCell.appendChild(cellText);
var accLengthCell = document.createElement("td");
cellText = document.createTextNode((accLength += grid.segments[segment].length).toFixed(3));
accLengthCell.appendChild(cellText);
var accCostCell = document.createElement("td");
cellText = document.createTextNode((gridCost(accDemand,accLength, grid.a, grid.c1, grid.c2)).toFixed(3));
accCostCell.appendChild(cellText);
row.appendChild(id);
row.appendChild(demand);
row.appendChild(length);
row.appendChild(accDemandCell);
row.appendChild(accLengthCell);
row.appendChild(accCostCell);
// add the row to the end of the table body
tblBody.appendChild(row);
}
// put the <tbody> in the <table>
if (table.children[1]) table.children[1].replaceWith(tblBody);
else table.appendChild(tblBody);
}
function drawBaseGrid(viewer, wholeGrid) {
// todo: clear entities
for (var segment in wholeGrid) {
// parse a WKT string, converting it into a Terraformer.Primitive
let geojsonLineString = Terraformer.WKT.parse(wholeGrid[segment].geometry)
let coordinates = []
for (let i = 0; i < (geojsonLineString.coordinates.length); i++) {
let projWebCoordinate = reprojectCoordinate(geojsonLineString.coordinates[i])
coordinates.push(projWebCoordinate)
}
// draw grids based on coordinates
for (let i = 0; i < (coordinates.length-1); i++) {
viewer.entities.add({
id: "BaseGrid"+"_Segment-"+wholeGrid[segment].id+"-"+i,
polyline: {
positions: Cesium.Cartesian3.fromDegreesArray([coordinates[i][0], coordinates[i][1], coordinates[i+1][0], coordinates[i+1][1]]),
width: 2,
material: Cesium.Color.BLACK,
clampToGround: true,
}
})
}
}
}
function drawGrid(viewer, grid) {
for (var segment in grid.segments) {
// parse a WKT string, converting it into a Terraformer.Primitive
let geojsonLineString = Terraformer.WKT.parse(grid.segments[segment].geometry)
let coordinates = []
for (let i = 0; i < (geojsonLineString.coordinates.length); i++) {
let projWebCoordinate = reprojectCoordinate(geojsonLineString.coordinates[i])
coordinates.push(projWebCoordinate)
}
// draw grids based on coordinates
for (let i = 0; i < (coordinates.length-1); i++) {
viewer.entities.add({
id: "Grid"+"_Segment-"+grid.segments[segment].id+"-"+i,
polyline: {
positions: Cesium.Cartesian3.fromDegreesArray([coordinates[i][0], coordinates[i][1], coordinates[i+1][0], coordinates[i+1][1]]),
width: 5,
material: Cesium.Color.RED,
clampToGround: true,
},
});
}
}
}
function reprojectCoordinate(coordinate) {
let firstProj = "+proj=tmerc +lat_0=0 +lon_0=9 +k=1 +x_0=3500000 +y_0=0 +ellps=bessel +datum=potsdam +units=m +no_defs"; // EPSG:31467
let secondProj = "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"; // EPSG:4326
// convert the passed coordinate to geographic coordinate
let geoCoordinate = Terraformer.Tools.positionToGeographic(coordinate)
// converts the passed coordinate to web mercator spatial reference.
let webCoordinate = Terraformer.Tools.positionToMercator(geoCoordinate)
// project coordinate to EPSG 4326
let projWebCoordinate = proj4(firstProj, secondProj, webCoordinate)
return projWebCoordinate
}
function init() {
// set links to the result files
let aJson = document.getElementById('jsonResult')
let resultJsonFilename = {{ resultFileJson | tojson }}
aJson.href = "result/"+resultJsonFilename
aJson.textContent = resultJsonFilename
let aCsv = document.getElementById('csvResult')
let resultCsvFilename = {{ resultFileCsv | tojson }}
aCsv.href = "result/"+resultCsvFilename
aCsv.textContent = resultCsvFilename
// load cesiumjs
Cesium.Ion.defaultAccessToken = 'put-your-cesium-token-here'
let viewer = new Cesium.Viewer("cesiumContainer", {
animation: false,
timeline: false,
terrainProvider: Cesium.createWorldTerrain(),
imageryProvider : new Cesium.OpenStreetMapImageryProvider({
url : 'https://a.tile.openstreetmap.org/'})
});
// Add Cesium OSM buildings to the scene
//viewer.scene.primitives.add(Cesium.createOsmBuildings());
//myViewer = viewer
myWholeGrid = JSON.parse({{ wholeGrid | tojson }})
myGrid = JSON.parse({{ grid | tojson }})
displayTable(myGrid)
drawBaseGrid(viewer, myWholeGrid)
drawGrid(viewer, myGrid)
viewer.zoomTo(viewer.entities)
}
init()
</script>
</body>
</html>
wsgi.py 0 → 100644
from disaggregation import app
if __name__ == '__main__':
app.run(debug=False)
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment