def plot_zone_constructions(con_file, geo_file, ax=None): """Plot all zone constructions.""" zone_geometry = get.geometry(geo_file) con = get.constructions(con_file, geo_file) layer_therm_props = con["layer_therm_props"] for i, _ in enumerate(zone_geometry["edges"]): con_data = layer_therm_props[i] surface = zone_geometry["edges"][i] # map vertex indices in edges list to x,y,z vertices vertices_surf_i = [] for vertex in surface: vertices_surf_i.append(zone_geometry["vertices"][vertex - 1]) plot_construction(con_data, vertices_surf_i, ax=ax)
def plot_zone(geo_file, ax=None, show_roof=True): """Plot zone from surfaces Example: fig = plt.figure() ax = fig.gca(projection='3d') ax.set_aspect('equal') plot.plot_zone(geo_file, ax=ax) plot.set_axes_equal(ax) plt.show() """ geo = get.geometry(geo_file) vertices = geo["vertices"] edges = geo["edges"] for i, surface in enumerate(edges): # Translate vertex no. to vertex x,y,z pos. vs = [] for vertex in surface: vs.append(vertices[vertex - 1]) # Plot surface from vertex coordinates) if ( geo["props"][i][1] == "CEIL" or geo["props"][i][1] == "SLOP" ) and not show_roof: print("not showing roof") else: if geo["props"][i][6] == "OPAQUE" and geo["props"][i][7] == "EXTERIOR": if "DOOR" in geo["props"][i][3] or "FRAME" in geo["props"][i][3]: plot_zone_surface(vs, ax=ax, facecolour="#c19a6b", alpha=None) else: # default grey surface plot_zone_surface(vs, ax=ax, facecolour="#afacac", alpha=None) elif geo["props"][i][6] == "OPAQUE" and geo["props"][i][7] == "ANOTHER": if "DOOR" in geo["props"][i][3]: # door plot_zone_surface(vs, ax=ax, facecolour="#f5f2d0", alpha=None) else: # default 25% lighter surface plot_zone_surface(vs, ax=ax, facecolour="#ffffff", alpha=None) elif geo["props"][i][6] == "OPAQUE" and geo["props"][i][7] == "SIMILAR": # opaque, similar plot_zone_surface(vs, ax=ax, facecolour="#d8e4bc", alpha=None) elif geo["props"][i][6] == "OPAQUE" and geo["props"][i][7] == "GROUND": plot_zone_surface(vs, ax=ax, facecolour="#654321", alpha=None) else: # Transparent surfaces plot_zone_surface(vs, ax=ax, facecolour="#008db0")
def zone_to_predef_entity(geo_file, name, desc, category): """Convert a zone geometry file to a predefined entity entry. Args: geo_file: ESP-r geometry file. Returns: A text file that can be copied into an ESP-r predefined entities database. """ # TODO(j.allison): Process visual entities # TODO(j.allison): Shift x,y,z to (0,0,0) origin geo = get.geometry(geo_file) all_vertices = geo["vertices"] props = geo["props"] surfaces = geo["edges"] vx = [v[0] for v in all_vertices] vy = [v[1] for v in all_vertices] vz = [v[2] for v in all_vertices] size = (max(vx) - min(vx), max(vy) - min(vy), max(vz) - min(vz)) out_file = f"{name}.txt" with open(out_file, "w+") as the_file: the_file.write(f"*item,{name},{desc} # tag name menu entry\n") the_file.write(f"*incat,{category} \n") the_file.write("*sourced,Custom built.\n") the_file.write("*origin,0.0,0.0,0.0 # local origin\n") the_file.write( f"*bounding_box, {size[0]:.3f} {size[1]:.3f} {size[2]:.3f} # extents of object\n" ) the_file.write("*Text\n") the_file.write(f"{desc}\n") the_file.write("*End_text\n") the_file.write("#\n") for i, vertex in enumerate(all_vertices): the_file.write( f"*vertex,{vertex[0]:.5f},{vertex[1]:.5f},{vertex[2]:.5f} # {i + 1}\n" ) the_file.write("#\n") for i, (s, p) in enumerate(zip(surfaces, props)): the_file.write(f"*mass,{p[0]},{p[5]},OPAQUE,{len(s)}," + " ".join(map(str, s)) + f" # {i + 1}\n") the_file.write("#\n") # the_file.write(f"*vobject,{name},{desc},{len(self.vis)},{','.join([v[8] for v in self.vis])}") the_file.write("*end_item")
def plot_building_component(geo_file, con_file, idx_surface, ax=None, show_roof=True): """Plot generic 3D building component. This function plots a 3D building component (wall, floor, roof etc.) from its surface geometry and construction data. The inside surface is plotted as white, while the external surface colour is dependent on the surface properties from the geometry file. vertices list of x,y,z position vertices of the inside (zone-facing) surface """ # TODO(j.allison): Create new figure and axes if none are provided # Read geometry file zone_geometry = get.geometry(geo_file) surface_props = zone_geometry["props"][idx_surface] # Get vertex numbers that comprise surface surface_edges = zone_geometry["edges"][idx_surface] # Get vertex positions that comprise surface vertices_surf = get.pos_from_vert_num_list(zone_geometry["vertices"], surface_edges) # Plot inside (zone-facing) surface if (surface_props[1] == "CEIL" or surface_props[1] == "SLOP") and not show_roof: pass else: if surface_props[6] == "OPAQUE": plot_zone_surface(vertices_surf, ax=ax, facecolour="w", alpha=None) else: plot_zone_surface(vertices_surf, ax=ax, facecolour="#008db0") # Plot construction layers con = get.constructions(con_file, geo_file) layer_therm_props = con["layer_therm_props"] con_data = layer_therm_props[idx_surface] if (surface_props[1] == "CEIL" or surface_props[1] == "SLOP") and not show_roof: pass else: plot_construction(con_data, vertices_surf, ax=ax) # ------------------------------------- # Plot outer surface # ------------------------------------- normal = get.calculate_normal(vertices_surf) # vertices_surf += [vertices_surf[0]] total_thickness = sum([x[3] for x in con_data]) # Extend vertex position along surface normal by the total thickness x_pos = [v[0] + total_thickness * normal[0] for v in vertices_surf] y_pos = [v[1] + total_thickness * normal[1] for v in vertices_surf] z_pos = [v[2] + total_thickness * normal[2] for v in vertices_surf] # Restructure to surface vertices # Can probably do this in a zip list comprehension... vertices_surf_outer = [] for i, _ in enumerate(vertices_surf): vertices_surf_outer.append([x_pos[i], y_pos[i], z_pos[i]]) if (surface_props[1] == "CEIL" or surface_props[1] == "SLOP") and not show_roof: pass else: if surface_props[6] == "OPAQUE" and surface_props[7] == "EXTERIOR": if "DOOR" in surface_props[3] or "FRAME" in surface_props[3]: # door or frame plot_zone_surface( vertices_surf_outer, ax=ax, facecolour="#c19a6b", alpha=None ) else: # default grey surface plot_zone_surface( vertices_surf_outer, ax=ax, facecolour="#afacac", alpha=None ) elif surface_props[6] == "OPAQUE" and surface_props[7] == "ANOTHER": if "DOOR" in surface_props[3]: # door plot_zone_surface( vertices_surf_outer, ax=ax, facecolour="#f5f2d0", alpha=None ) else: # default 25% lighter surface plot_zone_surface( vertices_surf_outer, ax=ax, facecolour="#ffffff", alpha=None ) elif surface_props[6] == "OPAQUE" and surface_props[7] == "SIMILAR": plot_zone_surface( vertices_surf_outer, ax=ax, facecolour="#d8e4bc", alpha=None ) elif surface_props[6] == "OPAQUE" and surface_props[7] == "GROUND": plot_zone_surface( vertices_surf_outer, ax=ax, facecolour="#654321", alpha=None ) else: # Transparent surfaces plot_zone_surface(vertices_surf_outer, ax=ax, facecolour="#008db0")
def time_series(cfg_file, res_file, param_list, out_file=None, time_fmt=None): """Extract results from results database to CSV. Args: cfg_file: ESP-r configuration file. res_file: ESP-r results database. param_list: List of parameters to extract. Examples - param_list = [['all', 'Zone db T']] param_list = [['id:reception', 'Zone db T']] param_list = [[['id:roof_space', 'id:reception'], 'Zone db T']] param_list = [[['a', 'b'], 'Zone db T'], [['id:reception', 'b'], 'Wind direction']] out_file (optional): Name of exported CSV file. time_fmt: Format of DateTime in exported CSV. Julian or DateTime Returns: res: Console feedback from res. """ res_dict = { # Climate "Ambient temperature": ["a", "a"], "Solar Dir N": ["a", "b"], "Solar diffuse": ["a", "c"], "Wind speed": ["a", "d"], "Wind direction": ["a", "e"], "Ambient RH": ["a", "f"], "Sky illuminance": ["a", "g"], # Temperatures "Zone db T": ["b", "a", "-"], "Zone db T - ambient db T": ["b", "b", "-"], "Zone db T - other zone db T": ["b", "c", "-"], "Zone control point T": ["b", "d", "-"], "Zone Resultant T": ["b", "e", "-"], "Mean Radiant T (area wtd)": ["b", "f", "-"], "Mean Radiant T (at sensor)": ["b", "g", "-"], "Dew point T": ["b", "h", "-"], "Surf inside face T": ["b", "i", "-"], "Surf T - dewpoint T": ["b", "j", "-"], "Surf outside face T": ["b", "k", "-"], "Surf node T": ["b", "l", "-"], # Comfort metrics # <TBC> requires extra inputs from user # 'Predicted Mean Vote (PMV)': ['c', 'a'], # 'PMV using SET': ['c', 'b'], # 'Percentage Dissatisfied (PPD)': ['c', 'c'], # 'Local delta T head-foot': ['c', 'd'], # 'Dissatisfied due to floor T': ['c', 'e'], # 'Diss. warm/ cool ceiling': ['c', 'f'], # 'Diss. wall rad T assymetry': ['c', 'g'], # 'Dissatisfied due to draught': ['c', 'h'], # Solar processes "Solar entering from outside": ["d", "a"], "Solar entering from adj": ["d", "b"], "Solar absorbed in zone": ["d", "c"], # Zone flux "Infiltration (from outside)": ["f", "a"], "Ventilation (adj zones)": ["f", "b"], "Occupant casual gains (R+C)": ["f", "c"], "Lighting casual gains (R+C)": ["f", "d"], "Small power casual gains (R+C)": ["f", "e"], "Other casual gains (R+C)": ["f", "f"], "Controlled casual gains (R+C": ["f", "g"], "Opaq surf conv @extrn": ["f", "h"], "Opaq surf conv @partns": ["f", "i"], "Tran surf conv @extrn": ["f", "j"], "Tran surf conv @partns": ["f", "k"], "Total surface conv": ["f", "l"], # Surface flux "conduction (inside)": ["g", "a", "-", "N"], "convection (inside)": ["g", "b", "-", "N"], # Heat/cool/humidify "Sensible heating load": ["h", "a"], "Sensible cooling load": ["h", "b"], "Dehumidification load": ["h", "c"], "Humidification load": ["h", "d"], "Sensible H+C loads": ["h", "e"], "Latent H+C loads": ["h", "f"], "All Sensible + latent load": ["h", "g"], "Aggregate heating load": ["h", "h"], "Aggregate cooling load": ["h", "i"], "Aggregate dehumidification": ["h", "j"], "Aggregate humidification": ["h", "k"], # Zone RH "Zone RH": ["i"], # Casual gains (more to complete) "occupant convective": ["j", "f", "-"], "lighting convective": ["j", "j", "-"], "equipment convective": ["j", "n", "-"], } # Read cfg file for list of zones cfg = get.config(cfg_file) zones = cfg["zones"] # Loop through each zone file and get zone name zone_names = [] for ind, _ in enumerate(zones): file_path = zones[ind][1]["geo"] zone_names.append(get.geometry(file_path)["name"]) # TODO(j.allison): Check/validate time_fmt res_open = ["", "c"] time_dict = {"Julian": ["*", "a"], "DateTime": ["*", "a", "*", "a"]} if time_fmt is not None: csv_open = [">", "temp.csv", "desc"] + time_dict[time_fmt] + ["&", "^", "e"] else: csv_open = [">", "temp.csv", "desc"] + ["&", "^", "e"] perf_met = ["g"] res_select = [] for item in param_list: zone_select = [] zone_input = item[0] metric_input = item[1] # --------------------------------- # Select all zones # --------------------------------- if zone_input == "all": # res_select.append(["4", "*", "-"]) res_select.append(["4", "*"]) # --------------------------------- # Multiple zone selections # --------------------------------- elif isinstance(zone_input, list) and len(zone_input) > 1: for j in zone_input: # Selection by id: if j[:3] == "id:": selected_zone = j[3:] chr_zone = [ chr(96 + ind + 1) for ind, x in enumerate(zone_names) if x == selected_zone ] # If exists select it, otherwise throw error if chr_zone: zone_select.append(chr_zone[0]) else: print( "zone selection error, '{}' not found".format(selected_zone) ) # Assume direct letter selection of zones if len = 1 elif len(j) == 1: zone_select.append(j[0]) else: print("zone selection error for '{}', check input format".format(j)) res_select.append(["4"] + zone_select + ["-"]) # --------------------------------- # Single selection # --------------------------------- # From zone name elif zone_input[:3] == "id:": selected_zone = zone_input[3:] chr_zone = [ chr(96 + ind + 1) for ind, x in enumerate(zone_names) if x == selected_zone ] # If exists select it, otherwise throw error if chr_zone: zone_select.append(chr_zone[0]) res_select.append(["4"] + zone_select + ["-"]) else: print("zone selection error, '{}' not found".format(selected_zone)) # Assume single letter selection elif len(zone_input) == 1: zone_select.append(zone_input[0]) res_select.append(["4"] + zone_select + ["-"]) else: print( "zone selection error for '{}', check input format".format(zone_input) ) # Select metric # If error in single selection, gets all zones (for now) res_select.append(res_dict[metric_input]) # Surface flux if res_dict[metric_input][0] == "g": surface_input = item[2] res_select.append(surface_input + ["-"]) # Flatten list res_select = list(itertools.chain.from_iterable(res_select)) csv_close = ["!", ">"] res_close = ["-", "-", "-", "-"] cmd = res_open + csv_open + perf_met + res_select + csv_close + res_close cmd = "\n".join(cmd) # print(cmd) res = run( ["res", "-file", res_file, "-mode", "script"], input=cmd, stdout=PIPE, stderr=PIPE, encoding="ascii", ) header_lines = 4 if out_file: with open("temp.csv", "r") as infile, open( out_file, "w", newline="" ) as outfile: reader = csv.reader(infile) writer = csv.writer(outfile) line_count = 1 for row in reader: if line_count < header_lines: pass elif line_count == header_lines: newrow = ["Time"] + row[1:] writer.writerow(newrow) else: newrow = row writer.writerow(newrow) line_count += 1 data_frame = pandas.read_csv( "temp.csv", sep=",", header=3, index_col=0, parse_dates=True ) os.remove("temp.csv") return data_frame