Skip to content

Commit

Permalink
This is a merge action from the ForDevelopment Branch to the main one…
Browse files Browse the repository at this point in the history
…. the merge is done in a hard way.

lots of improvement and robustness done from the former main branch. some improvement could still be made on the geometry and cleaning side to make it faster for cleanner geometries and more in depth for rough ones. It will be handles in the future. Improvement goes along improvements on geomeppy ForMUBES branch !
  • Loading branch information
xavfa committed May 11, 2022
1 parent d3a3a8b commit c695cec
Show file tree
Hide file tree
Showing 17 changed files with 979 additions and 463 deletions.
285 changes: 193 additions & 92 deletions BuildObject/BuildingObject.py

Large diffs are not rendered by default.

299 changes: 265 additions & 34 deletions BuildObject/GeomUtilities.py

Large diffs are not rendered by default.

14 changes: 11 additions & 3 deletions CoreFiles/CaseBuilder_OAT.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ def LaunchProcess(SimDir,FirstRun,TotNbRun,currentRun,keyPath,nbcase,CorePerim,F
if not DataBaseInput:
# Buildingobjects from reading the geojson file as input for further functions if not given as arguments
DataBaseInput = GrlFct.ReadGeoJsonFile(keyPath)
Buildingsfile = DataBaseInput['Build']
epluspath = keyPath['epluspath']
os.chdir(SimDir)
start = time.time()
Expand Down Expand Up @@ -114,7 +113,15 @@ def LaunchProcess(SimDir,FirstRun,TotNbRun,currentRun,keyPath,nbcase,CorePerim,F
str(round(time.time()-startIniti,2))+' sec\n', LogFile)
# The simulation parameters are assigned here
if not MakePlotOnly:
GrlFct.setSimLevel(idf, building)
try: GrlFct.setSimLevel(idf, building)
except:
msg = '[Error] The SimLevel has failed...\n'
if Verbose: print(msg[:-1])
os.chdir(MainPath)
if FirstRun:
GrlFct.Write2LogFile(msg, LogFile)
GrlFct.Write2LogFile('##############################################################\n', LogFile)

# The geometry is assigned here
try:
if DebugMode: startIniti = time.time()
Expand Down Expand Up @@ -158,7 +165,7 @@ def LaunchProcess(SimDir,FirstRun,TotNbRun,currentRun,keyPath,nbcase,CorePerim,F

if DebugMode: startIniti = time.time()
if not MakePlotOnly: #in order to make parametric simulation, lets go along the VarName2Change list and change the building object attributes accordingly
GrlFct.setChangedParam(building, ParamVal, VarName2Change, MainPath, Buildingsfile, nbcase)
GrlFct.setChangedParam(building, ParamVal, VarName2Change, MainPath, DataBaseInput, nbcase)

# lets assign the material and finalize the envelope definition
try:
Expand All @@ -179,6 +186,7 @@ def LaunchProcess(SimDir,FirstRun,TotNbRun,currentRun,keyPath,nbcase,CorePerim,F
str(round(time.time() - startIniti, 2)) + ' sec\n', LogFile)

if MakePlotOnly:
idf.idfname += ' / ' +building.BuildID['BldIDKey']+' : '+ str(building.BuildID[building.BuildID['BldIDKey']])
return building,idf, 'OK'

# lets define the zone level now
Expand Down
8 changes: 6 additions & 2 deletions CoreFiles/DefaultConfig.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
PATH_TO_RESULTS : ../../MUBES_SimResults/ #[Str] this is the main folder where the results will be stored. it will be created if not exists

1_DATA :
PATH_TO_DATA : '../ModelerFolder/Minneberg_Buildings_v1.geojson' #[Str] Input file or folder in case of several files
PATH_TO_DATA : ../ModelerFolder/Minneberg_Buildings_v1.geojson #[Str] Input file or folder in case of several files
EPSG_REF : None #[int], is 4326 for US East coast, 3950 for EU, some other for elsewhere, leave None if no conversion is wanted

2_CASE :
0_GrlChoices :
Expand All @@ -20,7 +21,7 @@
DebugMode : False #[Bool] The log file will be feeded by detailed information along the process
1_SimChoices :
ZoneOfInterest : '' #[Str] BldID can be given from an external file if generated by a third program.
BldID : [] #[List of Str] list of Building's ID if defined as attribute in the geojson file, index of the building in the geojson file otherwise
BldID : [] #[List of Str or int] list of Building's ID if defined as attribute in the geojson file, index of the building in the geojson file otherwise
DESO : [] #[List of Str] not currently used
VarName2Change : [] #[List of Str] parameters to be changed for parametric simulations
Bounds : [] #[List of list of 2 floats] bounds between the parameter are to be changed [Lower Bound,Upper Bounds] a pair of value is to be given for each parameter in VarName2Change
Expand All @@ -42,6 +43,7 @@
PassBldObject : True #[Bool] key word for reading only once the geojson file. but no launch through consol then for each bld
RefBuildNum : None #[Int] building number (order of the GeoJson file) taken as a reference to pick other within the RefPerimeter distance. useful for large DataSets if None it will be ignored
RefPerimeter : 500 #[int] Distance threshold for which all building farer then this threshold for the RefBuildNum are ignored
MakePolygonPlots : False #[Bool] Distance threshold for which all building farer then this threshold for the RefBuildNum are ignored
3_SIM :
#files are needed to be located in the eather folder of EnergyPlus asthe same path is used afterward to launch the simulation
1_WeatherData :
Expand Down Expand Up @@ -192,6 +194,8 @@
VertexKey : 'geometries' #[str] key for the attribute of the coordinates given in the geojson file only
MaxShadingDist : 200 #[Float] Maximum distance allowed to consider shadowing walls
DistanceTolerance : 0.2 #[Float] Geometric threshold from which below every edge are removed and vertexes merged
AltitudeTolerance : 3 #[float] Threshold below wich altitude will be merged. it should be the heigh of a storey
VertexPrecision : 5 #[int] precision of the round function for vertex coordinates


# definition of person/m2...complytely abritrary, but we still need some vaalues
Expand Down
6 changes: 5 additions & 1 deletion CoreFiles/DefaultConfigKeyUnit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

1_DATA :
PATH_TO_DATA : [str] #Input file or folder in case of several files
EPSG_REF : [int,str] #[int or 'None'], is 4326 for US East coast, 3950 for EU, some other for elsewhere

2_CASE:
0_GrlChoices :
Expand All @@ -20,7 +21,7 @@
DebugMode : [bool] #[Bool] The log file will be feeded by detailed information along the process
1_SimChoices:
ZoneOfInterest : [str] #[Str] BldID can be given from an external file if generated by a third program.
BldID : [str] #[List of Str] list of Building's ID if defined as attribute in the geojson file, index of the building in the geojson file otherwise
BldID : [int,str] #[List of Str] list of Building's ID if defined as attribute in the geojson file, index of the building in the geojson file otherwise
DESO : [str] #[Str] not currently used
VarName2Change : [str] #[List of Str] parameters to be changed for parametric simulations
Bounds : [float,int] #[List of list of 2 floats] bounds between the parameter are to be changed [Lower Bound,Upper Bounds] a pair of value is to be given for each parameter in VarName2Change
Expand All @@ -42,6 +43,7 @@
PassBldObject: [bool] #[Bool] key word for reading only once the geojson file. but no launch through consol then for each bld
RefBuildNum: [int,str] #[Int] building number (order of the GeoJson file) taken as a reference to pick other within the RefPerimeter distance. useful for large DataSets
RefPerimeter: [int] #[int] Distance threshold for which all building farer then this threshold for the RefBuildNum are ignored
MakePolygonPlots : [bool] #[Bool] Distance threshold for which all building farer then this threshold for the RefBuildNum are ignored
3_SIM :
#files are needed to be located in the eather folder of EnergyPlus asthe same path is used afterward to launch the simulation
1_WeatherData :
Expand Down Expand Up @@ -190,6 +192,8 @@
VertexKey : [str] #[str] key for the attribute of the coordinates given in the geojson file only
MaxShadingDist : [float,int] #[Float] Maximum distance allowed to consider shadowing walls
DistanceTolerance : [float,int] #[Float] Geometric threshold from which below every edge are removed and vertexes merged
VertexPrecision : [int] #[int] precision of the round function for vertex coordinates
AltitudeTolerance : [float,int] #[float] Threshold below wich altitude will be merged


# definition of person/m2...complytely abritrary, but we still need some vaalues
Expand Down
94 changes: 65 additions & 29 deletions CoreFiles/GeneralFunctions.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@
import CoreFiles.DomesticHotWater as DomesticHotWater
import CoreFiles.MUBES_pygeoj as MUBES_pygeoj
import CoreFiles.BuildFMUs as BuildFMUs
import ReadResults.Utilities as Utilities
from openpyxl import load_workbook
import openturns as ot
import shutil
import pickle
import pyproj
import numpy as np
import json

def appendBuildCase(StudiedCase,keypath,nbcase,DataBaseInput,MainPath,LogFile,PlotOnly = False, DebugMode = False):
StudiedCase.addBuilding('Building'+str(nbcase),DataBaseInput,nbcase,MainPath,keypath,LogFile,PlotOnly, DebugMode)
Expand Down Expand Up @@ -68,21 +70,47 @@ def readPathfile(Pathways):
keyPath[key] = os.path.normcase(line[line.find(':') + 1:-1])
return keyPath

def ReadGeoJsonFile(keyPath,toBuildPool = False):
def ReadGeoJsonFile(keyPath,CoordSys = '',toBuildPool = False):
#print('Reading Input files,...')
try:
BuildObjectDict = ReadGeojsonKeyNames(keyPath['GeojsonProperties'])
Buildingsfile = MUBES_pygeoj.load(keyPath['Buildingsfile'])
#Shadingsfile = MUBES_pygeoj.load(keyPath['Shadingsfile'])
if not toBuildPool: Buildingsfile = checkRefCoordinates(Buildingsfile)
if not toBuildPool: Buildingsfile = checkRefCoordinates(Buildingsfile,CoordSys)
Shadingsfile = getShadowingFile(keyPath['Buildingsfile'],CoordSys)
#if not toBuildPool: Shadingsfile = checkRefCoordinates(Shadingsfile)
return {'BuildObjDict':BuildObjectDict,'Build' :Buildingsfile}#, 'Shades': Shadingsfile}
return {'BuildObjDict':BuildObjectDict,'Build' :Buildingsfile, 'Shades': Shadingsfile}
except:
Buildingsfile = MUBES_pygeoj.load(keyPath['Buildingsfile'])
#Shadingsfile = MUBES_pygeoj.load(keyPath['Shadingsfile'])
if not toBuildPool: Buildingsfile = checkRefCoordinates(Buildingsfile)
if not toBuildPool: Buildingsfile = checkRefCoordinates(Buildingsfile,CoordSys)
Shadingsfile = getShadowingFile(keyPath['Buildingsfile'],CoordSys)
#if not toBuildPool: Shadingsfile = checkRefCoordinates(Shadingsfile)
return {'Build': Buildingsfile}#, 'Shades': Shadingsfile}
return {'Build': Buildingsfile, 'Shades': Shadingsfile}

def getShadowingFile(BuildingFilePath,CoordSys):
Shadingsfile = []
JSONFile = []
GeJsonFile = []
BuildingFileName = os.path.basename(BuildingFilePath)
JSonTest = os.path.join(os.path.dirname(BuildingFilePath),
BuildingFileName[:BuildingFileName.index('.')] + '_Walls.json')
GeoJsonTest = os.path.join(os.path.dirname(BuildingFilePath), BuildingFileName.replace('Buildings', 'Walls'))
GeoJsonTest1 = True if 'Walls' in GeoJsonTest else False
if os.path.isfile(JSonTest):
JSONFile = JSonTest
elif os.path.isfile(GeoJsonTest) and GeoJsonTest1:
GeJsonFile = GeoJsonTest
else:
msg = '[Prep. Info] No shadowing wall file found'
if JSONFile:
msg = '[Prep. Info] json shadowing walls file found'
with open(JSONFile) as json_file:
Shadingsfile = json.load(json_file)
if GeJsonFile:
msg = '[Prep. Info] Geojson shadowing walls file found'
Shadingsfile = MUBES_pygeoj.load(GeJsonFile)
Shadingsfile = checkRefCoordinates(Shadingsfile,CoordSys)
print(msg)
return Shadingsfile

def ListAvailableFiles(keyPath):
# reading the pathfiles and the geojsonfile
Expand Down Expand Up @@ -112,30 +140,42 @@ def ReadGeoJsonDir(keyPath):
BuildingFiles.append(file)
return BuildingFiles

def checkRefCoordinates(GeojsonFile):
def checkRefCoordinates(GeojsonFile,CoordSys):
if not GeojsonFile:
return GeojsonFile
if 'EPSG' in GeojsonFile.crs['properties']['name']:
return GeojsonFile
##The coordinate system depends on the input file, thus, if specific filter or conversion from one to another,
# it should be done here
if "CRS84" in GeojsonFile.crs['properties']['name']:
print('Projecting coordinates of Input file,...')
transformer = pyproj.Transformer.from_crs("CRS84", "epsg:3950") #this transformation if done for the France's reference
for idx,obj in enumerate(GeojsonFile):
newCoord = []
for poly in obj.geometry.coordinates:
newpoly = []
for vertex in poly:
newpoly.append(list(transformer.transform(vertex[0], vertex[1])))
newCoord.append(newpoly)
obj.geometry.coordinates = newCoord
return GeojsonFile
# if 'EPSG' in GeojsonFile.crs['properties']['name']:
# return GeojsonFile
# ##The coordinate system depends on the input file, thus, if specific filter or conversion from one to another,
# # it should be done here
if type(CoordSys)==int:
GeojsonFile = MakeCoordConversion(GeojsonFile, CoordSys)
#GeojsonFile = MakeCoordConversion(GeojsonFile, CoordSys)
return GeojsonFile

def MakeCoordConversion(GeojsonFile,CoordSys):
print('Projecting coordinates of Input file,...')
transformer = pyproj.Transformer.from_crs("CRS84", "epsg:" + str(
CoordSys)) # this transformation if done for the France's reference
for idx, obj in enumerate(GeojsonFile):
newCoord = []
for poly in obj.geometry.coordinates:
newpoly = []
for vertex in poly:
newvertex = list(transformer.transform(vertex[0], vertex[1]))
newpoly.append(
newvertex) # the reversed list and this signe were added after looking at google map and the plot for boston city
newCoord.append(newpoly)
obj.geometry.coordinates = newCoord
obj.geometry.update_centroid()
return GeojsonFile


def ComputeDistance(v1,v2):
return ((v2[0]-v1[0])**2+(v2[1]-v1[1])**2)**0.5

def MakePolygonPlots(CaseChoices,Pool2Launch):
Utilities.makePolyPlots(CaseChoices,Pool2Launch)

def MakeAbsoluteCoord(building,idf = [],roundfactor = 8):
# we need to convert change the reference coordinate because precision is needed for boundary conditions definition:
newfoot = []
Expand Down Expand Up @@ -388,7 +428,7 @@ def AppendLogFiles(MainPath,BldIDKey):
os.remove(os.path.join(MainPath, file2del))

#def setChangedParam(building,ParamVal,VarName2Change,MainPath,Buildingsfile,Shadingsfile,nbcase,LogFile=[]):
def setChangedParam(building, ParamVal, VarName2Change, MainPath, Buildingsfile, nbcase, LogFile=[]):
def setChangedParam(building, ParamVal, VarName2Change, MainPath, DataBaseInput, nbcase, LogFile=[]):
#there is a loop file along the variable name to change and if specific ation are required it should be define here
# if the variable to change are embedded into several layer of dictionnaries than there is a need to make checks and change accordingly to the correct element
# here are examples for InternalMass impact using 'InternalMass' keyword in the VarName2Change list to play with the 'WeightperZoneArea' parameter
Expand Down Expand Up @@ -417,8 +457,6 @@ def setChangedParam(building, ParamVal, VarName2Change, MainPath, Buildingsfile,
setattr(building, var, exttmass)
elif 'MaxShadingDist' in var:
building.MaxShadingDist = round(ParamVal[varnum], roundVal)
#building.shades = building.getshade(Buildingsfile[nbcase], Shadingsfile, Buildingsfile,LogFile,PlotOnly = False)
building.shades = building.getshade(nbcase, Buildingsfile, LogFile,PlotOnly=False)
elif 'IntLoadCurveShape' in var:
building.IntLoadCurveShape = max(round(ParamVal[varnum], roundVal),1e-6)
building.IntLoad = building.getIntLoad(MainPath, LogFile)
Expand Down Expand Up @@ -545,8 +583,6 @@ def ManageGlobalPlots(BldObj,IdfObj,FigCenter,WindSize, PlotBldOnly,nbcase = [],
adiabsurf.append(s.Name[:s.Name.index('_')])
nbadiab += 1
RoofSpecialColor = "firebrick"
if nbcase in [39]:
RoofSpecialColor = 'limegreen'
IdfObj.view_model(test= True if PlotBldOnly+LastBld>0 else False, FigCenter=FigCentroid, WindSize=2 * WindSize,
RoofSpecialColor=RoofSpecialColor)
return FigCenter,WindSize
Expand Down
Loading

0 comments on commit c695cec

Please sign in to comment.