An error occurred while loading the file. Please try again.
disaggregation_lookahead.py 33.10 KiB
"""
@author: Andrés Lalama
"""
from locale import atof, setlocale, LC_NUMERIC
import time
from typing import List
import pandas as pd
import math
import array as arr
import sys
import getopt
import json
import subprocess
import time
import os
import platform
from datetime import datetime
class Segment(object):
    def __init__(self,
                 id: int,
                 neighbors=None,
                 demand=float,
                 length=None,
                 totalDistance=None,
                 isInGrid=False, geometry=None):
        self.id = id
        self.neighbors: List[int] = neighbors
        self.length = length
        self.totalDistance = totalDistance
        self.demand = demand
        self.isInGrid = isInGrid
        self.hasUnusedSegments = True
        self.geometry = geometry
class HeatGrid:
    def __init__(self, id: int, targetDemand: float = None, segments=[]):
        self.id = id
        self.c1 = 368
        self.c2 = 2602.5
        self.a = 0.0725
        # use 'self.targetDemand = targetDemand' in order to use the maximal possible energy demand
        self.targetDemand = targetDemand
        #self.targetDemand = 33518557
        #self.segmentsFile = "ise_files\\stat_lines_with_industry_v2102.csv"
        self.segmentsFile = "ise_files\\Rainau_stat_lines_with_industry.csv"
        self.accumulatedDemand = 0
        self.segments = segments
        self.availableSegments = []
        self.availableSegmentsCount = 0
        self.investmentCost = 0
        self.totalLength = 0
        self.komMod = []
        self.lookAhead = 2
        self.givenGrid = []
    def importFromFile(self) -> bool:
        if self.segmentsFile.endswith(".csv"):
            segmentData = pd.read_csv(self.segmentsFile, sep=";")
        elif self.segmentsFile.endswith(".excel"):
            print("found excel")
            segmentData = pd.read_excel(self.segmentsFile)
        rightArguments = segmentData
        # setting german locale because of excel files
setlocale(LC_NUMERIC, 'German_Germany.1252') for index, row in rightArguments.iterrows(): length = row['Length'] totalDistance = row['Total Distance'] demand = row['Total Yearly Heat+DHW demand'] if isinstance(length, float) is False: length = atof(length) if isinstance(totalDistance, float) is False: totalDistance = atof(totalDistance) else: totalDistance = 0 if isinstance(demand, float) is False: demand = atof(demand) else: # setting demand to 0 if it the cell is empty demand = 0 # converting string to array of int IDs neighborsString = row['neighbor'] neighborsString = neighborsString.replace(' ', '') neighborsString = neighborsString.replace('[', '') neighborsString = neighborsString.replace(']', '') neighbors = [int(s) for s in neighborsString.split(',') if s.isdigit()] geometry = row['geometry'] id = row['ID'] try: segId = int(id) except ValueError: segId = int(id[:-2]) newSegment = Segment(id=segId, neighbors=neighbors, length=length, totalDistance=totalDistance, demand=demand, geometry=geometry) self.availableSegments.append(newSegment) fileNameOnly = "" if "\\" in self.segmentsFile: fileNameOnly = self.segmentsFile.split("\\") elif "/" in self.segmentsFile: fileNameOnly = self.segmentsFile.split("/") self.segmentsFile = fileNameOnly[-1] self.availableSegmentsCount = len(self.availableSegments) print('Available Segments :', self.availableSegmentsCount) self.populateNeighbor() return True def importKomModFromFile(self, path: str) -> bool: if path.endswith(".csv"): segmentData = pd.read_csv(path, sep=";") elif path.endswith(".excel"): print("found excel") segmentData = pd.read_excel(path) # setting german locale because of excel files setlocale(LC_NUMERIC, 'German_Germany.1252') for index, row in segmentData.iterrows(): cost = row['specificGridCost(kWh)'] demand = row['totalDemandMean(kWh)'] grid.komMod.append([cost, demand]) print('KomMod Calculations :', len(grid.komMod)) return True def addSegment(self, segment: Segment) -> bool: """ addSegments adds a segment to the grid :param segment: the segment to be added to the grid :return: true if the segment was added, false if not """
if segment.isInGrid: return False segment.isInGrid = True self.segments.append(segment) self.accumulatedDemand += segment.demand self.totalLength += (segment.length + segment.totalDistance) #print('Added Segment:', segment.id) return True def addSegmentById(self, id: int) -> bool: """ addSegmentById adds a segment to the grid by a given ID This method is used when the user provides an existing grid. :param id: the id of the segment to be added to the grid :return: true if the segment was added, false if not """ for segment in self.availableSegments: if segment.id == int(id): #print(f'YES segment ID: ', segment.id) segment.isInGrid = True self.segments.append(segment) self.accumulatedDemand += segment.demand self.totalLength += (segment.length + segment.totalDistance) # print( # f'Adding segment ID: {segment.id:4} - Accumulated demand: {self.accumulatedDemand:13.3f} - Total Length: {self.totalLength:.2f} - Count: {len(self.segments)}') return True return False def isDemandMet(self) -> bool: """ isDemandMet checks wether the grid already has met the heating demand :return: true if the demand was met, false if not """ return (self.accumulatedDemand >= self.targetDemand or math.isclose(self.accumulatedDemand, self.targetDemand, rel_tol=1e-5)) def calculateGrid(self): """ calculateGrid Runs the algorithm to calculate the grid """ highestDemand = self.findHighestDemandNeighbor() if highestDemand != None: self.addSegment(highestDemand) else: # Looking for unused segments which are not connected to the grid stillAvailableSegments = filter( lambda segment: not segment.isInGrid, self.availableSegments) startNewGrid = max(stillAvailableSegments, key=lambda segment: segment.demand) if startNewGrid != None: self.addSegment(startNewGrid) else: printError() return if self.isDemandMet(): # if met we are finished printResults(self) else: # continue looking for next best segment self.calculateGrid() def calcGridCost(self): """ calcGridCost Runs the algorithm to calculate the grid """ q_s = (self.accumulatedDemand/(10**6))*3600 d_a = 0.0486 * math.log(q_s/self.totalLength) + 0.0007 self.investmentCost = self.a * \ (self.c1 + self.c2 * d_a) * self.totalLength
def populateNeighbor(self): """ populateNeighbor Fills a dictionary with segment objects. The segments are normally delivered as ID strings. Key = Segment Values = List of segments neighboring the key segment """ for segment in self.availableSegments: for neighborId in segment.neighbors: for neighbor in self.availableSegments: if (neighbor.id == neighborId): if segment in segNeighborDic: segNeighborDic[segment].append(neighbor) else: segNeighborDic[segment] = [neighbor] def findHighestDemandNeighbor(self) -> Segment: """ findHighestDemandNeighbor Checks for the neighbor with the highest demand which is not yet part of the grid :return: true if the demand was met, false if not """ # if the grid has no segments # look for a segment with the highest demant # and select it as the starting point if len(self.segments) == 0: highestDemand = max(self.availableSegments, key=lambda segment: segment.demand) return highestDemand score = -1 bestNeighborObject = None allCombinations = [] # iterate through all segments of the grid for gridSegment in self.segments: combinations = findPossibilities( [], gridSegment, self.lookAhead, self) bestValue = getBestNeighbor(combinations) if len(bestValue) > 0: allCombinations.append(bestValue) for comb in allCombinations: # print('all combinations', comb) if comb[1] > score: score = comb[1] bestNeighborObject = comb[0] return bestNeighborObject def findPossibilities(visitedSegments: List[Segment], startingSegment: Segment, lookAhead: int, grid: HeatGrid) -> List[Segment]: #print('lookAhead', lookAhead, startingSegment.id, ) """ findPossibilities Calculates all possible combinations of segments which can be added to the grid starting com a given segment. It takes into account how many neighbors to take into account depending of the lookAhead value. :param visitedSegments: A list of "visited" segments to ignore when looking for further possibilities :param startingSegment: The "root" segment from where to start looking. It is already part of the grid :param lookAhead: is the number of further connected segments to also take into consideration :param grid: The heat grid :return: A list of all possibilities as an List[List[Segment]] """ visited = "" for segment in visitedSegments: visited = visited + str(segment.id) + "," allCombinationsList = [] if not startingSegment.hasUnusedSegments: return allCombinationsList
if lookAhead == 0: allCombinationsList.append([startingSegment]) return allCombinationsList hasNeighbors = filter(lambda segment: not segment.isInGrid, segNeighborDic[startingSegment]) neighborList = list(hasNeighbors) if len(neighborList) == 0: startingSegment.hasUnusedSegments = False # add starting segment to the visited segments newVisitedSegments = [] + visitedSegments newVisitedSegments.append(startingSegment) segmentsNeighbors = filter( lambda segment: not segment in visitedSegments, neighborList) currentNotInGrid = list(segmentsNeighbors) for nextNeighborSeg in currentNotInGrid: combinations = findPossibilities( newVisitedSegments, nextNeighborSeg, lookAhead-1, grid) for combination in combinations: arrayForCombiList = [] for i in range(len(combination)): if i == 0: arrayForCombiList.append(startingSegment) arrayForCombiList.append(combination[i]) allCombinationsList.append(arrayForCombiList) return allCombinationsList def getBestNeighbor(combinations) -> List[any]: """ getBestNeighbor Calculates the best combination out of a combinations list. The method gives each combination a score by diving the sum of all demands by the sum of all lengths (Σ Q_n / Σ L_n ) The combination with the highest score is chosen as the best one. :param tempGridSegments: A list of "visited" segments to ignore when looking for further possibilities :param neighborSeg: The "root" segment from where to start looking. :param grid: The heat grid :return: An array containing the first segment of the best combination and its combination score. """ score = 0 # saves a combination which have the same score as best areBest = [] bestNeighbor: Segment # combinations are List of List of Segments # combinations[0] = combination[0] = [2 ,3 ,4] # combination[1] = [2 ,3, 7] # combination[2] = [2 ,3 ,9] # combinations[1] = combination[0] = [2 ,5 ,4] # combination[1] = [2 ,5 ,8] #print('============') for combination in combinations: segString = "" aggDemand = 0 aggLength = 0 for i in range(len(combination)): if i ==0 : continue seg = combination[i] aggDemand += seg.demand aggLength += seg.length segString += str(seg.id) + ", " if (aggDemand/aggLength) > score: score = (aggDemand/aggLength) areBest = [] areBest.append(combination) elif (aggDemand/aggLength) == score: areBest.append(combination)
#print('Combi: ', segString, 'current Score:', score, ' my value: ',str(aggDemand/aggLength) ) #print('============') # check if there are many combinations with the same best score # if it is only one segment choose that one as best if len(areBest) == 1: bestNeighbor = areBest[0][1] # if there are more than one best segment choose the one with # the shortest length (which should be cheaper to build) elif len(areBest) > 1: for i in range(len(areBest)): if (i == 0): bestNeighbor = areBest[i][1] else: if (areBest[i][1].demand/areBest[i][1].length) > (bestNeighbor.demand/bestNeighbor.length): bestNeighbor = areBest[i][1] # check if a bestNeighbor was found try: bestNeighbor except NameError: return [] else: return [bestNeighbor, score] def serialize(obj): if isinstance(obj, Segment): serial = obj.__dict__ return serial return obj.__dict__ segNeighborDic: dict = {} grid = HeatGrid(1) def gridCost(grid, total_demand_kWh, total_length_m): q_s = (total_demand_kWh/(10**6))*3600 d_a = 0.0486 * math.log(q_s/total_length_m) + 0.0007 gridInvCostEur = grid.a*(grid.c1 + grid.c2 * d_a) * total_length_m return gridInvCostEur # prints all segments of the grid def exportResult(): for segment in grid.segments: print(segment.id) # prints help on how to use the script to the command line def printHelp(): print('') print('| Option | Fullname | Description') print('| ------ | --------- | -------------------------------') print('| -t | target | The target of accumulated demand') print('| -s | segments | The input file containing the street segments') print('| -k | kommod | The KomMod file cotaining a list of grids and cost') print('| -r | rabbitmq | send ') print('| -g | grid | The IDs to set as existing grid, separated by comma') print('') print('example: disaggregation.py -t <target> -i <inputfile> -o <outputfile> -r <rabbitMQServer>') def printError(): print('---->>>> No segment found : STOPPING <<<<-----') print('==================================')
print(' Error Results') print('==================================') print("Could not find any other possible neighbor") print("The target demand could not be matched") def printResults(grid): print('==================================') print(' Results') print('==================================') dem = format(grid.accumulatedDemand, '.2f') print(f'Accumulated demand (kWh) : {dem}') grid.calcGridCost() print(f'Investment cost (EUR) : {round(grid.investmentCost,3)}') print(f'Total grid length (m) : {round(grid.totalLength,3)}') print('-----------------------------------') print(f'Please Open the the result file in the result Report') def main(argv): try: opts, args = getopt.getopt( argv, "ht:s:g:k:o:r:", ["target=", "segments=", "grid=", "kommod=", "outfile=", "rabbitmq=", "gui="]) except getopt.GetoptError: print('Did not recognize all of the user arguments. Use \'-h\' for help.') sys.exit(2) print('==================================') print(' ENsource Disaggregation') print('==================================') grid.givenGridAvailable = False for opt, arg in opts: if opt == '-h': printHelp() sys.exit() elif opt in ("-t", "--target"): target = arg grid.targetDemand = float(target) 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)
if grid.targetDemand is None: grid.targetDemand = maxPossibleDemand print(f'No target demand provided.') print(f'Using max possible demand: {round(maxPossibleDemand,3)}') if grid.targetDemand > maxPossibleDemand: print(f'---------->> ERROR <<-------------') print(f'Target demand : {target}') print(f'Max possible demand : {round(maxPossibleDemand,3)}') print('The target demand is higher than given segments allow') print('==================================') return start = time.time() grid.calculateGrid() end = time.time() print('Runtime: ',end - start ) d = datetime.now() d_formatted = d.strftime('%Y%m%d%H%M%S') # Ensure that single digit days and months are padded with a leading `0` folderName = f'result_{d_formatted}' filepathHtml = f'{folderName}.html' # create folder for files os.mkdir(folderName) # write html file resultFileHtml = open(folderName+f'/{folderName}.html', 'w') wholeGrid = json.dumps(grid.availableSegments, default=serialize, indent=2) # write csv file resultFileCsv = open(folderName+f'/{folderName}.csv', 'w') # 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.write(headers) accDemand = 0 totalGridLength = 0 accCost = 0 for seg in grid.segments: accDemand += seg.demand totalGridLength += (seg.length + seg.totalDistance) accCost = gridCost(grid, accDemand, totalGridLength) specCost = accCost / accDemand resultFileCsv.write("\n") resultFileCsv.write( f'{seg.id};{seg.demand};{seg.length};{seg.totalDistance};{accDemand};{totalGridLength};{accCost};{specCost}') resultFileCsv.close() # write json file # delete attributes to avoid cycles in the data delattr(grid, 'availableSegments') delattr(grid, 'komMod') jsonResultGrid = json.dumps(grid, default=serialize, indent=2) resultFileJson = open(folderName+f'/{folderName}.json', 'w') resultReport = """<html> <head> <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; } 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; } 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:])