2565 lines
117 KiB
Python
2565 lines
117 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
Created on Tue May 19 16:33:00 2020
|
|
@author: Rebecca
|
|
|
|
This is a Master_v5_3.py script based on SVN rev 897.
|
|
Changes from SVN rev 897:
|
|
-I have removed the module matplotlib
|
|
-I changed the double backslash \\ that denotes directories in Windows with the single forward slash / used in Linux.
|
|
-I removed the math.remainder and replaced it with the modulus operator (%) since it wasn't introduced until Python3.7'
|
|
|
|
by: Rebecca PINTO
|
|
2020-01-15"""
|
|
# %% Import Packages
|
|
import pandas as pd
|
|
import numpy as np
|
|
import re
|
|
import os
|
|
import math
|
|
from datetime import date
|
|
from decimal import Decimal
|
|
from pathlib import Path
|
|
|
|
#import my functions from other Python files in the same folder
|
|
#import func_readSerrData as func_serr
|
|
|
|
#TO DEBUG, insert "breakpoint()" where you want the simulation to stop
|
|
|
|
#%% 0. GET RUN NUMBER
|
|
run_num = int(input("Enter the run number: "))
|
|
# run_num = 999
|
|
|
|
#%% 00. USER DECISIONS
|
|
# rewind = 0.25 #corresponds to 720 iterations at dt=300s
|
|
|
|
# tolerance for steady-state IC while loop, IC_SS function
|
|
tolerance = 0.01 #C
|
|
|
|
#%%% Is the north wall BC different?
|
|
# north_BC_diff = int(input("Is north wall boundary at an elevated temperature (1=Yes/0=No): "))
|
|
north_BC_diff=0
|
|
#%%% Should all nodes in concrete and XPS layers be output for visualization (1=Yes/0=No)?
|
|
all_wall_layer_nodes = 1
|
|
|
|
#%% FUNCTIONS from func_readSerrData
|
|
|
|
def read_loops_heat_transfer(filename, dat_headers, main_dir, data_dir):
|
|
|
|
import pandas as pd
|
|
|
|
#import csv file with and assign headers from dat_headers df
|
|
col_headers = dat_headers['Loops_heat_transfer'].dropna()
|
|
Serr_loops_heat_transfer = pd.read_table(data_dir.joinpath(filename),
|
|
header = None,
|
|
names = col_headers,
|
|
sep = '\s+',
|
|
comment="#")
|
|
|
|
|
|
return Serr_loops_heat_transfer
|
|
|
|
def read_sand_temps(filename, dat_headers, main_dir, data_dir):
|
|
|
|
import pandas as pd
|
|
|
|
|
|
|
|
#import csv file with TCs and assign headers from dat_headers df
|
|
Serr_sand_temps = pd.read_table(data_dir.joinpath(filename),
|
|
header = None,
|
|
names = dat_headers['Sand_temperatures'].dropna(),
|
|
sep = '\s+',
|
|
comment="#")
|
|
|
|
|
|
return Serr_sand_temps
|
|
|
|
#%% FUNCTIONS
|
|
def remove_newline_in_string(string):
|
|
#remove the \n somehow inserted into the vectors when str() is used
|
|
regex = re.compile(r'\n')
|
|
string_out = regex.sub("",string)
|
|
return string_out
|
|
|
|
def check_mod(rem,divisor):
|
|
rem = round(rem,3)
|
|
rem = float(rem)
|
|
|
|
if rem == divisor:
|
|
#if the remainder is equal to the divisor, then the remainder should really
|
|
#be zero, and it's a particularity of floating point arithmetic and binary numbers
|
|
#and the modulus operator that have made it not equal to zero
|
|
rem = 0
|
|
|
|
return rem
|
|
|
|
def boundaryConditions(startday,day,node_zcoords,domain_H, T_Nbound, T_SEWbound):
|
|
global T_avg, ampl, T_avg_N, ampl_N, north_BC_diff
|
|
|
|
DOY = startday + day
|
|
|
|
#if in higher years
|
|
if DOY > 365*4:
|
|
#Translate to day in year 0 (initial year)
|
|
DOY = DOY-365*4
|
|
elif DOY > 365*3:
|
|
DOY = DOY-365*3
|
|
elif DOY > 365*2:
|
|
DOY = DOY-365*2
|
|
elif DOY > 365:
|
|
DOY = DOY-365
|
|
|
|
#Boundary temperatures of far-field conditions around sand store --> use Kusada eqn:
|
|
#T_soil = T_avg_yearly_temp - ampl*exp(-depth_below_surface/damp_dpth)*cos(2*pi*DOY/365 - depth_below_surface/damp_dpth - phase)
|
|
|
|
#Fill side wall matrices with boundary conditions
|
|
for k in range(0,len(node_zcoords)):
|
|
T_SEWbound[k] = T_avg - ampl*math.exp(-(domain_H-node_zcoords[k])/damp_dpth)*math.cos(2*math.pi*DOY/365 - (domain_H-node_zcoords[k])/damp_dpth - phase)
|
|
|
|
#different parameters on north domain boundary
|
|
if north_BC_diff == 1:
|
|
T_Nbound[k] = T_avg_N - ampl_N*math.exp(-(domain_H-node_zcoords[k])/damp_dpth)*math.cos(2*math.pi*DOY/365 - (domain_H-node_zcoords[k])/damp_dpth - phase)
|
|
else:
|
|
T_Nbound[k] = T_SEWbound[k]
|
|
|
|
|
|
return T_Nbound,T_SEWbound
|
|
|
|
|
|
def updateBCs(T_Nbound, T_SEWbound,timestep):
|
|
global Temps,U,V,W
|
|
#APPLY DIRICHLET BOUNDARY CONDITIONS
|
|
for k in range(1,W-1):
|
|
#NORTH B.C. applies:
|
|
Temps[0,:,k,timestep] = T_Nbound[k]
|
|
|
|
#SOUTH WALL B.C. applies:
|
|
Temps[U-1,:,k,timestep] = T_SEWbound[k]
|
|
|
|
#WEST WALL B.C. applies:
|
|
Temps[:,0,k,timestep] = T_SEWbound[k]
|
|
|
|
#EAST WALL B.C. applies:
|
|
Temps[:,V-1,k,timestep] = T_SEWbound[k]
|
|
|
|
|
|
#BOTTOM WALL B.C. applies:
|
|
Temps[:,:,0,timestep] = T_SEWbound[0]
|
|
#TOP WALL B.C. applies:
|
|
Temps[:,:,W-1,timestep] = T_SEWbound[W-1]
|
|
|
|
|
|
def print2newfile(filename,day,hour,array2print,dim_X, dim_Y, dim_Z, viz = False):
|
|
# global start_YYY, start_MM, start_DD, end_YYY,
|
|
#note: the brackets around the temparray allow the array to be treated as a list of only one list, instead of as a list of lists....so it prints out the delimiters between the numbers
|
|
#https://stackoverflow.com/questions/42068144/numpy-savetxt-is-not-adding-comma-delimiter
|
|
temparray = np.concatenate(([day], [hour], array2print.flatten(order='F')))
|
|
with open(filename,'w') as f:
|
|
#writes parameters to file - dimensions of array
|
|
f.write("#output_array_dims " + str(dim_X) + "," + str(dim_Y) + "," + str(dim_Z)+"\n")
|
|
#writes parameters to file - start and end dates
|
|
f.write("#start_and_end_dates_of_simulation " + str(start_YYYY) + "-" + str(start_MM) + "-" + str(start_DD)+ "," + str(end_YYYY) + "-" + str(end_MM) + "-" + str(end_DD)+"\n")
|
|
f.write("#Number of days of simulation: " + str(numberofdays_simu) + "\n")
|
|
if viz == True:
|
|
#writes x-, y-, and z-coordinate vectors of visualized nodes to file
|
|
f.write("#x-coords " + remove_newline_in_string(str(node_xcoords)) +"\n")
|
|
f.write("#x-viz indices " + remove_newline_in_string(str(VIZ_X_index)) +"\n")
|
|
f.write("#y-coords " + remove_newline_in_string(str(node_ycoords)) +"\n")
|
|
f.write("#y-viz indices " + remove_newline_in_string(str(VIZ_Y_index)) +"\n")
|
|
f.write("#z-coords " + remove_newline_in_string(str(node_zcoords)) +"\n")
|
|
f.write("#z-viz indices " + remove_newline_in_string(str(VIZ_Z_index)) +"\n")
|
|
#writes x- and y-coordinate vectors of location of TC nodes to file
|
|
f.write("#TC_xcoords " + remove_newline_in_string(str(TC_xcoords)) +"\n")
|
|
f.write("#TC_ycoords " + remove_newline_in_string(str(TC_ycoords)) +"\n")
|
|
#write out initial condition in the form of a flattened array
|
|
np.savetxt(f,[temparray],newline=' ', delimiter=',',fmt='%.6f')
|
|
|
|
|
|
def append2file(filename,day,hour,array2print):
|
|
#note: the brackets around the temparray allow the array to be treated as a list of only one list, instead of as a list of lists....so it prints out the delimiters between the numbers
|
|
#https://stackoverflow.com/questions/42068144/numpy-savetxt-is-not-adding-comma-delimiter
|
|
temparray = np.concatenate(([day], [hour], array2print.flatten(order='F')))
|
|
with open(filename,'a') as f:
|
|
f.write("\n")
|
|
np.savetxt(f,[temparray],newline=' ', delimiter=',',fmt='%.6f')
|
|
|
|
def IC_SS(dt):
|
|
global U,V,W, Temps,Lambda, rho, Cp, node_xcoords, node_ycoords, node_zcoords
|
|
global pwr_bott_indx,x_pwr_low_indx, x_pwr_high_indx, y_pwr_low_indx, y_pwr_high_indx
|
|
global pwr_mid_indx, pwr_upr_indx, nn, tolerance, rewind, diff, get_out
|
|
|
|
import matplotlib.pyplot as plt
|
|
#initialize
|
|
prev=0
|
|
diff=20
|
|
|
|
fig,ax=plt.subplots()
|
|
fig1,ax1=plt.subplots()
|
|
fig2,ax2=plt.subplots()
|
|
|
|
#while (rewind*10*24*3600/300 > nn):#rewinds of 10 days at dt=300s
|
|
|
|
while (diff > tolerance):
|
|
nn = nn+1
|
|
print(nn,diff)
|
|
|
|
# if math.remainder(nn,100) == 0:
|
|
# #save the graphs
|
|
# ax.set_title("After " + str(nn) + " iterations, max diff=" + str(diff))
|
|
# fig.savefig(main_dir.joinpath("After " + str(nn) + " iterations_x.png"), dpi=150, bbox_inches='tight')
|
|
# ax1.set_title("After " + str(nn) + " iterations")
|
|
# fig1.savefig(main_dir.joinpath("After " + str(nn) + " iterations_y.png"), dpi=150, bbox_inches='tight')
|
|
# ax2.set_title("After " + str(nn) + " iterations")
|
|
# fig2.savefig(main_dir.joinpath("After " + str(nn) + " iterations_z.png"), dpi=150, bbox_inches='tight')
|
|
|
|
#initialize new figures for the next 1000 lines
|
|
# fig,ax=plt.subplots()
|
|
# fig1,ax1=plt.subplots()
|
|
# fig2,ax2=plt.subplots()
|
|
|
|
# ax.plot(range(0,Temps[:,31,24,0].shape[0]),Temps[:,31,24,0])
|
|
# ax1.plot(range(0,Temps[31,:,24,0].shape[0]),Temps[31,:,24,0])
|
|
# ax2.plot(range(0,Temps[31,31,:,0].shape[0]),Temps[31,31,:,0])
|
|
|
|
|
|
#We are not iterating over boundary walls or the sand store
|
|
for i in range(1,U-1):
|
|
for j in range(1,V-1):
|
|
for k in range(1,W-1):
|
|
|
|
#cubic volume of the sand store, don't iterate over it
|
|
if (k > indx_bndrz_z[6] and k < indx_bndrz_z[7] and
|
|
i > indx_bndrz_x[6] and i < indx_bndrz_x[11] and
|
|
j > indx_bndrz_y[6] and j < indx_bndrz_y[11]):
|
|
|
|
continue #skip the rest of the for loop
|
|
else:
|
|
#prev time step temp
|
|
old_T = Temps[i,j,k,prev]
|
|
|
|
#GETTING TEMPS AROUND NODE FROM PREV TIMESTEP AND LAMBDAs, TO USE IN GOV EQN
|
|
North = Temps[i-1,j,k,prev]
|
|
South = Temps[i+1,j,k,prev]
|
|
West = Temps[i,j-1,k,prev]
|
|
East = Temps[i,j+1,k,prev]
|
|
Bottom = Temps[i,j,k-1,prev]
|
|
Top = Temps[i,j,k+1,prev]
|
|
|
|
lmbda_S = Lambda[i+1,j,k]
|
|
lmbda_E = Lambda[i,j+1,k]
|
|
lmbda_T = Lambda[i,j,k+1]
|
|
|
|
#APPLY GOVERNING EQUATION
|
|
#variable substitution [for easier reading of GE]
|
|
#subscripts _ip1/_im1 mean "i plus 1, i minus 1"
|
|
g = dt/ (rho[i,j,k] * Cp[i,j,k])
|
|
lmbda = Lambda[i,j,k]
|
|
x_i = node_xcoords[i]
|
|
x_ip1 = node_xcoords[i+1] #ip1 -> i plus one
|
|
x_im1 = node_xcoords[i-1] #im1 -> i minus one
|
|
y_j = node_ycoords[j]
|
|
y_jp1 = node_ycoords[j+1]
|
|
y_jm1 = node_ycoords[j-1]
|
|
z_k = node_zcoords[k]
|
|
z_kp1 = node_zcoords[k+1]
|
|
z_km1 = node_zcoords[k-1]
|
|
|
|
#else use GE without Q_source term
|
|
Temps[i,j,k,1] = old_T + g *( (lmbda_S-lmbda)*(South-old_T)/((x_ip1-x_i)**2) +
|
|
(2*lmbda/(x_ip1-x_im1))*( ((South-old_T)/(x_ip1-x_i))-((North-old_T)/(x_im1-x_i)) ) +
|
|
(lmbda_E-lmbda)*(East-old_T)/((y_jp1-y_j)**2) +
|
|
(2*lmbda/(y_jp1-y_jm1))*( ((East-old_T)/(y_jp1-y_j))-((West-old_T)/(y_jm1-y_j)) ) +
|
|
(lmbda_T-lmbda)*(Top-old_T)/((z_kp1-z_k)**2) +
|
|
(2*lmbda/(z_kp1-z_km1))*( ((Top-old_T)/(z_kp1-z_k))-((Bottom-old_T)/(z_km1-z_k)) ) )
|
|
|
|
|
|
#take difference between the maximum temperatures in the new and old timesteps
|
|
diff = np.max(abs(Temps[:,:,:,1]-Temps[:,:,:,0]))
|
|
|
|
if np.max(Temps)>1000 or np.min(Temps)<-1000 or np.isinf(Temps).sum()>0 or np.isnan(Temps).sum()>0:
|
|
get_out=1
|
|
print("Exited for loop - unstable FDM model")
|
|
break
|
|
|
|
if diff > 20:
|
|
print("yes")
|
|
if abs(diff) > 20:
|
|
print("abs_yes")
|
|
#put temps from just-calculated timestep into "previous" timestep
|
|
Temps[:,:,:,0] = Temps[:,:,:,1]
|
|
|
|
return diff
|
|
|
|
def GoverningEqn(dt,n):
|
|
global U,V,W, Temps,Lambda, rho, Cp, node_xcoords, node_ycoords, node_zcoords, solar_to_Sand_W, Sand_to_SH_W
|
|
global pwr_bott_indx,x_pwr_low_indx, x_pwr_high_indx, y_pwr_low_indx, y_pwr_high_indx
|
|
global pwr_mid_indx, pwr_upr_indx
|
|
#We are not iterating over boundary nodes, because their temperatures
|
|
#are known
|
|
prev = 0
|
|
|
|
for i in range(1,U-1):
|
|
for j in range(1,V-1):
|
|
for k in range(1,W-1):
|
|
#prev time step temp
|
|
old_T = Temps[i,j,k,prev]
|
|
|
|
#GETTING TEMPS AROUND NODE FROM PREV TIMESTEP AND LAMBDAs, TO USE IN GOV EQN
|
|
North = Temps[i-1,j,k,prev]
|
|
South = Temps[i+1,j,k,prev]
|
|
West = Temps[i,j-1,k,prev]
|
|
East = Temps[i,j+1,k,prev]
|
|
Bottom = Temps[i,j,k-1,prev]
|
|
Top = Temps[i,j,k+1,prev]
|
|
|
|
lmbda_S = Lambda[i+1,j,k]
|
|
lmbda_E = Lambda[i,j+1,k]
|
|
lmbda_T = Lambda[i,j,k+1]
|
|
|
|
#APPLY GOVERNING EQUATION
|
|
#variable substitution [for easier reading of GE]
|
|
#subscripts _ip1/_im1 mean "i plus 1, i minus 1"
|
|
g = dt/ (rho[i,j,k] * Cp[i,j,k])
|
|
lmbda = Lambda[i,j,k]
|
|
x_i = node_xcoords[i]
|
|
x_ip1 = node_xcoords[i+1] #ip1 -> i plus one
|
|
x_im1 = node_xcoords[i-1] #im1 -> i minus one
|
|
y_j = node_ycoords[j]
|
|
y_jp1 = node_ycoords[j+1]
|
|
y_jm1 = node_ycoords[j-1]
|
|
z_k = node_zcoords[k]
|
|
z_kp1 = node_zcoords[k+1]
|
|
z_km1 = node_zcoords[k-1]
|
|
|
|
|
|
#if node being calculated is within the bottom power slab area
|
|
if (k==pwr_bott_indx and (i >= x_pwr_low_indx and i <= x_pwr_high_indx) and (j >= y_pwr_low_indx and j <= y_pwr_high_indx)):
|
|
#use GE with Q_source term
|
|
Temps[i,j,k,1] = old_T + g *( solar_to_Sand_W[n-1,2] - Sand_to_SH_W[n-1,2] +
|
|
(lmbda_S-lmbda)*(South-old_T)/((x_ip1-x_i)**2) +
|
|
(2*lmbda/(x_ip1-x_im1))*( ((South-old_T)/(x_ip1-x_i))-((North-old_T)/(x_im1-x_i)) ) +
|
|
(lmbda_E-lmbda)*(East-old_T)/((y_jp1-y_j)**2) +
|
|
(2*lmbda/(y_jp1-y_jm1))*( ((East-old_T)/(y_jp1-y_j))-((West-old_T)/(y_jm1-y_j)) ) +
|
|
(lmbda_T-lmbda)*(Top-old_T)/((z_kp1-z_k)**2) +
|
|
(2*lmbda/(z_kp1-z_km1))*( ((Top-old_T)/(z_kp1-z_k))-((Bottom-old_T)/(z_km1-z_k)) ) )
|
|
|
|
#if node being calculated is within the middle power slab area
|
|
elif (k==pwr_mid_indx and (i >= x_pwr_low_indx and i <= x_pwr_high_indx)
|
|
and (j >= y_pwr_low_indx and j <= y_pwr_high_indx)):
|
|
#use GE with Q_source term
|
|
Temps[i,j,k,1] = old_T + g *( solar_to_Sand_W[n-1,2] - Sand_to_SH_W[n-1,2] +
|
|
(lmbda_S-lmbda)*(South-old_T)/((x_ip1-x_i)**2) +
|
|
(2*lmbda/(x_ip1-x_im1))*( ((South-old_T)/(x_ip1-x_i))-((North-old_T)/(x_im1-x_i)) ) +
|
|
(lmbda_E-lmbda)*(East-old_T)/((y_jp1-y_j)**2) +
|
|
(2*lmbda/(y_jp1-y_jm1))*( ((East-old_T)/(y_jp1-y_j))-((West-old_T)/(y_jm1-y_j)) ) +
|
|
(lmbda_T-lmbda)*(Top-old_T)/((z_kp1-z_k)**2) +
|
|
(2*lmbda/(z_kp1-z_km1))*( ((Top-old_T)/(z_kp1-z_k))-((Bottom-old_T)/(z_km1-z_k)) ) )
|
|
|
|
#if node being calculated is within the top power slab area
|
|
elif (k==pwr_upr_indx and (i >= x_pwr_low_indx and i <= x_pwr_high_indx)
|
|
and (j >= y_pwr_low_indx and j <= y_pwr_high_indx)):
|
|
#use GE with Q_source term
|
|
Temps[i,j,k,1] = old_T + g *( solar_to_Sand_W[n-1,2] - Sand_to_SH_W[n-1,2] +
|
|
(lmbda_S-lmbda)*(South-old_T)/((x_ip1-x_i)**2) +
|
|
(2*lmbda/(x_ip1-x_im1))*( ((South-old_T)/(x_ip1-x_i))-((North-old_T)/(x_im1-x_i)) ) +
|
|
(lmbda_E-lmbda)*(East-old_T)/((y_jp1-y_j)**2) +
|
|
(2*lmbda/(y_jp1-y_jm1))*( ((East-old_T)/(y_jp1-y_j))-((West-old_T)/(y_jm1-y_j)) ) +
|
|
(lmbda_T-lmbda)*(Top-old_T)/((z_kp1-z_k)**2) +
|
|
(2*lmbda/(z_kp1-z_km1))*( ((Top-old_T)/(z_kp1-z_k))-((Bottom-old_T)/(z_km1-z_k)) ) )
|
|
else:
|
|
#else use GE without Q_source term
|
|
Temps[i,j,k,1] = old_T + g *( (lmbda_S-lmbda)*(South-old_T)/((x_ip1-x_i)**2) +
|
|
(2*lmbda/(x_ip1-x_im1))*( ((South-old_T)/(x_ip1-x_i))-((North-old_T)/(x_im1-x_i)) ) +
|
|
(lmbda_E-lmbda)*(East-old_T)/((y_jp1-y_j)**2) +
|
|
(2*lmbda/(y_jp1-y_jm1))*( ((East-old_T)/(y_jp1-y_j))-((West-old_T)/(y_jm1-y_j)) ) +
|
|
(lmbda_T-lmbda)*(Top-old_T)/((z_kp1-z_k)**2) +
|
|
(2*lmbda/(z_kp1-z_km1))*( ((Top-old_T)/(z_kp1-z_k))-((Bottom-old_T)/(z_km1-z_k)) ) )
|
|
|
|
|
|
# def partialAvg_of_Temps_in_zDir(XYZarray,min_zIndx,max_zIndx):
|
|
# #This function calculates the average of a 3-D chunk of an array, from bottom z index, up to and including the top z-index.
|
|
# global indx_bndrz_z, moisture_layer_height
|
|
|
|
# temp_sum = 0
|
|
# temp_avg = 0
|
|
# for k in range(min_zIndx,max_zIndx + 1):
|
|
# temp_sum = temp_sum + np.mean(XYZarray[:,:,k])
|
|
# temp_avg = temp_sum/len(range(min_zIndx,max_zIndx + 1))
|
|
|
|
# return temp_avg
|
|
|
|
# %% Define Directory Paths
|
|
#get current directory
|
|
main_dir = Path(os.getcwd())
|
|
#define parent directory
|
|
parent = main_dir.parents[0]
|
|
|
|
#define directory holding input data
|
|
data_dir = parent.joinpath('Exp_Data_for_models')
|
|
#define directory where graphs will be saved
|
|
graph_dir = main_dir.joinpath('Diff_runs')
|
|
|
|
#Read in Headers file
|
|
dat_headers = pd.read_csv(data_dir.joinpath('Serrano_dat_headers.csv'))
|
|
|
|
|
|
# %% 1. IMPORT EXPERIMENTAL DATA FILES
|
|
#FILENAMES OF DATA FILES
|
|
#(NB! filename1 MUST have a start AND end date, even if they are equal, ie. only one day of data)
|
|
|
|
#Excel sheet with different run descriptions
|
|
diff_runs_file = graph_dir.joinpath('2021-07-13 Description of different runs.xlsx')
|
|
diff_runs = pd.read_excel(diff_runs_file, header=1, index_col=0)
|
|
|
|
#check the period column to get the experimental file names accordingly
|
|
if diff_runs.Period[run_num].rstrip() == 'cooldown June 2021':
|
|
|
|
#%%%% Cooldown (mode 1)
|
|
#sand store temperatures file
|
|
filename1 = 'Sand_temperatures_2021-05-28-to-2021-07-06.dat'
|
|
#loops heat transfer file
|
|
filename2 ='Loops_heat_transfer_2021-05-28-to-2021-07-06.dat'
|
|
|
|
elif diff_runs.Period[run_num].rstrip() == 'charging Mar 2021':
|
|
|
|
#%%%% Charging (mode 2)
|
|
#sand store temperatures file
|
|
filename1 = 'Sand_temperatures_2021-03-21-to-2021-03-23.dat'
|
|
#loops heat transfer file
|
|
filename2 ='Loops_heat_transfer_2021-03-21-to-2021-03-23.dat'
|
|
|
|
elif diff_runs.Period[run_num].rstrip() == 'discharging Nov 2020':
|
|
|
|
#%%%% Discharging (mode 3)
|
|
#sand store temperatures file
|
|
filename1 = 'Sand_temperatures_2020-11-25-to-2020-11-27.dat'
|
|
#loops heat transfer file
|
|
filename2 ='Loops_heat_transfer_2020-11-25-to-2020-11-27.dat'
|
|
|
|
elif diff_runs.Period[run_num].rstrip() == 'charging + discharging Nov 29':
|
|
|
|
#%%%% Charging and Discharging (mode 4)
|
|
#sand store temperatures file
|
|
filename1 = 'Sand_temperatures_2020-11-28-to-2020-11-30.dat'
|
|
#loops heat transfer file
|
|
filename2 ='Loops_heat_transfer_2020-11-28-to-2020-11-30.dat'
|
|
|
|
elif diff_runs.Period[run_num].rstrip() == 'charging + discharging Nov 23':
|
|
|
|
#%%%% Charging and Discharging 2 (mode 5)
|
|
#sand store temperatures file
|
|
filename1 = 'Sand_temperatures_2020-11-23-to-2020-11-23.dat'
|
|
#loops heat transfer file
|
|
filename2 ='Loops_heat_transfer_2020-11-23-to-2020-11-23.dat'
|
|
elif diff_runs.Period[run_num].rstrip() == 'heating season 2021':
|
|
|
|
#%%%% Entire heating season (mode 6)
|
|
#sand store temperatures file
|
|
filename1 = 'Sand_temperatures_2020-11-19-to-2021-04-30.dat'
|
|
#loops heat transfer file
|
|
filename2 ='Loops_heat_transfer_2020-11-19-to-2021-04-30.dat'
|
|
else:
|
|
print("Experimental data files not correctly selected. Please check run number and that the Excel input file is correct.")
|
|
#%%% Processing of dates
|
|
#Parse out dates between which to run the simulation
|
|
|
|
#find year 1
|
|
f1_name, f1_2, f1_3 = re.split('(_20)',filename1)
|
|
|
|
st1 = filename1.find('_20')
|
|
date_start = filename1[st1+1:st1+11]
|
|
|
|
end1 = filename1.find('to-')
|
|
date_end = filename1[end1+3:-4]
|
|
|
|
#convert to datetime format
|
|
start_YYYY, start_MM, start_DD = date_start.split('-')
|
|
end_YYYY, end_MM, end_DD = date_end.split('-')
|
|
|
|
date_start = date(int(start_YYYY),int(start_MM),int(start_DD))
|
|
date_end = date(int(end_YYYY),int(end_MM),int(end_DD))
|
|
|
|
#Read in Headers file
|
|
dat_headers = pd.read_csv(data_dir.joinpath('Serrano_dat_headers.csv'))
|
|
|
|
#Read in sand temps data into a DataFrame
|
|
Exp_sand_temps = read_sand_temps(filename1, dat_headers, main_dir, data_dir)
|
|
|
|
#Read in loops heat transfer data into DataFrame
|
|
Exp_heat_transfer_data = read_loops_heat_transfer(filename2, dat_headers, main_dir, data_dir)
|
|
#Initialize boolean variable
|
|
missing_heat_data = False
|
|
|
|
# %%1. Timestep Parameters - CAN BE CHANGED
|
|
|
|
dt = 300 #time step, in seconds
|
|
output_temp_freq_h = 1 #how often the TC temperatures from the 3-D sand store will be output to the data file, in hours
|
|
visualization_output_freq_h = 24 #how often the temperatures from the domain nodes (more nodes than TC temps) will be output to the data file, in hours
|
|
|
|
output_temp_freq_int = (output_temp_freq_h * 3600)/dt #frequency that temperatures of the 3-D sand store will be output to the data file, in number of timestep intervals
|
|
viz_output_freq_int = (visualization_output_freq_h * 3600)/dt #frequency that temperatures of the domain will be output to the data file, in number of timestep intervals
|
|
|
|
#How many days in the simulation?
|
|
if (date_start == date_end):
|
|
numberofdays_simu = 1
|
|
else:
|
|
numberofdays_simu = (date_end - date_start).days + 1
|
|
|
|
tot_time = numberofdays_simu*24*3600 #1h = 3600s
|
|
timeIntrvls_per_day = int(24*3600/dt) # number of time step intervals per day
|
|
totTimeIntrvls = int(tot_time/dt) # total number of time step intervals
|
|
|
|
# %%1. Kusuda parameters - CAN BE CHANGED
|
|
|
|
#KUSUDA PARAMETERS for Ottawa(ground temp)
|
|
T_avg = 8 #(C)
|
|
ampl = 18.507
|
|
#depth from surface (m)
|
|
damp_dpth = 3
|
|
phase =0.38
|
|
|
|
#different parameters on north domain boundary due to presence of house
|
|
if north_BC_diff == 1:
|
|
T_avg_N = 8+4 #(C)
|
|
ampl_N = 14
|
|
else:
|
|
T_avg_N = 8
|
|
ampl_N = 18.507
|
|
|
|
# %% 2. Process Experimental Sand Temp data into Numpy arrays
|
|
"""
|
|
This script processes the experimental data, output by Serrano, from a .dat
|
|
or .csv file into Matlab matrix form, so that it can be used later
|
|
|
|
RECALL!!!! k = 0 is bottom of sand store, while C-layer is bottom-most plane
|
|
"""
|
|
|
|
#Put time data into a new numpy array (shows the time in hours from the start of the year)
|
|
time_h = Exp_sand_temps['time'].copy().to_numpy()
|
|
|
|
#rows and columns of sand temp data
|
|
[A, B] = Exp_sand_temps.shape
|
|
|
|
#create 4-D array to hold temp data
|
|
Exp_sand_temps_4d = np.zeros(shape=[6,6,3,A])
|
|
|
|
#create loop to map expt'l data to 4-D matrix
|
|
for indx1 in range(0,A):
|
|
|
|
indx2 = 1 #index for the number of columns in the matrix. It starts at 1 since the first column is the time-stamp (zero-indexed)
|
|
|
|
for k in range (2,-1,-1):
|
|
for i in range (0,6):
|
|
for j in range (0,6):
|
|
Exp_sand_temps_4d[i,j,k,indx1] = Exp_sand_temps.iloc[indx1,indx2]
|
|
|
|
#increment the column to be read next time
|
|
indx2 = indx2 + 1
|
|
#check that it exists, and that it's not the end of the line
|
|
if indx2 >= B:
|
|
#break out of the innermost loop
|
|
break
|
|
|
|
|
|
#take averages of sand temps (lowest index is bottom-most layer of sand store)
|
|
avg_expmtl_temps = np.mean(np.mean(Exp_sand_temps_4d,axis=0),axis=0).transpose()
|
|
|
|
#convert time in hours into minutes from start of year
|
|
time_min = time_h*60
|
|
|
|
#Calculate day of year data starts
|
|
DOY = math.floor(time_h[0]/24)+1
|
|
# %% 2. Geometry of Domain
|
|
# %%% High-level geometry
|
|
|
|
#x-y-z origin lies at north-west corner, bottom of sand store
|
|
sand_L = 6 #(m) length of sand store x = 0 m to x = 6 m
|
|
sand_W = 6 #(m) width of sand store y = 0 m to y = 6 m
|
|
sand_H = 3 #(m) height of sand store, from bottom z = 0 m to top z = 3 m
|
|
|
|
XPS_th = 0.35 #(m) spec'd thickness of insulation around sand store (14")
|
|
conc_th = 0.10 #(m) spec'd thickness of concrete
|
|
|
|
soil_top_th = 1.5 #(m) thickness of soil layer on top of sand store to surface
|
|
soil_nrthside_th = 3.5 #(m) thickness of soil layer on north side of sand store to soil near house
|
|
soil_th = 10 #(m) thickness of soil layer on S, E, W, and bottom sides of sand store to far-field temp
|
|
|
|
no_TC = 0.5 #(m) buffer of 0.5m between sand store wall and 1st TCs (according to Briana Kemery's Visio document:https://chernode.mae.carleton.ca/sbes_svn/CHEeR_instrumentation/Sensor_connections_to_DAQs/Sand_store_TC_and_moisture_meter_placements.vsdx
|
|
node_space = (sand_L - 2*no_TC)/5 #Calculating the distance (m) between TCs in the sand store, assuming that there are 6 x 6 TCs equally spaced on each layer,
|
|
|
|
no_pwr = 0.3 #(m) length around outside of sand store where the PEX tubes are not layed down (estimated from photos)
|
|
pwr_bott = 0.4 #(m) bottom z-value of x-z plane where PEX tubing is laid down
|
|
pwr_mid = 1.3 #(m) middle z-value of x-z plane where PEX tubing is laid down
|
|
pwr_upr = 2.2 #(m) top z-value of x-z plane where PEX tubing is laid down
|
|
|
|
domain_L = soil_th + soil_nrthside_th + conc_th*2 + XPS_th*2 + sand_L #(m) length of numerical domain, x-axis
|
|
domain_W = soil_th*2 + conc_th*2 + XPS_th*2 + sand_W#(m) width of numerical domain, y-axis
|
|
domain_H = soil_th + soil_top_th + conc_th + XPS_th*2 + sand_H#(m) height of numerical domain, z-axis
|
|
|
|
|
|
#%%% Node Placement (varying mesh size)
|
|
|
|
#In x (or y-direction), from x=0 to the south.
|
|
#0m = north far-field temperature
|
|
|
|
"""
|
|
The following values can be changed to see the effect of number of nodes on the final solution
|
|
"""
|
|
dx_soil = 0.3 #(m) dx of nodes in coarse grid horiz soil layer: in between the soil far-field boundary and the "increased node spacing layer"
|
|
dx_soilconc_boundary = 0.1 #(m) dx of nodes in fine grid horiz soil layer: between the coarse grid and the concrete layer
|
|
soilconc_boundary_th = 0.2 #(m) thickness of fine grid horiz soil layer
|
|
nodes_conc = 2 #number of nodes to make up concrete layer (horiz and vertical)
|
|
nodes_XPS = 2 #number of nodes to make up XPS layer (horiz and vertical)
|
|
nodes_no_pwr = 2 # number of horiz. nodes in sand layer, in the "no_pwr" area
|
|
dx_sand = 0.2 #(m) dx of horiz. nodes in sand layer, inside the "pwr" area
|
|
|
|
dz_soil_top = 0.3 #(m)dz of nodes in top vert. soil layer
|
|
dz_pwr_th = 0.03 #(m) the vertical node spacing in the three power slab layers. Each power slab layer has three equi-sized dz layers
|
|
#around and on it, with the node of the middle layer directly on the power slab line (i.e. 0.4m, 1.3m, and 2.2m
|
|
#above the sand store bottom)
|
|
nodes_dz1_sand = 2 #number of nodes in between pwr_bott layer and bottom of sand store (not including the three nodes around the pwr_bott layer)
|
|
nodes_dz2_sand = 4 #number of nodes in between pwr_mid layer and pwr_bott layer (not including the three nodes around each pwr layer)
|
|
nodes_dz3_sand = 4 #number of nodes in between pwr_upr layer and pwr_mid layer (not including the three nodes around each pwr layer)
|
|
nodes_dz4_sand = 4 #number of nodes in between pwr_upr layer and top of sand store(not including the three nodes around pwr_upr layer)
|
|
|
|
#%%% Horizontal Coordinate Vectors
|
|
#%%%% SOIL COORDS
|
|
|
|
#(Note:the vector of dx's is the same as the vector for dy's, except for
|
|
#the length of the northside soil thickness)
|
|
#============================================================
|
|
#============================================================
|
|
#number of nodes in coarser soil grid
|
|
QN1 = math.floor(round((soil_nrthside_th - soilconc_boundary_th)/dx_soil,3))
|
|
#remainder of coarse soil length needing to be accounted for
|
|
RN1 = (Decimal(soil_nrthside_th) - Decimal(soilconc_boundary_th)) % Decimal(dx_soil)
|
|
RN1 = check_mod(RN1,dx_soil)
|
|
|
|
|
|
#number of nodes in fine soil grid
|
|
Q2 = math.floor(round(soilconc_boundary_th/dx_soilconc_boundary,3))
|
|
#remainder of fine soil length needing to be accounted
|
|
R2 = Decimal(soilconc_boundary_th) % Decimal(dx_soilconc_boundary)
|
|
R2 = check_mod(R2,dx_soilconc_boundary)
|
|
|
|
#SUBVECTOR in which to put X-COORDINATES OF NORTH SOIL NODES
|
|
#--------------------------------------------------
|
|
Hsoil_coords_n = np.zeros(shape=[1+QN1+Q2])
|
|
|
|
#far-field north boundary x=0 m
|
|
Hsoil_coords_n[0] = 0
|
|
#1st node's x-coordinate, in metres:
|
|
Hsoil_coords_n[1] = (dx_soil/2) + RN1 + R2
|
|
#starting at index 3, coarse nodes' x-coordinates in metres
|
|
for i in range(2,(1+QN1)):
|
|
Hsoil_coords_n[i] = Hsoil_coords_n[i-1] + dx_soil
|
|
|
|
#1st node in fine grid area:
|
|
i = i+1
|
|
Hsoil_coords_n[i] = Hsoil_coords_n[i-1] + dx_soil/2 + dx_soilconc_boundary/2
|
|
i = i+1
|
|
#fine nodes' x-coordinates in metres
|
|
for i in range(i,len(Hsoil_coords_n)):
|
|
Hsoil_coords_n[i] = Hsoil_coords_n[i-1] + dx_soilconc_boundary
|
|
|
|
|
|
#SUBVECTOR in which to put Y-COORDINATES OF WEST SOIL NODES
|
|
#--------------------------------------------------
|
|
#number of nodes in coarser soil grid
|
|
Q1 = math.floor((soil_th - soilconc_boundary_th)/dx_soil)
|
|
#remainder of coarse soil length needing to be accounted for
|
|
R1 = (soil_th - soilconc_boundary_th) % dx_soil
|
|
|
|
Hsoil_coords_w = np.zeros(shape=[1+Q1+Q2])
|
|
|
|
#far-field west boundary x=0 m
|
|
Hsoil_coords_w[0] = 0
|
|
#1st node's y-coordinate, in metres:
|
|
Hsoil_coords_w[1] = (dx_soil/2) + R1 + R2
|
|
#starting at index 3, coarse nodes' x-coordinates in metres
|
|
for i in range(2,(1+Q1)):
|
|
Hsoil_coords_w[i] = Hsoil_coords_w[i-1] + dx_soil
|
|
|
|
#1st node in fine grid area:
|
|
i = i+1
|
|
Hsoil_coords_w[i] = Hsoil_coords_w[i-1] + dx_soil/2 + dx_soilconc_boundary/2
|
|
i = i+1
|
|
#fine nodes' x-coordinates in metres
|
|
for i in range(i,len(Hsoil_coords_w)):
|
|
Hsoil_coords_w[i] = Hsoil_coords_w[i-1] + dx_soilconc_boundary
|
|
|
|
|
|
#SUBVECTOR in which to put X-COORDINATES OF SOUTH SOIL NODES
|
|
#--------------------------------------------------
|
|
Hsoil_coords_s = np.zeros(shape=[1+Q1+Q2])
|
|
|
|
Hsoil_coords_s[(0)] = soil_nrthside_th + conc_th*2 + XPS_th*2 + sand_L + dx_soilconc_boundary/2
|
|
#fine nodes' x-coordinates in metres
|
|
for i in range(1,Q2):
|
|
Hsoil_coords_s[i] = Hsoil_coords_s[i-1] + dx_soilconc_boundary
|
|
|
|
#1st node in coarse grid area:
|
|
i = i+1
|
|
Hsoil_coords_s[i] = Hsoil_coords_s[i-1] + dx_soil/2 + dx_soilconc_boundary/2
|
|
i = i+1
|
|
#coarse nodes' x-coordinates in metres
|
|
for i in range(i,(len(Hsoil_coords_s)-1)):
|
|
Hsoil_coords_s[i] = Hsoil_coords_s[i-1] + dx_soil
|
|
|
|
#far-field south boundary x=domain_L
|
|
Hsoil_coords_s[(len(Hsoil_coords_s)-1)] = domain_L
|
|
|
|
|
|
#SUBVECTOR in which to put Y-COORDINATES OF EAST SOIL NODES
|
|
#--------------------------------------------------
|
|
Hsoil_coords_e = np.zeros(shape=[1+Q1+Q2])
|
|
|
|
Hsoil_coords_e[(0)] = soil_th + conc_th*2 + XPS_th*2 + sand_W + dx_soilconc_boundary/2
|
|
#fine nodes' x-coordinates in metres
|
|
for i in range(1,Q2):
|
|
Hsoil_coords_e[i] = Hsoil_coords_e[i-1] + dx_soilconc_boundary
|
|
|
|
#1st node in coarse grid area:
|
|
i = i+1
|
|
Hsoil_coords_e[i] = Hsoil_coords_e[i-1] + dx_soil/2 + dx_soilconc_boundary/2
|
|
i = i+1
|
|
#coarse nodes' x-coordinates in metres
|
|
for i in range(i,(len(Hsoil_coords_e)-1)):
|
|
Hsoil_coords_e[i] = Hsoil_coords_e[i-1] + dx_soil
|
|
|
|
#far-field south boundary y=domain_W
|
|
Hsoil_coords_e[(len(Hsoil_coords_e)-1)] = domain_W
|
|
|
|
|
|
# %%%% CONCRETE COORDS
|
|
#============================================================
|
|
Hconc_coords_n = np.zeros(shape=[nodes_conc])
|
|
Hconc_coords_w = np.zeros(shape=[nodes_conc])
|
|
Hconc_coords_s = np.zeros(shape=[nodes_conc])
|
|
Hconc_coords_e = np.zeros(shape=[nodes_conc])
|
|
|
|
#dx for concrete:
|
|
Q3 = math.floor(conc_th*100/nodes_conc)/100
|
|
#remainder of concrete length needing to be accounted for
|
|
R3 = (conc_th*100 % nodes_conc)/100
|
|
|
|
#1st conc node
|
|
Hconc_coords_n[0] = soil_nrthside_th + Q3/2 + R3
|
|
Hconc_coords_w[0] = soil_th + Q3/2 + R3
|
|
Hconc_coords_s[0] = soil_nrthside_th + conc_th + XPS_th*2 + sand_L + Q3/2
|
|
Hconc_coords_e[0] = soil_th + conc_th + XPS_th*2 + sand_W + Q3/2
|
|
|
|
#remainder of nodes
|
|
for i in range(1,nodes_conc):
|
|
Hconc_coords_n[i] = Hconc_coords_n[i-1] + Q3
|
|
Hconc_coords_w[i] = Hconc_coords_w[i-1] + Q3
|
|
Hconc_coords_s[i] = Hconc_coords_s[i-1] + Q3
|
|
Hconc_coords_e[i] = Hconc_coords_e[i-1] + Q3
|
|
|
|
|
|
#%%%% XPS COORDS
|
|
#============================================================
|
|
HXPS_coords_n = np.zeros(shape=[nodes_XPS])
|
|
HXPS_coords_w = np.zeros(shape=[nodes_XPS])
|
|
HXPS_coords_s = np.zeros(shape=[nodes_XPS])
|
|
HXPS_coords_e = np.zeros(shape=[nodes_XPS])
|
|
|
|
#dx for XPS:
|
|
Q4 = math.floor(XPS_th*100/nodes_XPS)/100
|
|
#remainder of XPS length needing to be accounted for
|
|
R4 = (XPS_th*100 % nodes_XPS)/100
|
|
|
|
#1st XPS node
|
|
HXPS_coords_n[0] = soil_nrthside_th + conc_th + Q4/2 + R4
|
|
HXPS_coords_w[0] = soil_th + conc_th + Q4/2 + R4
|
|
HXPS_coords_s[0] = soil_nrthside_th + conc_th + XPS_th + sand_L + Q4/2
|
|
HXPS_coords_e[0] = soil_th + conc_th + XPS_th + sand_W + Q4/2
|
|
|
|
#remainder of nodes
|
|
for i in range(1,nodes_XPS):
|
|
HXPS_coords_n[i] = HXPS_coords_n[i-1] + Q4
|
|
HXPS_coords_w[i] = HXPS_coords_w[i-1] + Q4
|
|
HXPS_coords_s[i] = HXPS_coords_s[i-1] + Q4
|
|
HXPS_coords_e[i] = HXPS_coords_e[i-1] + Q4
|
|
|
|
|
|
#%%%% SAND, NO-POWER ZONE COORDS (north and west sides)
|
|
#============================================================
|
|
Hnopwr_coords_n = np.zeros(shape=[nodes_no_pwr])
|
|
Hnopwr_coords_w = np.zeros(shape=[nodes_no_pwr])
|
|
Hnopwr_coords_s = np.zeros(shape=[nodes_no_pwr])
|
|
Hnopwr_coords_e = np.zeros(shape=[nodes_no_pwr])
|
|
|
|
#dx for no_pwr:
|
|
Q5 = math.floor(no_pwr*100/nodes_no_pwr)/100
|
|
#remainder of no_pwr length needing to be accounted for
|
|
R5 = (no_pwr*100 % nodes_no_pwr)/100
|
|
|
|
#1st no_pwr node on north and west sides
|
|
Hnopwr_coords_n[0] = soil_nrthside_th + conc_th + XPS_th + Q5/2 + R5
|
|
Hnopwr_coords_w[0] = soil_th + conc_th + XPS_th + Q5/2 + R5
|
|
|
|
#remainder of nodes on north and west sides
|
|
for i in range(1,nodes_no_pwr):
|
|
Hnopwr_coords_n[i] = Hnopwr_coords_n[i-1] + Q5
|
|
Hnopwr_coords_w[i] = Hnopwr_coords_w[i-1] + Q5
|
|
|
|
|
|
#%%%% SAND, POWER ZONE COORDS
|
|
#============================================================
|
|
#number of nodes in sand power area, x-dir
|
|
Q6 = math.floor(round((sand_L - no_pwr*2)/dx_sand,3))
|
|
#remainder of sand length needing to be accounted for
|
|
R6 = (Decimal(sand_L) - Decimal(no_pwr)*2) % Decimal(dx_sand)
|
|
R6 = check_mod(R6,dx_sand)
|
|
|
|
#number of nodes in sand power area, y-dir
|
|
Q7 = math.floor(round((sand_W - no_pwr*2)/dx_sand,3))
|
|
#remainder of sand width needing to be accounted for
|
|
R7 = (Decimal(sand_W) - Decimal(no_pwr)*2) % Decimal(dx_sand)
|
|
R7 = check_mod(R7,dx_sand)
|
|
|
|
|
|
Hsand_coords_x = np.zeros(shape=[Q6])
|
|
Hsand_coords_y = np.zeros(shape=[Q7])
|
|
|
|
Hsand_coords_x[0] = soil_nrthside_th + conc_th + XPS_th + no_pwr + dx_sand/2 + R6
|
|
Hsand_coords_y[0] = soil_th + conc_th + XPS_th + no_pwr + dx_sand/2 + R7
|
|
|
|
#remainder of nodes
|
|
for i in range(1,Q6):
|
|
Hsand_coords_x[i] = Hsand_coords_x[i-1] + dx_sand
|
|
|
|
for j in range(1,Q7):
|
|
Hsand_coords_y[(j)] = Hsand_coords_y[(j-1)] + dx_sand
|
|
|
|
|
|
#%%%% SAND NO-POWER ZONE COORDS (south and east sides)
|
|
#============================================================
|
|
#1st no_pwr node on south and east sides
|
|
Hnopwr_coords_s[0] = soil_nrthside_th + conc_th + XPS_th + sand_L - no_pwr + Q5/2
|
|
Hnopwr_coords_e[0] = soil_th + conc_th + XPS_th + sand_W - no_pwr + Q5/2
|
|
|
|
#remainder of nodes on south and east sides
|
|
for i in range(1,nodes_no_pwr):
|
|
Hnopwr_coords_s[i] = Hnopwr_coords_s[i-1] + Q5
|
|
Hnopwr_coords_e[i] = Hnopwr_coords_e[i-1] + Q5
|
|
|
|
|
|
#%%%% PUTTING X- AND Y- MESH COORDINATES VECTORS TOGETHER
|
|
#============================================================
|
|
node_xcoords = np.concatenate((Hsoil_coords_n,Hconc_coords_n,HXPS_coords_n,Hnopwr_coords_n,Hsand_coords_x,Hnopwr_coords_s,HXPS_coords_s,Hconc_coords_s,Hsoil_coords_s))
|
|
|
|
node_ycoords = np.concatenate((Hsoil_coords_w,Hconc_coords_w,HXPS_coords_w,Hnopwr_coords_w,Hsand_coords_y,Hnopwr_coords_e,HXPS_coords_e,Hconc_coords_e,Hsoil_coords_e))
|
|
|
|
|
|
#%%% Vertical Coordinate Vectors
|
|
#%%%% SOIL COORDS
|
|
|
|
'''
|
|
#Reminder:
|
|
#number of nodes in coarser soil grid = Q1
|
|
#remainder of coarse soil length needing to be accounted for = R1
|
|
|
|
#number of nodes in fine soil grid = Q2
|
|
#remainder of fine soil length needing to be accounted for = R2
|
|
'''
|
|
|
|
#SUBVECTOR in which to put Z-COORDINATES OF BOTTOM SOIL NODES
|
|
#--------------------------------------------------
|
|
Vsoil_coords_b = np.zeros(shape=[1+Q1+Q2])
|
|
|
|
#far-field bottom boundary z=0 m
|
|
Vsoil_coords_b[0] = 0
|
|
#1st node's z-coordinate, in metres:
|
|
Vsoil_coords_b[1] = (dx_soil/2) + R1 + R2
|
|
#starting at index 3, coarse nodes' z-coordinates in metres
|
|
for i in range(2,(1+Q1)):
|
|
Vsoil_coords_b[i] = Vsoil_coords_b[i-1] + dx_soil
|
|
|
|
#1st node in fine grid area:
|
|
i = i+1
|
|
Vsoil_coords_b[i] = Vsoil_coords_b[i-1] + dx_soil/2 + dx_soilconc_boundary/2
|
|
i = i+1
|
|
#fine nodes' z-coordinates in metres
|
|
for i in range(i,len(Vsoil_coords_b)):
|
|
Vsoil_coords_b[i] = Vsoil_coords_b[i-1] + dx_soilconc_boundary
|
|
|
|
|
|
|
|
#SUBVECTOR in which to put Z-COORDINATES OF TOP SOIL NODES
|
|
#--------------------------------------------------
|
|
#number of nodes in coarser soil grid
|
|
Q8 = math.floor((soil_top_th - soilconc_boundary_th)/dz_soil_top)
|
|
#remainder of coarse soil length needing to be accounted for
|
|
R8 = (soil_top_th - soilconc_boundary_th) % dz_soil_top
|
|
|
|
Vsoil_coords_t = np.zeros(shape=[1+Q8+Q2])
|
|
|
|
Vsoil_coords_t[0] = soil_th + conc_th + XPS_th*2 + sand_H + dx_soilconc_boundary/2
|
|
#fine nodes' z-coordinates in metres
|
|
for i in range(1,Q2):
|
|
Vsoil_coords_t[i] = Vsoil_coords_t[i-1] + dx_soilconc_boundary
|
|
|
|
#1st node in coarse grid area:
|
|
i = i+1
|
|
Vsoil_coords_t[i] = Vsoil_coords_t[i-1] + dz_soil_top/2 + dx_soilconc_boundary/2
|
|
i = i+1
|
|
#coarse nodes' z-coordinates in metres
|
|
for i in range(i,len(Vsoil_coords_t)-1):
|
|
Vsoil_coords_t[i] = Vsoil_coords_t[i-1] + dz_soil_top
|
|
|
|
#far-field south boundary x=domain_L
|
|
Vsoil_coords_t[len(Vsoil_coords_t)-1] = domain_H
|
|
|
|
|
|
#%%%% CONCRETE COORDS
|
|
#============================================================
|
|
Vconc_coords_b = np.zeros(shape=[nodes_conc])
|
|
|
|
#dx for concrete = Q3:
|
|
#remainder of concrete length needing to be accounted for = R3
|
|
|
|
#1st conc node
|
|
Vconc_coords_b[0] = soil_th + Q3/2 + R3
|
|
|
|
#remainder of nodes
|
|
for i in range(1,nodes_conc):
|
|
Vconc_coords_b[i] = Vconc_coords_b[i-1] + Q3
|
|
|
|
|
|
#%%%% XPS COORDS
|
|
#============================================================
|
|
VXPS_coords_b = np.zeros(shape=[nodes_XPS])
|
|
VXPS_coords_t = np.zeros(shape=[nodes_XPS])
|
|
|
|
#dx for XPS = Q4
|
|
#remainder of XPS length needing to be accounted for = R4
|
|
|
|
#1st XPS node
|
|
VXPS_coords_b[0] = soil_th + conc_th + Q4/2 + R4
|
|
VXPS_coords_t[0] = soil_th + conc_th + XPS_th + sand_H + Q4/2
|
|
|
|
#remainder of nodes
|
|
for i in range(1,nodes_XPS):
|
|
VXPS_coords_b[i] = VXPS_coords_b[i-1] + Q4
|
|
VXPS_coords_t[i] = VXPS_coords_t[i-1] + Q4
|
|
|
|
|
|
#%%%% SAND COORDS
|
|
#============================================================
|
|
#dz in space in between pwr_bott layer and bottom of sand store (not including the three nodes around the pwr_bott layer)
|
|
dz1 = (pwr_bott - (dz_pwr_th + dz_pwr_th/2))/nodes_dz1_sand
|
|
#initialize vector
|
|
Vsand1 = np.zeros(shape=[nodes_dz1_sand+3])
|
|
#1st node coordinate
|
|
Vsand1[0] = soil_th + conc_th + XPS_th + dz1/2
|
|
#remainder of nodes
|
|
for i in range(1,nodes_dz1_sand):
|
|
Vsand1[i] = Vsand1[i-1] + dz1
|
|
|
|
#1st node in "3-node pwr layer"
|
|
i = i+1
|
|
Vsand1[i] = Vsand1[i-1] + dz1/2 + dz_pwr_th/2
|
|
i = i+1
|
|
#remainder of nodes in "3-node pwr layer"
|
|
for i in range(i,len(Vsand1)):
|
|
Vsand1[i] = Vsand1[i-1] + dz_pwr_th
|
|
|
|
|
|
#*********
|
|
|
|
#dz in space #number of nodes in between pwr_mid layer and pwr_bott layer (not including the three nodes around each pwr layer)
|
|
dz2 = ((pwr_mid - (dz_pwr_th + dz_pwr_th/2)) - (pwr_bott + (dz_pwr_th + dz_pwr_th/2)))/nodes_dz2_sand
|
|
#initialize vector
|
|
Vsand2 = np.zeros(shape=[nodes_dz2_sand+3])
|
|
#1st node coordinate
|
|
Vsand2[0] = soil_th + conc_th + XPS_th + pwr_bott + (dz_pwr_th + dz_pwr_th/2) + dz2/2
|
|
#remainder of nodes
|
|
for i in range(1,nodes_dz2_sand):
|
|
Vsand2[i] = Vsand2[i-1] + dz2
|
|
|
|
#1st node in "3-node pwr layer"
|
|
i = i+1
|
|
Vsand2[i] = Vsand2[i-1] + dz2/2 + dz_pwr_th/2
|
|
i = i+1
|
|
#remainder of nodes in "3-node pwr layer"
|
|
for i in range(i,len(Vsand2)):
|
|
Vsand2[i] = Vsand2[i-1] + dz_pwr_th
|
|
|
|
|
|
#*********
|
|
|
|
#dz in space #number of nodes in between pwr_upr layer and pwr_mid layer (not including the three nodes around each pwr layer)
|
|
dz3 = ((pwr_upr - (dz_pwr_th + dz_pwr_th/2)) - (pwr_mid + (dz_pwr_th + dz_pwr_th/2)))/nodes_dz3_sand
|
|
#initialize vector
|
|
Vsand3 = np.zeros(shape=[nodes_dz3_sand+3])
|
|
#1st node coordinate
|
|
Vsand3[0] = soil_th + conc_th + XPS_th + pwr_mid + (dz_pwr_th + dz_pwr_th/2) + dz3/2
|
|
#remainder of nodes
|
|
for i in range(1,nodes_dz3_sand):
|
|
Vsand3[i] = Vsand3[i-1] + dz3
|
|
|
|
|
|
#1st node in "3-node pwr layer"
|
|
i = i+1
|
|
Vsand3[i] = Vsand3[i-1] + dz3/2 + dz_pwr_th/2
|
|
i = i+1
|
|
#remainder of nodes in "3-node pwr layer"
|
|
for i in range(i,len(Vsand3)):
|
|
Vsand3[i] = Vsand3[i-1] + dz_pwr_th
|
|
|
|
|
|
#*********
|
|
|
|
#dz in space #number of nodes in between pwr_upr layer and pwr_mid layer (not including the three nodes around each pwr layer)
|
|
dz4 = (sand_H - (pwr_upr + (dz_pwr_th + dz_pwr_th/2)))/nodes_dz4_sand
|
|
#initialize vector
|
|
Vsand4 = np.zeros(shape=[nodes_dz4_sand])
|
|
#1st node coordinate
|
|
Vsand4[0] = soil_th + conc_th + XPS_th + pwr_upr + (dz_pwr_th + dz_pwr_th/2) + dz4/2
|
|
#remainder of nodes
|
|
for i in range(1,nodes_dz4_sand):
|
|
Vsand4[i] = Vsand4[i-1] + dz4
|
|
|
|
|
|
|
|
#%%%% PUTTING Z- COORDINATE VECTORS TOGETHER
|
|
#============================================================
|
|
node_zcoords = np.concatenate((Vsoil_coords_b,Vconc_coords_b,VXPS_coords_b,Vsand1,Vsand2,Vsand3,Vsand4,VXPS_coords_t,Vsoil_coords_t))
|
|
# figure
|
|
# plot(ones(length(node_zcoords),1),node_zcoords,'o')
|
|
|
|
|
|
#%%% Print out mesh size spacing to screen
|
|
#------------------------------------------------------------------------
|
|
print('------------')
|
|
print('MESH SIZING:')
|
|
print('------------')
|
|
print('Soil(coarse) dx,dy,dz =',dx_soil, 'm')
|
|
print('Soil(fine) dx,dy,dz =',dx_soilconc_boundary, 'm on',soilconc_boundary_th, 'm')
|
|
print('Concrete dx,dy,dz =',Q3, 'm')
|
|
print('XPS dx,dy,dz =',Q4, 'm')
|
|
print('Sand (no power zone) dx =',Q5, 'm')
|
|
print('Sand (power zone) dx,dy =',dx_sand, 'm\n')
|
|
|
|
print('Sand dz on 0 m < z <',pwr_bott,'m of sand store =',"%.2f" % dz1, 'm')
|
|
print('Sand dz on ',pwr_bott,'m < z <',pwr_mid,'m of sand store =',"%.2f" % dz2, 'm')
|
|
print('Sand dz on ',pwr_mid,'m < z <',pwr_upr,'m of sand store =',"%.2f" % dz3, 'm')
|
|
print('Sand dz on ',pwr_upr,'m < z <',sand_H,'m of sand store =',"%.2f" % dz4, 'm')
|
|
|
|
|
|
#%%%VERTICAL index boundaries (6 layers)
|
|
indx_bndrz_z = np.array([0, #bottom soil
|
|
len(Vsoil_coords_b)-1, #bottom soil
|
|
len(Vsoil_coords_b), #bottom conc
|
|
len(Vsoil_coords_b)+len(Vconc_coords_b)-1, #bottom conc
|
|
len(Vsoil_coords_b)+len(Vconc_coords_b), #bottom XPS
|
|
len(Vsoil_coords_b)+len(Vconc_coords_b)+len(VXPS_coords_b)-1, #bottom XPS
|
|
len(Vsoil_coords_b)+len(Vconc_coords_b)+len(VXPS_coords_b), #sand
|
|
len(Vsoil_coords_b)+len(Vconc_coords_b)+len(VXPS_coords_b)+len(Vsand1)+len(Vsand2)+len(Vsand3)+len(Vsand4)-1, #sand
|
|
len(Vsoil_coords_b)+len(Vconc_coords_b)+len(VXPS_coords_b)+len(Vsand1)+len(Vsand2)+len(Vsand3)+len(Vsand4), #top XPS
|
|
len(Vsoil_coords_b)+len(Vconc_coords_b)+len(VXPS_coords_b)+len(Vsand1)+len(Vsand2)+len(Vsand3)+len(Vsand4)+len(VXPS_coords_t)-1,#top XPS
|
|
len(Vsoil_coords_b)+len(Vconc_coords_b)+len(VXPS_coords_b)+len(Vsand1)+len(Vsand2)+len(Vsand3)+len(Vsand4)+len(VXPS_coords_t),#top soil
|
|
len(node_zcoords)-1])#top soil
|
|
|
|
#Indices for the top node (inclusive) of each "moisture layer boundary"...appx middle points between moisture sensor z-coordinates
|
|
moisture_layer_height = np.zeros(shape=[3], dtype=int)
|
|
moisture_layer_height[0] = int(len(Vsoil_coords_b)+len(Vconc_coords_b)+len(VXPS_coords_b)+len(Vsand1)+ math.floor(nodes_dz2_sand/2) - 1) # -1 to acct for zero-based arrays
|
|
moisture_layer_height[1] = int(len(Vsoil_coords_b)+len(Vconc_coords_b)+len(VXPS_coords_b)+len(Vsand1)+len(Vsand2)+math.floor(nodes_dz3_sand/2) - 1) # -1 to acct for zero-based arrays
|
|
moisture_layer_height[2] = int(indx_bndrz_z[7])
|
|
|
|
vol_slab = (sand_L - 2*no_pwr)*(sand_W - 2*no_pwr)*dz_pwr_th #(m3) volume of each power source slab
|
|
|
|
#Define number of nodes in each direction in numerical model domain
|
|
|
|
U = len(node_xcoords) #number of nodes in x-direction
|
|
V = len(node_ycoords) #number of nodes in y-direction
|
|
W = len(node_zcoords) #number of nodes in z-direction
|
|
|
|
|
|
pwr_bott_indx = indx_bndrz_z[5] + nodes_dz1_sand + 2 #[m] k-index for bottom layer of PEX tubing
|
|
pwr_mid_indx = indx_bndrz_z[5] + len(Vsand1) + nodes_dz2_sand + 2 #[m] k-index for middle layer of PEX tubing
|
|
pwr_upr_indx = indx_bndrz_z[5] + len(Vsand1) + len(Vsand2) + nodes_dz3_sand + 2 #[m] k-index for top layer of PEX tubing
|
|
|
|
#%%%HORIZONTAL index boundaries [9 layers]
|
|
indx_bndrz_x = np.array([0, #north soil
|
|
len(Hsoil_coords_n)-1, #north soil
|
|
len(Hsoil_coords_n), #north conc
|
|
len(Hsoil_coords_n)+len(Hconc_coords_n)-1, #north conc
|
|
len(Hsoil_coords_n)+len(Hconc_coords_n), #north XPS
|
|
len(Hsoil_coords_n)+len(Hconc_coords_n)+len(HXPS_coords_n)-1, #north XPS
|
|
len(Hsoil_coords_n)+len(Hconc_coords_n)+len(HXPS_coords_n), #north sand no power
|
|
len(Hsoil_coords_n)+len(Hconc_coords_n)+len(HXPS_coords_n)+len(Hnopwr_coords_n)-1, #north sand no power
|
|
len(Hsoil_coords_n)+len(Hconc_coords_n)+len(HXPS_coords_n)+len(Hnopwr_coords_n), #sand
|
|
len(Hsoil_coords_n)+len(Hconc_coords_n)+len(HXPS_coords_n)+
|
|
len(Hnopwr_coords_n)+len(Hsand_coords_x)-1,#sand
|
|
len(Hsoil_coords_n)+len(Hconc_coords_n)+len(HXPS_coords_n)+
|
|
len(Hnopwr_coords_n)+len(Hsand_coords_x), #south sand no pwr
|
|
len(Hsoil_coords_n)+len(Hconc_coords_n)+len(HXPS_coords_n)+
|
|
len(Hnopwr_coords_n)+len(Hsand_coords_x)+len(Hnopwr_coords_s)-1, #south sand no pwr
|
|
len(Hsoil_coords_n)+len(Hconc_coords_n)+len(HXPS_coords_n)+
|
|
len(Hnopwr_coords_n)+len(Hsand_coords_x)+len(Hnopwr_coords_s), #south XPS
|
|
len(Hsoil_coords_n)+len(Hconc_coords_n)+len(HXPS_coords_n)+
|
|
len(Hnopwr_coords_n)+len(Hsand_coords_x)+len(Hnopwr_coords_s)+
|
|
len(HXPS_coords_s)-1, #south XPS
|
|
len(Hsoil_coords_n)+len(Hconc_coords_n)+len(HXPS_coords_n)+
|
|
len(Hnopwr_coords_n)+len(Hsand_coords_x)+len(Hnopwr_coords_s)+
|
|
len(HXPS_coords_s), #south conc
|
|
len(Hsoil_coords_n)+len(Hconc_coords_n)+len(HXPS_coords_n)+
|
|
len(Hnopwr_coords_n)+len(Hsand_coords_x)+len(Hnopwr_coords_s)+
|
|
len(HXPS_coords_s)+len(Hconc_coords_s)-1, #south conc
|
|
len(Hsoil_coords_n)+len(Hconc_coords_n)+len(HXPS_coords_n)+
|
|
len(Hnopwr_coords_n)+len(Hsand_coords_x)+len(Hnopwr_coords_s)+
|
|
len(HXPS_coords_s)+len(Hconc_coords_s), #south soil
|
|
len(node_xcoords)-1]) #south soil
|
|
|
|
|
|
indx_bndrz_y = np.array([0, #west soil
|
|
len(Hsoil_coords_w)-1, #west soil
|
|
len(Hsoil_coords_w), #west conc
|
|
len(Hsoil_coords_w)+len(Hconc_coords_w)-1, #west conc
|
|
len(Hsoil_coords_w)+len(Hconc_coords_w), #west XPS
|
|
len(Hsoil_coords_w)+len(Hconc_coords_w)+len(HXPS_coords_w)-1, #west XPS
|
|
len(Hsoil_coords_w)+len(Hconc_coords_w)+len(HXPS_coords_w), #west sand no power
|
|
len(Hsoil_coords_w)+len(Hconc_coords_w)+len(HXPS_coords_w)+len(Hnopwr_coords_w)-1, #west sand no power
|
|
len(Hsoil_coords_w)+len(Hconc_coords_w)+len(HXPS_coords_w)+
|
|
len(Hnopwr_coords_w), #sand
|
|
len(Hsoil_coords_w)+len(Hconc_coords_w)+len(HXPS_coords_w)+
|
|
len(Hnopwr_coords_w)+len(Hsand_coords_y)-1,#sand
|
|
len(Hsoil_coords_w)+len(Hconc_coords_w)+len(HXPS_coords_w)+
|
|
len(Hnopwr_coords_w)+len(Hsand_coords_y), #east sand no pwr
|
|
len(Hsoil_coords_w)+len(Hconc_coords_w)+len(HXPS_coords_w)+
|
|
len(Hnopwr_coords_w)+len(Hsand_coords_y)+len(Hnopwr_coords_e)-1, #east sand no pwr
|
|
len(Hsoil_coords_w)+len(Hconc_coords_w)+len(HXPS_coords_w)+
|
|
len(Hnopwr_coords_w)+len(Hsand_coords_y)+len(Hnopwr_coords_e), #east XPS
|
|
len(Hsoil_coords_w)+len(Hconc_coords_w)+len(HXPS_coords_w)+
|
|
len(Hnopwr_coords_w)+len(Hsand_coords_y)+len(Hnopwr_coords_e)+
|
|
len(HXPS_coords_e)-1, #east XPS
|
|
len(Hsoil_coords_w)+len(Hconc_coords_w)+len(HXPS_coords_w)+
|
|
len(Hnopwr_coords_w)+len(Hsand_coords_y)+len(Hnopwr_coords_e)+
|
|
len(HXPS_coords_e), #east conc
|
|
len(Hsoil_coords_w)+len(Hconc_coords_w)+len(HXPS_coords_w)+
|
|
len(Hnopwr_coords_w)+len(Hsand_coords_y)+len(Hnopwr_coords_e)+
|
|
len(HXPS_coords_e)+len(Hconc_coords_e)-1, #east conc
|
|
len(Hsoil_coords_w)+len(Hconc_coords_w)+len(HXPS_coords_w)+
|
|
len(Hnopwr_coords_w)+len(Hsand_coords_y)+len(Hnopwr_coords_e)+
|
|
len(HXPS_coords_e)+len(Hconc_coords_e), #east soil
|
|
len(node_ycoords)-1]) #east soil
|
|
|
|
|
|
#%%%Indices for points within the "power slab" in the x-y plane
|
|
x_pwr_low_indx = indx_bndrz_x[8] #inclusive of this index
|
|
x_pwr_high_indx = indx_bndrz_x[9]#inclusive of this index
|
|
y_pwr_low_indx = indx_bndrz_y[8] #inclusive of this index
|
|
y_pwr_high_indx = indx_bndrz_y[9]#inclusive of this index
|
|
|
|
#============================================================
|
|
#%%%Vectors with CARTESIAN COORDS OF LAYER BOUNDARIES
|
|
#north-south
|
|
N_S_layr_bounds = np.array([0, #north boundary
|
|
soil_nrthside_th, #soil/conc
|
|
soil_nrthside_th + conc_th, #conc/XPS
|
|
soil_nrthside_th + conc_th + XPS_th , #XPS/sand
|
|
soil_nrthside_th + conc_th + XPS_th + sand_L, #sand/XPS
|
|
soil_nrthside_th + conc_th + XPS_th*2 + sand_L, #XPS/conc
|
|
soil_nrthside_th + conc_th*2 + XPS_th*2 + sand_L,#conc/soil
|
|
soil_nrthside_th + conc_th*2 + XPS_th*2 + sand_L + soil_th]) #south boundary
|
|
|
|
|
|
#west-east
|
|
W_E_layr_bounds =np.array([0, #west boundary
|
|
soil_th, #soil/conc
|
|
soil_th + conc_th, #conc/XPS
|
|
soil_th + conc_th + XPS_th , #XPS/sand
|
|
soil_th + conc_th + XPS_th + sand_W, #sand/XPS
|
|
soil_th + conc_th + XPS_th*2 + sand_W, #XPS/conc
|
|
soil_th + conc_th*2 + XPS_th*2 + sand_W,#conc/soil
|
|
soil_th*2 + conc_th*2 + XPS_th*2 + sand_W]) #east boundary
|
|
|
|
#bottom-top
|
|
B_T_layr_bounds =np.array([0, #bottom boundary
|
|
soil_th, #soil/conc
|
|
soil_th + conc_th, #conc/XPS
|
|
soil_th + conc_th + XPS_th , #XPS/sand
|
|
soil_th + conc_th + XPS_th + sand_H, #sand/XPS
|
|
soil_th + conc_th + XPS_th*2 + sand_H, #XPS/soil
|
|
soil_th + conc_th + XPS_th*2 + sand_H + soil_top_th]) #top boundary
|
|
|
|
#============================================================
|
|
#%%%Vectors holding the x and y coordinates of the TCs in the sand store
|
|
TC_xcoords = np.zeros(shape=[6])
|
|
TC_ycoords = np.zeros(shape=[6])
|
|
|
|
TC_xcoords[0] = soil_nrthside_th + conc_th + XPS_th + no_TC
|
|
TC_ycoords[0] = soil_th + conc_th + XPS_th + no_TC
|
|
|
|
for i in range(1,6):
|
|
TC_xcoords[i] = TC_xcoords[i-1] + node_space
|
|
TC_ycoords[i] = TC_ycoords[i-1] + node_space
|
|
|
|
|
|
#Find the indices of the TC locations
|
|
sand_TC_node_xindices = np.zeros(shape=[6], dtype=int)
|
|
|
|
for TC in range(0,6):
|
|
diff = 0
|
|
prev = 100
|
|
for i in range(0,len(node_xcoords)):
|
|
diff = abs(TC_xcoords[TC] - node_xcoords[i])
|
|
#this finds the closest nodes to the real locations of the TCs
|
|
if round(diff,5) >= round(prev,5):
|
|
#then we want the index represented by [i-1]
|
|
sand_TC_node_xindices[TC] = i-1
|
|
break
|
|
prev = diff
|
|
|
|
|
|
sand_TC_node_yindices = np.zeros(shape=[6], dtype=int)
|
|
|
|
for TC in range(0,6):
|
|
diff = 0
|
|
prev = 100
|
|
for j in range(0,len(node_ycoords)):
|
|
diff = abs(TC_ycoords[TC] - node_ycoords[j])
|
|
#this finds the closest nodes to the real locations of the TCs
|
|
if round(diff,5) >= round(prev,5):
|
|
#then we want the index represented by [j-1]
|
|
sand_TC_node_yindices[TC] = j-1
|
|
break
|
|
prev = diff
|
|
|
|
|
|
# %% 2. Material Thermal Properties
|
|
'''
|
|
This script defines the thermal properties of the materials used in the simulation and also builds the 3-D thermal property matrices for the simulation.
|
|
'''
|
|
#Properties of water
|
|
water_Cp = 4.186*1e3 # (J/kgK) specific heat for water
|
|
water_rho = 998.2 # (kg/m3) density for water at 293 K https://hypertextbook.com/facts/2007/AllenMa.shtml
|
|
|
|
#Properties of dry sand -> also used Hamdhan and Clarke (2010) as a reference
|
|
drySand_Cp = 830 #(J/kgK) specific heat for dry sand https://www.engineeringtoolbox.com/specific-heat-capacity-d_391.html
|
|
drySand_rho = 1850 #(kg/m3) density for dry sand (personal correspondence with Abdulghader Abdulrahman, Research Manager, Dr.Paul Simms' lab)
|
|
|
|
#volume percents of water layers in sand store
|
|
vol_percent = np.zeros(shape=[3])
|
|
vol_percent[0] = diff_runs['vol% bott'][run_num] #bottom layer = 33 vol#
|
|
vol_percent[1] = diff_runs['vol% mid'][run_num] #middle layer = 11 vol#
|
|
vol_percent[2] = diff_runs['vol% top'][run_num] #top layer = 7 vol#
|
|
|
|
sand_lambda = np.zeros(shape=[3])
|
|
sand_lambda[0] = diff_runs['λ_bott'][run_num] #(W/mK) bottom layer - thermal conductivity for saturated sand F. Rad (2009)
|
|
sand_lambda[1] = diff_runs['λ_mid'][run_num] #(W/mK) middle layer - moist sand https://www.engineeringtoolbox.com/thermal-conductivity-d_429.html
|
|
sand_lambda[2] = diff_runs['λ_top'][run_num] #(W/mK) top layer - moist sand https://www.engineeringtoolbox.com/thermal-conductivity-d_429.html
|
|
|
|
#Properties of concrete at 300 K (Source - Incropera, 6e, p.939)
|
|
conc_Cp = 880 #(J/kgK) specific heat
|
|
conc_rho = 2300 # (kg/m3) density
|
|
conc_lambda = 1.4 #(W/mK) thermal conductivity
|
|
|
|
#Properties of XPS at 297 K(Source - Owens Corning data sheets and papers - see ppt presentation MCG5157 final project for sources)
|
|
XPS_Cp_orig = 1500 #(J/kgK) specific heat source - article by BASF staff
|
|
XPS_rho_orig = 30 # (kg/m3) density
|
|
|
|
#Properties of XPS
|
|
vol_percent_H2O_SETface_XPS = diff_runs['SET(B) XPS Vol % H2O'][run_num]
|
|
XPS_lambda_SET = diff_runs['SET(B)'][run_num] #(W/mK) thermal conductivity
|
|
XPS_Cp_SET = ((water_Cp * (water_rho*vol_percent_H2O_SETface_XPS)) + (XPS_Cp_orig*XPS_rho_orig)) / (water_rho * vol_percent_H2O_SETface_XPS + XPS_rho_orig)
|
|
# (Number of Joules to raise sand in m3 by 1K + Joules to raise water in 1m3 by 1K) / (number of kg in 1m3)
|
|
XPS_rho_SET = water_rho * vol_percent_H2O_SETface_XPS + XPS_rho_orig
|
|
|
|
|
|
#Properties of soil (soil_rhoCp and soil_lambda) around CHEeR house sand
|
|
#store
|
|
soil_Cp = 750 #(J/kgK) (A. Wills MASc,Table 6.1)
|
|
soil_rho = 2800 #(kg/m3) (A. Wills MASc,Table 6.1)
|
|
soil_lambda = 2 #(W/mK) thermal conductivity (A. Wills MASc,Table 6.1) (TRY PARAMETRIZING FOR CLAY VALUES )
|
|
|
|
#%% 2. Print user inputs to screen:
|
|
print("\nCHECK THESE PARAMETERS \n")
|
|
print("Start and end dates: " + str(date_start) + " to " + str(date_end) + "\n")
|
|
print("Soil width surrounding sand store: " + str(soil_th) + " m and " + str(soil_nrthside_th) + " m \n")
|
|
print("Kusuda T_avg: " + str(T_avg) + " oC \n")
|
|
print("Kusuda ampl: " + str(ampl) + "\n")
|
|
|
|
|
|
#%% 2. Build matrices of thermal properties
|
|
# (from outside layers inwards)
|
|
|
|
#Initialize thermal property matrices
|
|
Lambda = np.zeros(shape=[U,V,W])
|
|
Cp = np.zeros(shape=[U,V,W])
|
|
rho = np.zeros(shape=[U,V,W])
|
|
|
|
#Soil layer - make entire matrix soil
|
|
Lambda[:,:,:] = soil_lambda
|
|
Cp[:,:,:] = soil_Cp
|
|
rho[:,:,:] = soil_rho
|
|
|
|
#Concrete layer
|
|
for k in range(indx_bndrz_z[2],indx_bndrz_z[9]+1):
|
|
for i in range(indx_bndrz_x[2],indx_bndrz_x[15]+1):
|
|
for j in range(indx_bndrz_y[2],indx_bndrz_y[15]+1):
|
|
Lambda[i,j,k] = conc_lambda
|
|
Cp[i,j,k] = conc_Cp
|
|
rho[i,j,k] = conc_rho
|
|
|
|
|
|
|
|
|
|
#Insulation layer
|
|
for k in range(indx_bndrz_z[4],indx_bndrz_z[9]+1):
|
|
for i in range(indx_bndrz_x[4],indx_bndrz_x[13]+1):
|
|
for j in range(indx_bndrz_y[4],indx_bndrz_y[13]+1):
|
|
Lambda[i,j,k] = XPS_lambda_SET
|
|
Cp[i,j,k] = XPS_Cp_SET
|
|
rho[i,j,k] = XPS_rho_SET
|
|
|
|
|
|
#North insulation layer
|
|
|
|
#volume percent of water layers in XPS north face
|
|
vpH20_NXPS = diff_runs['North XPS Vol % H2O'][run_num] # just an acronym of "vol_percent_H2O_Nface_XPS"; to make it easier to change values when face is homogeneous
|
|
vol_percent_H2O_Nface_XPS = [ vpH20_NXPS,vpH20_NXPS ,vpH20_NXPS ]
|
|
northXPS_lambda = diff_runs['North'][run_num]
|
|
# northXPS_lambda = [2, 2, 2]
|
|
|
|
#1st layer [bottom of insulation to ~halfway between first two PEX layers]
|
|
for k in range(indx_bndrz_z[4],moisture_layer_height[0]+1):
|
|
for i in range(indx_bndrz_x[4],indx_bndrz_x[5]+1):
|
|
for j in range(indx_bndrz_y[4],indx_bndrz_y[13]+1):
|
|
Lambda[i,j,k] = northXPS_lambda#[0]
|
|
Cp[i,j,k] = ((water_Cp * (water_rho*vol_percent_H2O_Nface_XPS[0])) + (XPS_Cp_orig*XPS_rho_orig)) / (water_rho * vol_percent_H2O_Nface_XPS[0] + XPS_rho_orig)
|
|
# (Number of Joules to raise sand in m3 by 1K + Joules to raise water in 1m3 by 1K) / (number of kg in 1m3)
|
|
rho[i,j,k] = water_rho * vol_percent_H2O_Nface_XPS[0] + XPS_rho_orig
|
|
|
|
#2nd layer [ of 1st layer to ~halfway between next two PEX layers]
|
|
for k in range((moisture_layer_height[0]+1),moisture_layer_height[1]+1):
|
|
for i in range(indx_bndrz_x[4],indx_bndrz_x[5]+1):
|
|
for j in range(indx_bndrz_y[4],indx_bndrz_y[13]+1):
|
|
Lambda[i,j,k] = northXPS_lambda#[1]
|
|
Cp[i,j,k] = ((water_Cp * (water_rho*vol_percent_H2O_Nface_XPS[1])) + (XPS_Cp_orig*XPS_rho_orig)) / (water_rho * vol_percent_H2O_Nface_XPS[1] + XPS_rho_orig)
|
|
rho[i,j,k] = water_rho * vol_percent_H2O_Nface_XPS[1] + XPS_rho_orig
|
|
|
|
#3rd layer [ of 2nd layer to top of insulation]
|
|
for k in range((moisture_layer_height[1]+1),indx_bndrz_z[9]+1):
|
|
for i in range(indx_bndrz_x[4],indx_bndrz_x[5]+1):
|
|
for j in range(indx_bndrz_y[4],indx_bndrz_y[13]+1):
|
|
Lambda[i,j,k] = northXPS_lambda#[2]
|
|
Cp[i,j,k] = ((water_Cp * (water_rho*vol_percent_H2O_Nface_XPS[2])) + (XPS_Cp_orig*XPS_rho_orig)) / (water_rho * vol_percent_H2O_Nface_XPS[2] + XPS_rho_orig)
|
|
rho[i,j,k] = water_rho * vol_percent_H2O_Nface_XPS[2] + XPS_rho_orig
|
|
|
|
|
|
#West insulation layer
|
|
|
|
#volume percent of water layers in XPS west face
|
|
vpH20_WXPS =diff_runs['West XPS Vol % H2O'][run_num] # just an acronym of "vol_percent_H2O_Nface_XPS"; to make it easier to change values when face is homogeneous
|
|
vol_percent_H2O_Wface_XPS = [ vpH20_WXPS, vpH20_WXPS, vpH20_WXPS ]
|
|
westXPS_lambda = diff_runs['West'][run_num]
|
|
# westXPS_lambda = [0.6, 0.6, 0.6]
|
|
|
|
#1st layer [bottom of insulation to ~halfway between first two PEX layers]
|
|
for k in range(indx_bndrz_z[4],moisture_layer_height[0]+1):
|
|
#this is starting at index 6 instead of 4 to not overwrite the properties already written in the North-face XPS section above
|
|
for i in range(indx_bndrz_x[6],indx_bndrz_x[13]+1):
|
|
for j in range(indx_bndrz_y[4],indx_bndrz_y[5]+1):
|
|
Lambda[i,j,k] = westXPS_lambda#[0]
|
|
Cp[i,j,k] = ((water_Cp * (water_rho*vol_percent_H2O_Wface_XPS[0])) + (XPS_Cp_orig*XPS_rho_orig)) / (water_rho * vol_percent_H2O_Wface_XPS[0] + XPS_rho_orig)
|
|
# (Number of Joules to raise sand in m3 by 1K + Joules to raise water in 1m3 by 1K) / (number of kg in 1m3)
|
|
rho[i,j,k] = water_rho * vol_percent_H2O_Wface_XPS[0] + XPS_rho_orig
|
|
|
|
#2nd layer [ of 1st layer to ~halfway between next two PEX layers]
|
|
for k in range((moisture_layer_height[0]+1),moisture_layer_height[1]+1):
|
|
for i in range(indx_bndrz_x[6],indx_bndrz_x[13]+1):
|
|
for j in range(indx_bndrz_y[4],indx_bndrz_y[5]+1):
|
|
Lambda[i,j,k] = westXPS_lambda#[1]
|
|
Cp[i,j,k] = ((water_Cp * (water_rho*vol_percent_H2O_Wface_XPS[1])) + (XPS_Cp_orig*XPS_rho_orig)) / (water_rho * vol_percent_H2O_Wface_XPS[1] + XPS_rho_orig)
|
|
rho[i,j,k] = water_rho * vol_percent_H2O_Wface_XPS[1] + XPS_rho_orig
|
|
|
|
#3rd layer [ of 2nd layer to top of insulation]
|
|
for k in range((moisture_layer_height[1]+1),indx_bndrz_z[9]+1):
|
|
for i in range(indx_bndrz_x[6],indx_bndrz_x[13]+1):
|
|
for j in range(indx_bndrz_y[4],indx_bndrz_y[5]+1):
|
|
Lambda[i,j,k] = westXPS_lambda#[2]
|
|
Cp[i,j,k] = ((water_Cp * (water_rho*vol_percent_H2O_Wface_XPS[2])) + (XPS_Cp_orig*XPS_rho_orig)) / (water_rho * vol_percent_H2O_Wface_XPS[2] + XPS_rho_orig)
|
|
rho[i,j,k] = water_rho * vol_percent_H2O_Wface_XPS[2] + XPS_rho_orig
|
|
|
|
#Bottom insulation layer
|
|
|
|
#volume percent of water layers in XPS west face
|
|
vpH20_BXPS = diff_runs['Bott XPS Vol % H2O'][run_num] # just an acronym of "vol_percent_H2O_Nface_XPS"; to make it easier to change values when face is homogeneous
|
|
vol_percent_H2O_Bface_XPS = [ vpH20_BXPS, vpH20_BXPS, vpH20_BXPS ]
|
|
bottomXPS_lambda = diff_runs['Bott'][run_num]
|
|
|
|
for k in range(indx_bndrz_z[4],indx_bndrz_z[5]+1):
|
|
#this is starting at index 6 instead of 4 to not overwrite the properties already written in the North-face XPS section above
|
|
for i in range(indx_bndrz_x[6],indx_bndrz_x[13]+1):
|
|
for j in range(indx_bndrz_y[6],indx_bndrz_y[13]+1):
|
|
Lambda[i,j,k] = bottomXPS_lambda#[0]
|
|
Cp[i,j,k] = ((water_Cp * (water_rho*vol_percent_H2O_Bface_XPS[0])) + (XPS_Cp_orig*XPS_rho_orig)) / (water_rho * vol_percent_H2O_Bface_XPS[0] + XPS_rho_orig)
|
|
# (Number of Joules to raise sand in m3 by 1K + Joules to raise water in 1m3 by 1K) / (number of kg in 1m3)
|
|
rho[i,j,k] = water_rho * vol_percent_H2O_Bface_XPS[0] + XPS_rho_orig
|
|
|
|
|
|
#-----------------------
|
|
|
|
#1st Sand layer [0m to ~halfway between first two PEX layers]
|
|
for k in range(indx_bndrz_z[6],moisture_layer_height[0]+1):
|
|
for i in range(indx_bndrz_x[6],indx_bndrz_x[11]+1):
|
|
for j in range(indx_bndrz_y[6],indx_bndrz_y[11]+1):
|
|
Lambda[i,j,k] = sand_lambda[0]
|
|
Cp[i,j,k] = ((water_Cp * (water_rho*vol_percent[0])) + (drySand_Cp*drySand_rho)) / (water_rho * vol_percent[0] + drySand_rho)
|
|
# (Number of Joules to raise sand in m3 by 1K + Joules to raise water in 1m3 by 1K) / (number of kg in 1m3)
|
|
rho[i,j,k] = water_rho * vol_percent[0] + drySand_rho
|
|
|
|
|
|
|
|
|
|
#2nd Sand layer [ of 1st layer to ~halfway between next two PEX layers]
|
|
for k in range((moisture_layer_height[0]+1),moisture_layer_height[1]+1):
|
|
for i in range(indx_bndrz_x[6],indx_bndrz_x[11]+1):
|
|
for j in range(indx_bndrz_y[6],indx_bndrz_y[11]+1):
|
|
Lambda[i,j,k] = sand_lambda[1]
|
|
Cp[i,j,k] = ((water_Cp * (water_rho*vol_percent[1])) + (drySand_Cp*drySand_rho)) / (water_rho * vol_percent[1] + drySand_rho)
|
|
rho[i,j,k] = water_rho * vol_percent[1] + drySand_rho
|
|
|
|
|
|
|
|
|
|
#3rd Sand layer [ of 2nd layer to top of sand store]
|
|
for k in range((moisture_layer_height[1]+1),moisture_layer_height[2]+1):
|
|
for i in range(indx_bndrz_x[6],indx_bndrz_x[11]+1):
|
|
for j in range(indx_bndrz_y[6],indx_bndrz_y[11]+1):
|
|
Lambda[i,j,k] = sand_lambda[2]
|
|
Cp[i,j,k] = ((water_Cp * (water_rho*vol_percent[2])) + (drySand_Cp*drySand_rho)) / (water_rho * vol_percent[2] + drySand_rho)
|
|
rho[i,j,k] = water_rho * vol_percent[2] + drySand_rho
|
|
|
|
# %% 2. Heat input to Sand Store
|
|
# %%% Process heat input data
|
|
|
|
#Put heat source data into a new numpy array
|
|
solar_to_Sand_W = Exp_heat_transfer_data[['time','sand_H2O']].copy().to_numpy()
|
|
|
|
#Specific rate of heat transfer (W/m3) to sand store per unit volume of power source slabs
|
|
sp_heat_trnsfr=np.array(solar_to_Sand_W[:,1],ndmin=2).transpose()/(3*vol_slab)
|
|
|
|
#append specific rate of heat transfer to array
|
|
solar_to_Sand_W = np.append(solar_to_Sand_W,sp_heat_trnsfr,axis=1)
|
|
|
|
#%%%% Check for missing data
|
|
if (solar_to_Sand_W.shape[0] < totTimeIntrvls):
|
|
|
|
#set boolean marker to True
|
|
missing_heat_data = True
|
|
#make new array with orig data
|
|
solar_to_Sand_W_orig_data = solar_to_Sand_W
|
|
#re-initialize solar_to_Sand_W array
|
|
solar_to_Sand_W = np.zeros(shape=(totTimeIntrvls,solar_to_Sand_W.shape[1]))
|
|
|
|
new=0 #initialize second counter variable for loop below
|
|
solar_to_Sand_W[0,0] = solar_to_Sand_W_orig_data[0,0] #copy first data point
|
|
|
|
for orig in range(0,solar_to_Sand_W_orig_data.shape[0]-1):
|
|
|
|
#check gaps between data points to not be not larger than 2 time step intervals (dt), try 1.5 intervals
|
|
#If gap is larger than 1.5*dt, fill in missing data
|
|
if (solar_to_Sand_W_orig_data[orig+1,0] - solar_to_Sand_W_orig_data[orig,0]) > (1.5*dt/3600):
|
|
#number of data points to add (fill in)
|
|
fill = round((solar_to_Sand_W_orig_data[orig+1,0] - solar_to_Sand_W_orig_data[orig,0])*3600/dt)
|
|
|
|
# print(solar_to_Sand_W_orig_data[orig+1,0],
|
|
# solar_to_Sand_W_orig_data[orig,0],
|
|
# (solar_to_Sand_W_orig_data[orig+1,0]- solar_to_Sand_W_orig_data[orig,0])*60,
|
|
# fill,
|
|
# new,
|
|
# orig,
|
|
# new-orig)
|
|
|
|
#fill the missing data with average of points on either side
|
|
for i in range(0,fill-1):
|
|
new = new + 1 #increment second counter variable
|
|
#first column data fill
|
|
solar_to_Sand_W[new,0] = solar_to_Sand_W[new-1,0] + (dt/3600)
|
|
#second column data fill
|
|
solar_to_Sand_W[new,1] = (solar_to_Sand_W_orig_data[orig+1,1] +
|
|
solar_to_Sand_W_orig_data[orig,1])/2
|
|
#third column data fill
|
|
solar_to_Sand_W[new,2] = (solar_to_Sand_W_orig_data[orig+1,2] +
|
|
solar_to_Sand_W_orig_data[orig,2])/2
|
|
|
|
#copy the data point on the "far side of the data gap" to the new array
|
|
solar_to_Sand_W[new+1,0] = solar_to_Sand_W_orig_data[orig+1,0]
|
|
solar_to_Sand_W[new+1,1] = solar_to_Sand_W_orig_data[orig+1,1]
|
|
solar_to_Sand_W[new+1,2] = solar_to_Sand_W_orig_data[orig+1,2]
|
|
|
|
else:
|
|
#copy original data over to new array
|
|
solar_to_Sand_W[new+1,0] = solar_to_Sand_W_orig_data[orig+1,0]
|
|
solar_to_Sand_W[new+1,1] = solar_to_Sand_W_orig_data[orig+1,1]
|
|
solar_to_Sand_W[new+1,2] = solar_to_Sand_W_orig_data[orig+1,2]
|
|
|
|
new = new + 1 #increment second counter variable (regardless of if data has been filled or not)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
print('*****************************************************************\n')
|
|
print('GAPS IN EXPERIMENTAL SAND STORE HEAT DATA - VERIFY solar_to_Sand_W AND solar_to_Sand_W_orig_data ARRAYS MAKE SENSE!!!!\n')
|
|
print('*****************************************************************\n\n')
|
|
|
|
else:
|
|
print('*****************************************************************\n')
|
|
print('NO MISSING SAND STORE HEAT DATA\n')
|
|
print('*****************************************************************\n\n')
|
|
|
|
|
|
# %% 2. Heat extracted from Sand Store
|
|
# %%% Process discharging data
|
|
|
|
#Put discharging data into a new numpy array
|
|
Sand_to_SH_W = Exp_heat_transfer_data[['time','sand_2_SH']].copy().to_numpy()
|
|
|
|
#Specific rate of heat extraction (W/m3) from sand store per unit volume of power source slabs
|
|
sp_heat_extr=np.array(Sand_to_SH_W[:,1],ndmin=2).transpose()/(3*vol_slab)
|
|
|
|
#append specific rate of heat extraction to array
|
|
Sand_to_SH_W = np.append(Sand_to_SH_W,sp_heat_extr,axis=1)
|
|
|
|
|
|
#%%%% Check for missing data
|
|
if (Sand_to_SH_W.shape[0] < totTimeIntrvls):
|
|
|
|
#set boolean marker to True
|
|
missing_heat_data = True
|
|
#make new array with orig data
|
|
Sand_to_SH_W_orig_data = Sand_to_SH_W
|
|
#re-initialize Sand_to_SH_W array
|
|
Sand_to_SH_W = np.zeros(shape=(totTimeIntrvls,Sand_to_SH_W.shape[1]))
|
|
|
|
new=0 #initialize second counter variable for loop below
|
|
Sand_to_SH_W[0,0] = Sand_to_SH_W_orig_data[0,0] #copy first data point
|
|
|
|
for orig in range(0,Sand_to_SH_W_orig_data.shape[0]-1):
|
|
|
|
#check gaps between data points to not be not larger than 2 time step intervals (dt), try 1.5 intervals
|
|
#If gap is larger than 1.5*dt, fill in missing data
|
|
if (Sand_to_SH_W_orig_data[orig+1,0] - Sand_to_SH_W_orig_data[orig,0]) > (1.5*dt/3600):
|
|
#number of data points to add (fill in)
|
|
|
|
fill = round((Sand_to_SH_W_orig_data[orig+1,0] - Sand_to_SH_W_orig_data[orig,0])*3600/dt)
|
|
|
|
#fill the missing data with average of points on either side
|
|
for i in range(0,fill-1):
|
|
new = new + 1 #increment second counter variable
|
|
#first column data fill
|
|
Sand_to_SH_W[new,0] = Sand_to_SH_W[new-1,0] + (dt/3600)
|
|
#second column data fill
|
|
Sand_to_SH_W[new,1] = (Sand_to_SH_W_orig_data[orig+1,1] +
|
|
Sand_to_SH_W_orig_data[orig,1])/2
|
|
#third column data fill
|
|
Sand_to_SH_W[new,2] = (Sand_to_SH_W_orig_data[orig+1,2] +
|
|
Sand_to_SH_W_orig_data[orig,2])/2
|
|
|
|
#copy the data point on the "far side of the data gap" to the new array
|
|
Sand_to_SH_W[new+1,0] = Sand_to_SH_W_orig_data[orig+1,0]
|
|
Sand_to_SH_W[new+1,1] = Sand_to_SH_W_orig_data[orig+1,1]
|
|
Sand_to_SH_W[new+1,2] = Sand_to_SH_W_orig_data[orig+1,2]
|
|
|
|
else:
|
|
#copy original data over to new array
|
|
Sand_to_SH_W[new+1,0] = Sand_to_SH_W_orig_data[orig+1,0]
|
|
Sand_to_SH_W[new+1,1] = Sand_to_SH_W_orig_data[orig+1,1]
|
|
Sand_to_SH_W[new+1,2] = Sand_to_SH_W_orig_data[orig+1,2]
|
|
|
|
new = new + 1 #increment second counter variable (regardless of if data has been filled or not)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
print('*****************************************************************\n')
|
|
print('GAPS IN EXPERIMENTAL SAND STORE HEAT EXTRACTION DATA - VERIFY solar_to_Sand_W AND solar_to_Sand_W_orig_data ARRAYS MAKE SENSE!!!!\n')
|
|
print('*****************************************************************\n\n')
|
|
|
|
else:
|
|
print('*****************************************************************\n')
|
|
print('NO MISSING SAND STORE HEAT EXTRACTION DATA\n')
|
|
print('*****************************************************************\n\n')
|
|
|
|
|
|
# %%2. Visualization Output Points
|
|
|
|
'''
|
|
This script is to get the nodes that I will record to visualize the data to check that the FD eqn is performing as expected
|
|
'''
|
|
|
|
#%%%1st SOIL LAYER - starting at y, or z = 0 (west or bottom)
|
|
#every 60 cm, including points
|
|
node_dist = 0.6 #(m)
|
|
soil_viz_indices = np.zeros(shape=[math.floor(soil_th/node_dist)+1], dtype=int)
|
|
|
|
soil_viz_indices[0] = 0
|
|
for indx in range(1,len(soil_viz_indices)):
|
|
prev = 100
|
|
for i in range(0,len(Hsoil_coords_w)):
|
|
diff = abs((indx)*node_dist - Hsoil_coords_w[i]) #diff = desired position - current index
|
|
#this finds the closest node to the desired position
|
|
if round(diff,5) >= round(prev,5):
|
|
#then we want the index represented by (i-1)
|
|
soil_viz_indices[indx] = i-1
|
|
break
|
|
#if next iteration would be outside the soil domain, put the last node in the soil domain there
|
|
elif i == (len(Hsoil_coords_w)-1):
|
|
soil_viz_indices[indx] = i
|
|
|
|
prev = diff
|
|
|
|
|
|
|
|
|
|
#%%%NORTH SOIL LAYER
|
|
soil_nrthside_viz_indices = np.zeros(shape=[math.floor(soil_nrthside_th/node_dist)+1], dtype=int)
|
|
|
|
soil_nrthside_viz_indices[0] = 0
|
|
for indx in range(1,len(soil_nrthside_viz_indices)):
|
|
prev = 100
|
|
for i in range(0,len(Hsoil_coords_n)):
|
|
diff = abs((indx)*node_dist - Hsoil_coords_n[i]) #diff = desired position - current index
|
|
#this finds the closest node to the desired position
|
|
if round(diff,5) >= round(prev,5):
|
|
#then we want the index represented by (i-1)
|
|
soil_nrthside_viz_indices[indx] = i-1
|
|
break
|
|
#if next iteration would be outside the soil domain, put the last node in the soil domain there
|
|
elif i == len(Hsoil_coords_n)-1:
|
|
soil_nrthside_viz_indices[indx] = i
|
|
|
|
prev = diff
|
|
|
|
|
|
|
|
|
|
#%%%EAST SOIL LAYER - ending at y = domain_W
|
|
soil_east_viz_indices = np.zeros(shape=[math.floor(soil_th/node_dist)+1], dtype=int)
|
|
soil_east_viz_indices[-1] = indx_bndrz_y[-1] #last index in east soil
|
|
c = 0
|
|
for indx in range(len(soil_east_viz_indices)-2,-1,-1):
|
|
prev = 100
|
|
c = c+1
|
|
d = 0
|
|
for i in range(len(Hsoil_coords_e)-1,-1,-1):
|
|
d = d+1
|
|
diff = abs((W_E_layr_bounds[-1] - c*node_dist) - Hsoil_coords_e[i-1]) #diff = desired position - current index
|
|
#this finds the closest node to the desired position
|
|
if round(diff,5) >= round(prev,5):
|
|
#then we want the index representing the previous node
|
|
soil_east_viz_indices[indx] = indx_bndrz_y[-1] - d +1
|
|
break
|
|
elif i == 1: #If it's at the end of the loop and nothing has been chosen, choose the last node
|
|
soil_east_viz_indices[indx] = indx_bndrz_y[-2]
|
|
|
|
prev = diff
|
|
|
|
|
|
|
|
#%%%SOUTH SOIL LAYER - ending at x = domain_L
|
|
soil_south_viz_indices = np.zeros(shape=[math.floor(soil_th/node_dist)+1], dtype=int)
|
|
soil_south_viz_indices[-1] = indx_bndrz_x[-1] #last index in south soil
|
|
c = 0
|
|
for indx in range(len(soil_south_viz_indices)-2,-1,-1):
|
|
prev = 100
|
|
c = c+1
|
|
d = 0
|
|
for i in range(len(Hsoil_coords_s)-1,-1,-1):
|
|
d = d+1
|
|
diff = abs((N_S_layr_bounds[-1] - c*node_dist) - Hsoil_coords_s[i-1]) #diff = desired position - current index
|
|
#this finds the closest node to the desired position
|
|
if round(diff,5) >= round(prev,5):
|
|
#then we want the index representing the previous node
|
|
soil_south_viz_indices[indx] = indx_bndrz_x[-1] - d +1
|
|
break
|
|
elif i == 1: #If it's at the end of the loop and nothing has been chosen, choose the last node
|
|
soil_south_viz_indices[indx] = indx_bndrz_x[-2]
|
|
|
|
prev = diff
|
|
|
|
|
|
|
|
#%%%TOP SOIL LAYER - ending at x = domain_H
|
|
#every 50 cm, including points
|
|
node_dist = 0.5 #(m)
|
|
soil_top_viz_indices = np.zeros(shape=[math.floor(soil_top_th/node_dist)+1], dtype=int)
|
|
c = 0
|
|
soil_top_viz_indices[-1] = indx_bndrz_z[-1] #last index in top soil
|
|
for indx in range(len(soil_top_viz_indices)-2,-1,-1):
|
|
c = c+1
|
|
d = 0
|
|
prev = 100
|
|
for i in range(len(Vsoil_coords_t)-1,-1,-1):
|
|
d = d+1
|
|
diff = abs((B_T_layr_bounds[-1] - c*node_dist) - Vsoil_coords_t[i-1]) #diff = desired position - current index
|
|
#this finds the closest node to the desired position
|
|
if round(diff,5) >= round(prev,5):
|
|
#then we want the index representing the previous node
|
|
soil_top_viz_indices[indx] = indx_bndrz_z[-1] - d+1
|
|
break
|
|
elif i == 1: #If it's at the end of the loop and nothing has been chosen, choose the last node
|
|
soil_top_viz_indices[indx] = indx_bndrz_z[-2]
|
|
|
|
prev = diff
|
|
|
|
|
|
|
|
#%%%1st CONCRETE LAYER (west or bottom)
|
|
|
|
if all_wall_layer_nodes==0:
|
|
#one node in concrete layer, closest to centre of layer
|
|
conc_wb_viz_index = 0
|
|
prev = 100
|
|
for i in range(0,len(Vconc_coords_b)):
|
|
diff = abs((W_E_layr_bounds[1]+W_E_layr_bounds[2])/2 - Vconc_coords_b[i])
|
|
#this finds the closest node to the desired position
|
|
if round(diff,5) >= round(prev,5):
|
|
#then we want the index representing the previous node
|
|
conc_wb_viz_index = indx_bndrz_y[2] + (i-1)
|
|
break
|
|
elif i == len(Vconc_coords_b)-1: #If it's at the end of the loop and nothing has been chosen, choose the last node
|
|
conc_wb_viz_index = indx_bndrz_y[3]
|
|
|
|
prev = diff
|
|
|
|
|
|
#%%%North CONCRETE LAYER
|
|
#one node in concrete layer, closest to centre of layer
|
|
conc_n_viz_index = 0
|
|
prev = 100
|
|
for i in range(0,len(Hconc_coords_n)):
|
|
diff = abs((N_S_layr_bounds[1]+N_S_layr_bounds[2])/2 - Hconc_coords_n[i])
|
|
#this finds the closest node to the desired position
|
|
if round(diff,5) >= round(prev,5):
|
|
#then we want the index representing the previous node
|
|
conc_n_viz_index = indx_bndrz_x[2] + (i-1)
|
|
break
|
|
elif i == len(Hconc_coords_n)-1: #If it's at the end of the loop and nothing has been chosen, choose the last node
|
|
conc_n_viz_index = indx_bndrz_x[3]
|
|
|
|
prev = diff
|
|
|
|
|
|
#%%%East CONCRETE LAYER
|
|
#one node in concrete layer, closest to centre of layer
|
|
conc_e_viz_index = 0
|
|
prev = 100
|
|
d=0
|
|
for i in range(len(Hconc_coords_e)-1,-1,-1):
|
|
d = d+1
|
|
diff = abs((W_E_layr_bounds[5]+W_E_layr_bounds[6])/2 - Hconc_coords_e[i])
|
|
#this finds the closest node to the desired position
|
|
if round(diff,5) >= round(prev,5):
|
|
#then we want the index representing the previous node
|
|
conc_e_viz_index = indx_bndrz_y[15] - d +2
|
|
break
|
|
elif i == 0: #If it's at the end of the loop and nothing has been chosen, choose the last node
|
|
conc_e_viz_index = indx_bndrz_y[14]
|
|
|
|
prev = diff
|
|
|
|
|
|
#%%%South CONCRETE LAYER
|
|
#one node in concrete layer, closest to centre of layer
|
|
conc_s_viz_index = 0
|
|
prev = 100
|
|
d=0
|
|
for i in range(len(Hconc_coords_s)-1,-1,-1):
|
|
d = d+1
|
|
diff = abs((N_S_layr_bounds[5]+N_S_layr_bounds[6])/2 - Hconc_coords_s[i])
|
|
#this finds the closest node to the desired position
|
|
if round(diff,5) >= round(prev,5):
|
|
#then we want the index representing the previous node
|
|
conc_s_viz_index = indx_bndrz_x[15] - d +2
|
|
break
|
|
elif i == 0: #If it's at the end of the loop and nothing has been chosen, choose the last node
|
|
conc_s_viz_index = indx_bndrz_x[14]
|
|
|
|
prev = diff
|
|
|
|
|
|
#%%%1st XPS LAYER
|
|
#one node in insulation layer, closest to centre of layer
|
|
XPS_wb_viz_index = 0
|
|
prev = 100
|
|
for i in range(0,len(VXPS_coords_b)):
|
|
diff = abs((W_E_layr_bounds[2]+W_E_layr_bounds[3])/2 - VXPS_coords_b[i])
|
|
#this finds the closest node to the desired position
|
|
if round(diff,5) >= round(prev,5):
|
|
#then we want the index representing the
|
|
XPS_wb_viz_index = indx_bndrz_y[4] + (i-1)
|
|
break
|
|
elif i == len(VXPS_coords_b)-1: #If it's at the end of the loop and nothing has been chosen, choose the last node
|
|
XPS_wb_viz_index = indx_bndrz_y[5]
|
|
|
|
prev = diff
|
|
|
|
|
|
#%%%North XPS LAYER
|
|
#one node in insulation layer, closest to centre of layer
|
|
XPS_n_viz_index = 0
|
|
prev = 100
|
|
for i in range(0,len(HXPS_coords_n)):
|
|
diff = abs((N_S_layr_bounds[2] + N_S_layr_bounds[3])/2 - HXPS_coords_n[i])
|
|
#this finds the closest node to the desired position
|
|
if round(diff,5) >= round(prev,5):
|
|
#then we want the index representing the
|
|
XPS_n_viz_index = indx_bndrz_x[4] + (i-1)
|
|
break
|
|
elif i == len(HXPS_coords_n)-1: #If it's at the end of the loop and nothing has been chosen, choose the last node
|
|
XPS_n_viz_index = indx_bndrz_x[5]
|
|
|
|
prev = diff
|
|
|
|
|
|
#%%%Top XPS LAYER
|
|
#one node in insulation layer, closest to centre of layer
|
|
XPS_t_viz_index = 0
|
|
prev = 100
|
|
d=0
|
|
for i in range(len(VXPS_coords_t)-1,-1,-1):
|
|
d=d+1
|
|
diff = abs((B_T_layr_bounds[4] + B_T_layr_bounds[5])/2 - VXPS_coords_t[i])
|
|
#this finds the closest node to the desired position
|
|
if round(diff,5) >= round(prev,5):
|
|
#then we want the index representing the previous node
|
|
XPS_t_viz_index = indx_bndrz_z[9] - d +2
|
|
break
|
|
elif i == 0: #If it's at the end of the loop and nothing has been chosen, choose the last node
|
|
XPS_t_viz_index = indx_bndrz_z[8]
|
|
|
|
prev = diff
|
|
|
|
|
|
#%%%East XPS LAYER
|
|
#one node in insulation layer, closest to centre of layer
|
|
XPS_e_viz_index = 0
|
|
prev = 100
|
|
d=0
|
|
for i in range(len(HXPS_coords_e)-1,-1,-1):
|
|
d=d+1
|
|
diff = abs((W_E_layr_bounds[4] + W_E_layr_bounds[5])/2 - HXPS_coords_e[i])
|
|
#this finds the closest node to the desired position
|
|
if round(diff,5) >= round(prev,5):
|
|
#then we want the index representing the previous node
|
|
XPS_e_viz_index = indx_bndrz_y[13] - d +2
|
|
break
|
|
elif i == 0: #If it's at the end of the loop and nothing has been chosen, choose the last node
|
|
XPS_e_viz_index = indx_bndrz_y[12]
|
|
|
|
prev = diff
|
|
|
|
|
|
#%%%South XPS LAYER
|
|
#one node in insulation layer, closest to centre of layer
|
|
XPS_s_viz_index = 0
|
|
prev = 100
|
|
d=0
|
|
for i in range(len(HXPS_coords_s)-1,-1,-1):
|
|
d=d+1
|
|
diff = abs((N_S_layr_bounds[4] + N_S_layr_bounds[5])/2 - HXPS_coords_s[i])
|
|
#this finds the closest node to the desired position
|
|
if round(diff,5) >= round(prev,5):
|
|
#then we want the index representing the previous node
|
|
XPS_s_viz_index = indx_bndrz_x[13] - d +2
|
|
break
|
|
elif i == 0: #If it's at the end of the loop and nothing has been chosen, choose the last node
|
|
XPS_s_viz_index = indx_bndrz_x[12]
|
|
|
|
prev = diff
|
|
|
|
|
|
#%%%East SAND "no power" node
|
|
#Find the indices that correspond to the nodes in the sand store in the no TC zone
|
|
sand_noTCe_viz_index = 0
|
|
prev = 100
|
|
d=0
|
|
for i in range(len(Hnopwr_coords_e)-1,-1,-1):
|
|
d=d+1
|
|
diff = abs((W_E_layr_bounds[4] + W_E_layr_bounds[4]-no_pwr)/2 - Hnopwr_coords_e[i])
|
|
#this finds the closest node to the desired position
|
|
if round(diff,5) >= round(prev,5):
|
|
#then we want the index representing the previous node
|
|
sand_noTCe_viz_index = indx_bndrz_y[11] - d + 2
|
|
break
|
|
elif i == 0: #If it's at the end of the loop and nothing has been chosen, choose the last node
|
|
sand_noTCe_viz_index = indx_bndrz_y[10]
|
|
|
|
prev = diff
|
|
|
|
|
|
#%%%South SAND "no power" node
|
|
#Find the indices that correspond to the nodes in the sand store in the no TC zone
|
|
sand_noTCs_viz_index = 0
|
|
prev = 100
|
|
d=0
|
|
for i in range(len(Hnopwr_coords_s)-1,-1,-1):
|
|
d=d+1
|
|
diff = abs((N_S_layr_bounds[4] + N_S_layr_bounds[4]-no_pwr)/2 - Hnopwr_coords_s[i])
|
|
#this finds the closest node to the desired position
|
|
if round(diff,5) >= round(prev,5):
|
|
#then we want the index representing the previous node
|
|
sand_noTCs_viz_index = indx_bndrz_x[11] - d + 2
|
|
break
|
|
elif i == 0: #If it's at the of the loop and nothing has been chosen, choose the last node
|
|
sand_noTCs_viz_index = indx_bndrz_x[10]
|
|
|
|
prev = diff
|
|
|
|
|
|
#%%%North SAND "no power" node
|
|
#Find the indices that correspond to the nodes in the sand store in the no TC zone
|
|
sand_noTCn_viz_index = 0
|
|
prev = 100
|
|
for i in range(0,len(Hnopwr_coords_n)):
|
|
diff = abs((N_S_layr_bounds[3] + N_S_layr_bounds[3]+no_pwr)/2 - Hnopwr_coords_n[i])
|
|
#this finds the closest node to the desired position
|
|
if round(diff,5) >= round(prev,5):
|
|
#then we want the index representing the
|
|
sand_noTCn_viz_index = indx_bndrz_x[6] + (i-1)
|
|
break
|
|
elif i == len(Hnopwr_coords_n)-1: #If it's at the of the loop and nothing has been chosen, choose the last node
|
|
sand_noTCn_viz_index = indx_bndrz_x[6]+ (i)
|
|
|
|
prev = diff
|
|
|
|
|
|
#%%%WEST SAND "no power" node
|
|
#Find the indices that correspond to the nodes in the sand store in the no TC zone
|
|
sand_noTCw_viz_index = 0
|
|
prev = 100
|
|
for i in range(0,len(Hnopwr_coords_w)):
|
|
diff = abs((W_E_layr_bounds[3] + W_E_layr_bounds[3]+no_pwr)/2 - Hnopwr_coords_w[i])
|
|
#this finds the closest node to the desired position
|
|
if round(diff,5) >= round(prev,5):
|
|
#then we want the index representing the
|
|
sand_noTCw_viz_index = indx_bndrz_y[6] + (i-1)
|
|
break
|
|
elif i == len(Hnopwr_coords_n)-1: #If it's at the of the loop and nothing has been chosen, choose the last node
|
|
sand_noTCw_viz_index = indx_bndrz_y[6]+ i
|
|
|
|
prev = diff
|
|
|
|
|
|
#%%%N-S SAND "power" nodes
|
|
node_dist = 0.5
|
|
sand_x_viz_indices = np.zeros(shape=[math.floor((sand_L-no_pwr*2)/node_dist) + 2], dtype=int)
|
|
#If the number of nodes to be visualized is the same as or greater than the number of FDE nodes...
|
|
if len(sand_x_viz_indices) >= len(Hsand_coords_x):
|
|
sand_x_viz_indices = np.zeros(shape=(len(Hsand_coords_x)), dtype=int)
|
|
sand_x_viz_indices[0] = indx_bndrz_x[8]
|
|
for i in range(1,len(sand_x_viz_indices)):
|
|
sand_x_viz_indices[i] = sand_x_viz_indices[i-1]+1
|
|
else:
|
|
prev = 100
|
|
sand_x_viz_indices[0] = indx_bndrz_x[8]
|
|
for indx in range(1,len(sand_x_viz_indices)):
|
|
prev = 100
|
|
for i in range(0,len(Hsand_coords_x)):
|
|
diff = abs(N_S_layr_bounds[3]+no_pwr + indx*node_dist - Hsand_coords_x[i]) #diff = desired position - current index
|
|
#this finds the closest node to the desired position
|
|
if round(diff,5) >= round(prev,5):
|
|
#then we want the index represented by (i-1)
|
|
sand_x_viz_indices[indx] = indx_bndrz_x[8]+ i-1
|
|
break
|
|
#if next iteration would be outside the soil domain, put the last node in the soil domain there
|
|
elif i == len(Hsand_coords_x)-1:
|
|
sand_x_viz_indices[indx] = indx_bndrz_x[9]
|
|
|
|
prev = diff
|
|
|
|
|
|
|
|
|
|
#%%%W-E SAND "power" nodes
|
|
sand_y_viz_indices = np.zeros(shape=[math.floor((sand_W-no_pwr*2)/node_dist) + 2], dtype=int)
|
|
#If the number of nodes to be visualized is the same as or greater than the number of FDE nodes...
|
|
if len(sand_y_viz_indices) >= len(Hsand_coords_y):
|
|
sand_y_viz_indices = np.zeros(shape=(len(Hsand_coords_y)), dtype=int)
|
|
sand_y_viz_indices[0] = indx_bndrz_y[8]
|
|
for i in range(1,len(sand_y_viz_indices)):
|
|
sand_y_viz_indices[i] = sand_y_viz_indices[i-1]+1
|
|
else:
|
|
prev = 100
|
|
sand_y_viz_indices[0] = indx_bndrz_y[8]
|
|
for indx in range(1,len(sand_y_viz_indices)):
|
|
prev = 100
|
|
for i in range(0,len(Hsand_coords_y)):
|
|
diff = abs(W_E_layr_bounds[3]+no_pwr + indx*node_dist - Hsand_coords_y[i]) #diff = desired position - current index
|
|
#this finds the closest node to the desired position
|
|
if round(diff,5) >= round(prev,5):
|
|
#then we want the index represented by (i-1)
|
|
sand_y_viz_indices[indx] = indx_bndrz_y[8]+ i-1
|
|
break
|
|
#if next iteration would be outside the soil domain, put the last node in the soil domain there
|
|
elif i == len(Hsand_coords_y)-1:
|
|
sand_y_viz_indices[indx] = indx_bndrz_y[9]
|
|
|
|
prev = diff
|
|
|
|
|
|
|
|
|
|
#%%%VERT SAND nodes
|
|
#for the nodes between the bottom of sand store and the "first power"
|
|
#layer,pick the one closest to centre
|
|
sand_z_viz_indices1 = 0
|
|
prev = 100
|
|
for i in range(0,len(Vsand1)-3):
|
|
diff = abs((B_T_layr_bounds[3] + B_T_layr_bounds[3]+ pwr_bott)/2 - Vsand1[i])
|
|
#this finds the closest node to the desired position
|
|
if round(diff,5) >= round(prev,5):
|
|
#then we want the index representing the
|
|
sand_z_viz_indices1 = indx_bndrz_z[6] + (i-1)
|
|
break
|
|
elif i == (len(Vsand1)-4): #If it's at the of the loop and nothing has been chosen, choose the last node not in the power slab
|
|
sand_z_viz_indices1 = indx_bndrz_z[6]+ len(Vsand1)- 4
|
|
|
|
prev = diff
|
|
|
|
|
|
#for the nodes between the first power layer and the next layer, keep them 0.3m apart
|
|
#of the vector
|
|
node_dist = 0.3
|
|
sand_z_viz_indices2 = np.zeros(shape=[math.floor((pwr_mid-pwr_bott)/node_dist)-1], dtype=int)
|
|
for indx in range(0,len(sand_z_viz_indices2)):
|
|
prev = 100
|
|
for i in range (0,(len(Vsand2)-3)):
|
|
diff = abs(B_T_layr_bounds[3]+pwr_bott + (indx+1)*node_dist - Vsand2[i]) #diff = desired position - current index
|
|
#this finds the closest node to the desired position
|
|
if round(diff,5) >= round(prev,5):
|
|
#then we want the index represented by (i-1)
|
|
sand_z_viz_indices2[indx] = pwr_bott_indx + i+1
|
|
break
|
|
#if next iteration would be outside the soil domain, put the last node in the soil domain there
|
|
elif i == len(Vsand2)-4:
|
|
sand_z_viz_indices2[indx] = pwr_bott_indx + len(Vsand2)- 2
|
|
|
|
prev = diff
|
|
|
|
|
|
#keep same distance for next layer (mid and upr pwr layers)
|
|
sand_z_viz_indices3 = np.zeros(shape=[math.floor((pwr_upr-pwr_mid)/node_dist)-1], dtype=int)
|
|
for indx in range(0,len(sand_z_viz_indices3)):
|
|
prev = 100
|
|
for i in range(0,len(Vsand3)-3):
|
|
diff = abs(B_T_layr_bounds[3]+pwr_mid+ (indx+1)*node_dist - Vsand3[i]) #diff = desired position - current index
|
|
#this finds the closest node to the desired position
|
|
if round(diff,5) >= round(prev,5):
|
|
#then we want the index represented by (i-1)
|
|
sand_z_viz_indices3[indx] = pwr_mid_indx + i+1
|
|
break
|
|
#if next iteration would be outside the soil domain, put the last node in the soil domain there
|
|
elif i == len(Vsand3)-4:
|
|
sand_z_viz_indices3[indx] = pwr_mid_indx + len(Vsand3)- 2
|
|
|
|
prev = diff
|
|
|
|
|
|
|
|
|
|
#keep same distance for last layer (upr layer and top of sand store)
|
|
sand_z_viz_indices4 = np.zeros(shape=[math.floor((sand_H-pwr_upr)/node_dist)], dtype=int)
|
|
for indx in range(0,len(sand_z_viz_indices4)):
|
|
prev = 100
|
|
for i in range(0,len(Vsand4)):
|
|
diff = abs(B_T_layr_bounds[3] + pwr_upr+(indx+1)*node_dist - Vsand4[i]) #diff = desired position - current index
|
|
#this finds the closest node to the desired position
|
|
if round(diff,5) >= round(prev,5):
|
|
#then we want the index represented by (i-1)
|
|
sand_z_viz_indices4[indx] = pwr_upr_indx + i+1
|
|
break
|
|
#if next iteration would be outside the soil domain, put the last node in the soil domain there
|
|
elif i == len(Vsand4)-1:
|
|
sand_z_viz_indices4[indx] = pwr_upr_indx + len(Vsand4)+1
|
|
|
|
prev = diff
|
|
|
|
|
|
|
|
|
|
# Put sand indices together
|
|
sand_z_viz_indices = np.concatenate(([indx_bndrz_z[6]],[sand_z_viz_indices1],[pwr_bott_indx],sand_z_viz_indices2,[pwr_mid_indx],sand_z_viz_indices3, [pwr_upr_indx],sand_z_viz_indices4,[indx_bndrz_z[7]]))
|
|
|
|
|
|
#%%%PUT AXIS INDICES TOGETHER
|
|
|
|
#If the nodes from the concrete and XPS layers should all be output:
|
|
if all_wall_layer_nodes == 1:
|
|
VIZ_X_index = np.concatenate((soil_nrthside_viz_indices,np.arange(soil_nrthside_viz_indices[-1]+1,sand_noTCn_viz_index),[sand_noTCn_viz_index],sand_x_viz_indices,[sand_noTCs_viz_index],np.arange(sand_noTCs_viz_index+1,soil_south_viz_indices[0]),soil_south_viz_indices))
|
|
|
|
VIZ_Y_index = np.concatenate((soil_viz_indices,np.arange(soil_viz_indices[-1]+1,sand_noTCw_viz_index),[sand_noTCw_viz_index],sand_y_viz_indices,[sand_noTCe_viz_index],np.arange(sand_noTCe_viz_index+1,soil_east_viz_indices[0]), soil_east_viz_indices))
|
|
|
|
VIZ_Z_index = np.concatenate((soil_viz_indices,np.arange(soil_viz_indices[-1]+1,sand_z_viz_indices[0]),sand_z_viz_indices,np.arange(sand_z_viz_indices[-1]+1,soil_top_viz_indices[0]),soil_top_viz_indices))
|
|
#If only one node from the concrete and XPS layers should be output:
|
|
else:
|
|
VIZ_X_index = np.concatenate((soil_nrthside_viz_indices,[conc_n_viz_index],[XPS_n_viz_index],[sand_noTCn_viz_index],sand_x_viz_indices,[sand_noTCs_viz_index],[XPS_s_viz_index],[conc_s_viz_index],soil_south_viz_indices))
|
|
|
|
VIZ_Y_index = np.concatenate((soil_viz_indices,[conc_wb_viz_index],[XPS_wb_viz_index],[sand_noTCw_viz_index],sand_y_viz_indices,[sand_noTCe_viz_index],[XPS_e_viz_index], [conc_e_viz_index], soil_east_viz_indices))
|
|
|
|
VIZ_Z_index = np.concatenate((soil_viz_indices,[conc_wb_viz_index],[XPS_wb_viz_index],sand_z_viz_indices,[XPS_t_viz_index],soil_top_viz_indices))
|
|
|
|
|
|
#%% 3. FDE SOLVER
|
|
#%%% Initial conditions
|
|
#%%%% Initialize Variables for FDE Solver
|
|
|
|
#Initialize temperature matrix
|
|
Temps = np.ones(shape=(U,V,W,2)) #Matrix for temperatures (two time points)
|
|
|
|
#Side wall boundaries - initialize matrices
|
|
T_SEWbound = np.zeros(shape=(len(node_zcoords)))
|
|
|
|
#in case the north wall needs to be made different b/c of its proximity to the CHEeR house, an extra variable was created
|
|
T_Nbound = np.zeros(shape=(len(node_zcoords)))
|
|
|
|
#Initial avg temperatures of 3 sand store layers
|
|
IC_SSlayers = np.zeros(shape=(3))
|
|
IC_SSlayers[0]=avg_expmtl_temps[0,0] #Layer C (bottom)
|
|
IC_SSlayers[1]=avg_expmtl_temps[0,1] #Layer B (middle)
|
|
IC_SSlayers[2]=avg_expmtl_temps[0,2] #Layer A (top)
|
|
|
|
#variable that will hold temps of nodes closest to TCs, and will be printed out for comparison with experimental data
|
|
toprintTCs = np.zeros(shape=(len(sand_TC_node_xindices), len(sand_TC_node_yindices), 3))
|
|
|
|
# #if graphs of the entire num. domain are wanted, temps for visualization will be printed out
|
|
# toprintViz = np.zeros(shape=(len(VIZ_X_index), len(VIZ_Y_index), len(VIZ_Z_index)))
|
|
|
|
|
|
#Total time elapsed in days, and hour of the day
|
|
day = 0
|
|
hour = 0
|
|
|
|
#%%%% Set Initial Conditions
|
|
|
|
#Set initial temperature conditions for the very first timestep (construct layers from outside in)
|
|
n = 0 # first timestep
|
|
|
|
#Calculate/update boundary condition temps
|
|
[T_Nbound,T_SEWbound] = boundaryConditions(DOY,day,node_zcoords, domain_H, T_Nbound, T_SEWbound)
|
|
|
|
#Initial temperature of the concrete and XPS layers -> the average of the sand store average temp and the average of the Kusuda array
|
|
XPSConc_IC = np.mean([np.mean(IC_SSlayers), np.mean(T_SEWbound)])
|
|
|
|
#Initialize LOWER Soil layers - set temperatures in LOWER soil layer
|
|
#gradient in lower soil layer
|
|
gradient_z = (XPSConc_IC - T_SEWbound[0]) / (indx_bndrz_z[1]-indx_bndrz_z[0])
|
|
|
|
for k in range(1,indx_bndrz_z[1]+1):
|
|
Temps[:,:,k,n] = T_SEWbound[0] + gradient_z*k
|
|
|
|
|
|
#Concrete and XPS layers (entire x-y block from bottom of concrete to top of XPS)
|
|
Temps[:,:,indx_bndrz_z[2]:indx_bndrz_z[9]+1,0] = XPSConc_IC
|
|
|
|
#Initialize TOP Soil layers - set temperatures in TOP soil layer
|
|
#gradient in top soil layer
|
|
gradient_z = (XPSConc_IC - T_SEWbound[-1]) / (indx_bndrz_z[11]-indx_bndrz_z[10])
|
|
|
|
for k in range(indx_bndrz_z[11],indx_bndrz_z[10]-1,-1):
|
|
Temps[:,:,k,n] = T_SEWbound[-1] + gradient_z*(indx_bndrz_z[11]-k)
|
|
|
|
|
|
#Initialize MIDDLE Soil layers - set temperatures in MIDDLE soil layer, at elevation of concrete and XPS
|
|
for k in range(indx_bndrz_z[2]-2,indx_bndrz_z[9]+3):
|
|
|
|
#gradient in x-direction from north boundary wall and from south boundary wall
|
|
gradient_x = (XPSConc_IC - T_SEWbound[k]) / (indx_bndrz_x[1]-indx_bndrz_x[0])
|
|
|
|
for i in range(1,indx_bndrz_x[1]+1):
|
|
#for temps nearest to north boundary wall
|
|
Temps[i,:,k,0] = T_SEWbound[k] + gradient_x*i
|
|
#for temps nearest to south boundary wall
|
|
Temps[indx_bndrz_x[-1]-i,:,k,0] = T_SEWbound[k] + gradient_x*i
|
|
|
|
#gradient in y-direction from west boundary wal and from east boundary walll
|
|
gradient_y = (XPSConc_IC - T_SEWbound[k]) / (indx_bndrz_y[1]-indx_bndrz_y[0])
|
|
|
|
for j in range(1,indx_bndrz_y[1]+1):
|
|
#for temps nearest to west boundary wall
|
|
Temps[indx_bndrz_x[2]-2:indx_bndrz_x[15]+3,j,k,0] = T_SEWbound[k] + gradient_y*j
|
|
#for temps nearest to east boundary wall
|
|
Temps[indx_bndrz_x[2]-2:indx_bndrz_x[15]+3,indx_bndrz_y[-1]-j,k,0] = T_SEWbound[k] + gradient_y*j
|
|
|
|
#Apply BCs again
|
|
updateBCs(T_Nbound, T_SEWbound,0)
|
|
|
|
#1st Sand layer (0m to 0.9m from bottom of sand store)
|
|
for k in range(indx_bndrz_z[6],moisture_layer_height[0]+1):
|
|
for i in range(indx_bndrz_x[6],indx_bndrz_x[11]+1):
|
|
for j in range(indx_bndrz_y[6],indx_bndrz_y[11]+1):
|
|
Temps[i,j,k,n] = IC_SSlayers[0]
|
|
|
|
|
|
#2nd Sand layer (0.9m to 1.8m from bottom of sand store)
|
|
for k in range((moisture_layer_height[0]+1),moisture_layer_height[1]+1):
|
|
for i in range(indx_bndrz_x[6],indx_bndrz_x[11]+1):
|
|
for j in range(indx_bndrz_y[6],indx_bndrz_y[11]+1):
|
|
Temps[i,j,k,n] = IC_SSlayers[1]
|
|
|
|
|
|
#3rd Sand layer (1.8m to 3.0m from bottom of sand store)
|
|
for k in range((moisture_layer_height[1]+1),moisture_layer_height[2]+1):
|
|
for i in range(indx_bndrz_x[6],indx_bndrz_x[11]+1):
|
|
for j in range(indx_bndrz_y[6],indx_bndrz_y[11]+1):
|
|
Temps[i,j,k,n] = IC_SSlayers[2]
|
|
|
|
# #Copy the initial boundary conditions to next timestep (since now they are "ones" and they are
|
|
# #only updated every week in the simulation)
|
|
# updateBCs(T_Nbound, T_SEWbound,1)
|
|
|
|
#Copy the initial conditions to next timestep (since the IC_SS function will run next, and doesn't iterate
|
|
#over the middle of the sand store)
|
|
Temps[:,:,:,1] = Temps[:,:,:,0]
|
|
|
|
|
|
|
|
#%%%% Print initial conditions to file
|
|
|
|
#Copy temperature values that need to be output to compare to experimental data
|
|
for i in range(0,np.size(toprintTCs,0)):
|
|
for j in range(0,np.size(toprintTCs,1)):
|
|
toprintTCs[i,j,0] = Temps[sand_TC_node_xindices[i],sand_TC_node_yindices[j],pwr_bott_indx,n]
|
|
toprintTCs[i,j,1] = Temps[sand_TC_node_xindices[i],sand_TC_node_yindices[j],pwr_mid_indx,n]
|
|
toprintTCs[i,j,2] = Temps[sand_TC_node_xindices[i],sand_TC_node_yindices[j],pwr_upr_indx,n]
|
|
|
|
|
|
|
|
# #Copy intial temperature values to be visualized
|
|
# for i in range(0,np.size(toprintViz,0)):
|
|
# for j in range(0,np.size(toprintViz,1)):
|
|
# for k in range(0,np.size(toprintViz,2)):
|
|
# toprintViz[i,j,k] = Temps[VIZ_X_index[i], VIZ_Y_index[j], VIZ_Z_index[k],n]
|
|
|
|
|
|
#Output the first timestep of data (initial condition) to output files
|
|
#This file will hold temperature values that need to be compared to experimental data
|
|
fileID = 'r' + str(run_num) + '_1Sand_TC_Temps.txt'
|
|
print2newfile(fileID,day,hour,toprintTCs,len(sand_TC_node_xindices),len(sand_TC_node_yindices),3)
|
|
|
|
|
|
# #This file will hold temperature values that will be visualized
|
|
# fileID2='r' + str(run_num) + '_2Sand_Viz_Temps.txt'
|
|
# temparray = np.concatenate(([day], [hour], toprintViz.flatten(order='F')))
|
|
# print2newfile(fileID2,day,hour,toprintViz,len(VIZ_X_index),len(VIZ_Y_index),len(VIZ_Z_index),True)
|
|
|
|
|
|
|
|
#%%% Run function to get initial conditions to steady state (pre-conditioning period)
|
|
#create variable to exit the solver in case FDM model becomes unstable
|
|
get_out=0
|
|
|
|
#iterations variable, nn
|
|
nn=0
|
|
diff_tol = IC_SS(dt) #FUNCTION
|
|
|
|
print("IC_SS iterations: nn = " + str(nn) + ", diff = " + str(diff_tol))
|
|
|
|
#%%%% Print steady state initial conditions to file
|
|
if get_out==0: #if previous loop had get_out==1, skip this
|
|
|
|
n=0
|
|
#Copy temperature values that need to be output to compare to experimental data
|
|
for i in range(0,np.size(toprintTCs,0)):
|
|
for j in range(0,np.size(toprintTCs,1)):
|
|
toprintTCs[i,j,0] = Temps[sand_TC_node_xindices[i],sand_TC_node_yindices[j],pwr_bott_indx,n]
|
|
toprintTCs[i,j,1] = Temps[sand_TC_node_xindices[i],sand_TC_node_yindices[j],pwr_mid_indx,n]
|
|
toprintTCs[i,j,2] = Temps[sand_TC_node_xindices[i],sand_TC_node_yindices[j],pwr_upr_indx,n]
|
|
|
|
|
|
|
|
# #Copy intial temperature values to be visualized
|
|
# for i in range(0,np.size(toprintViz,0)):
|
|
# for j in range(0,np.size(toprintViz,1)):
|
|
# for k in range(0,np.size(toprintViz,2)):
|
|
# toprintViz[i,j,k] = Temps[VIZ_X_index[i], VIZ_Y_index[j], VIZ_Z_index[k],n]
|
|
|
|
#Output the data with a fake hour value of 0.001h (something close to zero, since we already have values output at t=0s)
|
|
append2file(fileID, day, 0.001, toprintTCs)
|
|
# append2file(fileID2, day, 0.001, toprintViz)
|
|
|
|
#%%% Solver
|
|
for n in range(1,totTimeIntrvls):
|
|
if get_out==1: #if previous loop had get_out==1
|
|
break
|
|
|
|
#Total time elapsed in days, and hour of the day
|
|
day = n*dt / 86400
|
|
hour = (day - math.floor(day))*24
|
|
|
|
#%%%% Boundary Conditions Update
|
|
if day%7 == 0: #If modulus (remainder) of division of day by 7 is zero
|
|
#Calculate/update boundary condition temps every week
|
|
[T_Nbound,T_SEWbound] = boundaryConditions(DOY,day,node_zcoords,domain_H, T_Nbound, T_SEWbound)
|
|
|
|
#Apply newly calculated B.C.'s to boundary temps
|
|
updateBCs(T_Nbound, T_SEWbound,1)
|
|
|
|
|
|
|
|
#%%%% Governing Eqn
|
|
GoverningEqn(dt,n)
|
|
|
|
|
|
#%%%% Print temperatures to output file at requested timestep interval
|
|
if n%output_temp_freq_int == 0: #checking modulus (remainder) of operation
|
|
#first check if model is stable, if it's not, exit simulation
|
|
if np.max(Temps)>1000 or np.min(Temps)<-1000 or np.isinf(Temps).sum()>0 or np.isnan(Temps).sum()>0:
|
|
get_out=1
|
|
print("Exited for loop - unstable FDM model")
|
|
break
|
|
|
|
#Copy temperature values that need to be output to compare to experimental data
|
|
for i in range(0,np.size(toprintTCs,0)):
|
|
for j in range(0,np.size(toprintTCs,1)):
|
|
toprintTCs[i,j,0] = Temps[sand_TC_node_xindices[i],sand_TC_node_yindices[j],pwr_bott_indx,1]
|
|
toprintTCs[i,j,1] = Temps[sand_TC_node_xindices[i],sand_TC_node_yindices[j],pwr_mid_indx,1]
|
|
toprintTCs[i,j,2] = Temps[sand_TC_node_xindices[i],sand_TC_node_yindices[j],pwr_upr_indx,1]
|
|
#write temperatures from that timestep to output file
|
|
append2file(fileID, day, hour, toprintTCs)
|
|
|
|
#print out last timestep of simulation
|
|
elif n == (totTimeIntrvls - 1):
|
|
#Copy temperature values that need to be output to compare to experimental data
|
|
for i in range(0,np.size(toprintTCs,0)):
|
|
for j in range(0,np.size(toprintTCs,1)):
|
|
toprintTCs[i,j,0] = Temps[sand_TC_node_xindices[i],sand_TC_node_yindices[j],pwr_bott_indx,1]
|
|
toprintTCs[i,j,1] = Temps[sand_TC_node_xindices[i],sand_TC_node_yindices[j],pwr_mid_indx,1]
|
|
toprintTCs[i,j,2] = Temps[sand_TC_node_xindices[i],sand_TC_node_yindices[j],pwr_upr_indx,1]
|
|
#write temperatures from that timestep to output file
|
|
append2file(fileID, day, hour, toprintTCs)
|
|
|
|
|
|
# #save variables to output viz file at the requested timestep interval
|
|
# if (n%viz_output_freq_int == 0 and n!=0): #modulus
|
|
# #Print out temperature values that will be visualized
|
|
# for i in range(0,np.size(toprintViz,0)):
|
|
# for j in range(0,np.size(toprintViz,1)):
|
|
# for k in range(0,np.size(toprintViz,2)):
|
|
# toprintViz[i,j,k] = Temps[VIZ_X_index[i], VIZ_Y_index[j], VIZ_Z_index[k],1]
|
|
# #print temps to file
|
|
# append2file(fileID2, day, hour, toprintViz)
|
|
|
|
# elif n == (totTimeIntrvls - 1): #print out last timestep
|
|
# #Print out temperature values that will be visualized
|
|
# for i in range(0,np.size(toprintViz,0)):
|
|
# for j in range(0,np.size(toprintViz,1)):
|
|
# for k in range(0,np.size(toprintViz,2)):
|
|
# toprintViz[i,j,k] = Temps[VIZ_X_index[i], VIZ_Y_index[j], VIZ_Z_index[k],1]
|
|
# #print temps to file
|
|
# append2file(fileID2, day, hour, toprintViz)
|
|
|
|
#%%%%Prepare for next iteration
|
|
#Put temps from just-calculated timestep into "previous" timestep
|
|
Temps[:,:,:,0]= Temps[:,:,:,1]
|
|
|
|
|
|
#%% 4. PARAMETER OUTPUTS TO FILE
|
|
|
|
if get_out ==1:
|
|
filename ='r' + str(run_num) +'_SimParameters_MODEL UNSTABLE.txt'
|
|
with open(filename,'w') as f:
|
|
f.write("Run number "+ str(run_num)+ "\n\n")
|
|
f.write("Did not finish simulation, model was unstable. Solver loop exited.")
|
|
|
|
f.write("Run number "+ str(run_num)+ "\n\n")
|
|
|
|
f.write("Number of pre-conditioning iterations: "+ str(nn)+ "\n")
|
|
f.write("Largest temperature difference between final pre-conditioning iterations: "+ str(diff_tol)+ "\n\n")
|
|
|
|
f.write(filename1 + "\n")
|
|
f.write(filename2 + "\n\n")
|
|
|
|
if north_BC_diff == 1:
|
|
f.write("North wall BC different? YES \n")
|
|
f.write("T_avg_N = " + str(T_avg_N) + "\n")
|
|
f.write("ampl_N = " + str(ampl_N) + "\n")
|
|
else:
|
|
f.write("North wall BC different? NO \n")
|
|
f.write("T_avg = " + str(T_avg) + "\n")
|
|
f.write("ampl = " + str(ampl) + "\n\n")
|
|
|
|
f.write("water_Cp = "+ str(water_Cp)+ "\n")
|
|
f.write("water_rho = "+ str(water_rho)+ "\n")
|
|
f.write("drySand_Cp = "+ str(drySand_Cp)+ "\n")
|
|
f.write("drySand_rho = "+ str(drySand_rho)+ "\n")
|
|
f.write("vol_percent = "+ str(vol_percent)+ "\n")
|
|
f.write("sand_lambda = "+ str(sand_lambda)+ "\n")
|
|
f.write("conc_Cp = "+ str(conc_Cp)+ "\n")
|
|
f.write("conc_rho = "+ str(conc_rho)+ "\n")
|
|
f.write("conc_lambda = "+ str(conc_lambda)+ "\n")
|
|
|
|
f.write("XPS_Cp_orig = "+ str(XPS_Cp_orig)+ "\n")
|
|
f.write("XPS_rho_orig = "+ str(XPS_rho_orig)+ "\n")
|
|
f.write("XPS_lambda_SET = "+ str(XPS_lambda_SET)+ "\n")
|
|
|
|
f.write("vol_percent_H2O_SETface_XPS = "+ str(vol_percent_H2O_SETface_XPS)+ "\n")
|
|
f.write("XPS_Cp_SET = "+ str(XPS_Cp_SET)+ "\n")
|
|
f.write("XPS_rho_SET = "+ str(XPS_rho_SET)+ "\n")
|
|
f.write("vol_percent_H2O_Nface_XPS = "+ str(vol_percent_H2O_Nface_XPS)+ "\n")
|
|
f.write("northXPS_lambda = "+ str(northXPS_lambda)+ "\n")
|
|
f.write("vol_percent_H2O_Wface_XPS = "+ str(vol_percent_H2O_Wface_XPS)+ "\n")
|
|
f.write("westXPS_lambda = "+ str(westXPS_lambda)+ "\n")
|
|
f.write("vol_percent_H2O_Bface_XPS = "+ str(vol_percent_H2O_Bface_XPS)+ "\n")
|
|
f.write("bottomXPS_lambda = "+ str(bottomXPS_lambda)+ "\n")
|
|
f.write("XPS Cp, north wall = "+ str([Cp[indx_bndrz_x[4],indx_bndrz_y[4],indx_bndrz_z[4]],
|
|
Cp[indx_bndrz_x[4],indx_bndrz_y[4],(moisture_layer_height[0]+1)],
|
|
Cp[indx_bndrz_x[4],indx_bndrz_y[4],(moisture_layer_height[1]+1)]]) + "\n")
|
|
f.write("XPS rho, north wall = "+ str([rho[indx_bndrz_x[4],indx_bndrz_y[4],indx_bndrz_z[4]],
|
|
rho[indx_bndrz_x[4],indx_bndrz_y[4],(moisture_layer_height[0]+1)],
|
|
rho[indx_bndrz_x[4],indx_bndrz_y[4],(moisture_layer_height[1]+1)]]) + "\n")
|
|
f.write("XPS Cp, west wall = "+ str([Cp[indx_bndrz_x[6],indx_bndrz_y[4],indx_bndrz_z[4]],
|
|
Cp[indx_bndrz_x[6],indx_bndrz_y[4],(moisture_layer_height[0]+1)],
|
|
Cp[indx_bndrz_x[6],indx_bndrz_y[4],(moisture_layer_height[1]+1)]]) + "\n")
|
|
f.write("XPS rho, west wall = "+ str([rho[indx_bndrz_x[6],indx_bndrz_y[4],indx_bndrz_z[4]],
|
|
rho[indx_bndrz_x[6],indx_bndrz_y[4],(moisture_layer_height[0]+1)],
|
|
rho[indx_bndrz_x[6],indx_bndrz_y[4],(moisture_layer_height[1]+1)]]) + "\n")
|
|
f.write("XPS Cp, bottom face = "+ str(Cp[indx_bndrz_x[6],indx_bndrz_y[6],indx_bndrz_z[4]])+ "\n")
|
|
f.write("XPS rho, bottom face = "+ str(rho[indx_bndrz_x[6],indx_bndrz_y[6],indx_bndrz_z[4]]) + "\n")
|
|
|
|
f.write("soil_Cp = "+ str(soil_Cp)+ "\n")
|
|
f.write("soil_rho = "+ str(soil_rho)+ "\n")
|
|
f.write("soil_lambda = "+ str(soil_lambda) + "\n\n")
|
|
|
|
f.write("simulation timestep, dt = "+ str(dt)+ "\n")
|
|
f.write("output_temp_freq_h = "+ str(output_temp_freq_h)+ "\n")
|
|
f.write("visualization_output_freq_h = "+ str(visualization_output_freq_h) +"\n\n")
|
|
|
|
f.write("sand_L = "+ str(sand_L)+ "\n")
|
|
f.write("sand_W = "+ str(sand_W)+ "\n")
|
|
f.write("sand_H = "+ str(sand_H)+ "\n")
|
|
f.write("XPS_th = "+ str(XPS_th)+ "\n")
|
|
f.write("conc_th = "+ str(conc_th)+ "\n")
|
|
f.write("soil_top_th = "+ str(soil_top_th)+ "\n")
|
|
f.write("soil_nrthside_th = "+ str(soil_nrthside_th)+ "\n")
|
|
f.write("soil_th = "+ str(soil_th)+ "\n")
|
|
f.write("no_TC = "+ str(no_TC)+ "\n")
|
|
f.write("node_space = "+ str(node_space)+ "\n")
|
|
f.write("no_pwr = "+ str(no_pwr)+ "\n")
|
|
f.write("pwr_bott = "+ str(pwr_bott)+ "\n")
|
|
f.write("pwr_mid = "+ str(pwr_mid)+ "\n")
|
|
f.write("pwr_upr = "+ str(pwr_upr)+ "\n\n")
|
|
|
|
f.write("------------"+ "\n")
|
|
f.write("MESH SIZING:"+ "\n")
|
|
f.write("------------"+ "\n")
|
|
f.write("Soil(coarse) dx,dy,dz = " + str(dx_soil) + "m" + "\n")
|
|
f.write("Soil(fine) dx,dy,dz = " + str(dx_soilconc_boundary)+ "m on " + str(soilconc_boundary_th)+ "m"+ "\n")
|
|
f.write("Concrete dx,dy,dz = "+ str(Q3) + "m"+ "\n")
|
|
f.write("XPS dx,dy,dz = "+ str(Q4) + "m"+ "\n")
|
|
f.write("Sand (no power zone) dx = "+ str(Q5) + "m"+ "\n")
|
|
f.write("Sand (power zone) dx,dy = "+ str(dx_sand) + "m\n"+ "\n")
|
|
|
|
f.write("Sand dz on 0<z<0.4m of sand store = "+ str(dz1) + "m"+ "\n")
|
|
f.write("Sand dz on 0.4m<z<1.3m of sand store = "+ str(dz2) + "m"+ "\n")
|
|
f.write("Sand dz on 1.3m<z<2.2m of sand store = "+ str(dz3) + "m"+ "\n")
|
|
f.write("Sand dz on 2.2m<z<3.0m of sand store = "+ str(dz4) + "m"+ "\n")
|
|
|
|
elif get_out != 1: #if model was stable, print file
|
|
|
|
filename ='r' + str(run_num) +'_SimParameters.txt'
|
|
|
|
with open(filename,'w') as f:
|
|
f.write("Run number "+ str(run_num)+ "\n\n")
|
|
|
|
f.write("Number of pre-conditioning iterations: "+ str(nn)+ "\n")
|
|
f.write("Largest temperature difference between final pre-conditioning iterations: "+ str(diff_tol)+ "\n\n")
|
|
|
|
f.write(filename1 + "\n")
|
|
f.write(filename2 + "\n\n")
|
|
|
|
if north_BC_diff == 1:
|
|
f.write("North wall BC different? YES \n")
|
|
f.write("T_avg_N = " + str(T_avg_N) + "\n")
|
|
f.write("ampl_N = " + str(ampl_N) + "\n")
|
|
else:
|
|
f.write("North wall BC different? NO \n")
|
|
f.write("T_avg = " + str(T_avg) + "\n")
|
|
f.write("ampl = " + str(ampl) + "\n\n")
|
|
|
|
f.write("water_Cp = "+ str(water_Cp)+ "\n")
|
|
f.write("water_rho = "+ str(water_rho)+ "\n")
|
|
f.write("drySand_Cp = "+ str(drySand_Cp)+ "\n")
|
|
f.write("drySand_rho = "+ str(drySand_rho)+ "\n")
|
|
f.write("vol_percent = "+ str(vol_percent)+ "\n")
|
|
f.write("sand_lambda = "+ str(sand_lambda)+ "\n")
|
|
f.write("conc_Cp = "+ str(conc_Cp)+ "\n")
|
|
f.write("conc_rho = "+ str(conc_rho)+ "\n")
|
|
f.write("conc_lambda = "+ str(conc_lambda)+ "\n")
|
|
f.write("XPS_Cp_orig = "+ str(XPS_Cp_orig)+ "\n")
|
|
f.write("XPS_rho_orig = "+ str(XPS_rho_orig)+ "\n")
|
|
f.write("XPS_lambda_SET = "+ str(XPS_lambda_SET)+ "\n")
|
|
|
|
f.write("vol_percent_H2O_SETface_XPS = "+ str(vol_percent_H2O_SETface_XPS)+ "\n")
|
|
f.write("XPS_Cp_SET = "+ str(XPS_Cp_SET)+ "\n")
|
|
f.write("XPS_rho_SET = "+ str(XPS_rho_SET)+ "\n")
|
|
f.write("vol_percent_H2O_Nface_XPS = "+ str(vol_percent_H2O_Nface_XPS)+ "\n")
|
|
f.write("northXPS_lambda = "+ str(northXPS_lambda)+ "\n")
|
|
f.write("vol_percent_H2O_Wface_XPS = "+ str(vol_percent_H2O_Wface_XPS)+ "\n")
|
|
f.write("westXPS_lambda = "+ str(westXPS_lambda)+ "\n")
|
|
f.write("vol_percent_H2O_Bface_XPS = "+ str(vol_percent_H2O_Bface_XPS)+ "\n")
|
|
f.write("bottomXPS_lambda = "+ str(bottomXPS_lambda)+ "\n")
|
|
f.write("XPS Cp, north wall = "+ str([Cp[indx_bndrz_x[4],indx_bndrz_y[4],indx_bndrz_z[4]],
|
|
Cp[indx_bndrz_x[4],indx_bndrz_y[4],(moisture_layer_height[0]+1)],
|
|
Cp[indx_bndrz_x[4],indx_bndrz_y[4],(moisture_layer_height[1]+1)]]) + "\n")
|
|
f.write("XPS rho, north wall = "+ str([rho[indx_bndrz_x[4],indx_bndrz_y[4],indx_bndrz_z[4]],
|
|
rho[indx_bndrz_x[4],indx_bndrz_y[4],(moisture_layer_height[0]+1)],
|
|
rho[indx_bndrz_x[4],indx_bndrz_y[4],(moisture_layer_height[1]+1)]]) + "\n")
|
|
f.write("XPS Cp, west wall = "+ str([Cp[indx_bndrz_x[6],indx_bndrz_y[4],indx_bndrz_z[4]],
|
|
Cp[indx_bndrz_x[6],indx_bndrz_y[4],(moisture_layer_height[0]+1)],
|
|
Cp[indx_bndrz_x[6],indx_bndrz_y[4],(moisture_layer_height[1]+1)]]) + "\n")
|
|
f.write("XPS rho, west wall = "+ str([rho[indx_bndrz_x[6],indx_bndrz_y[4],indx_bndrz_z[4]],
|
|
rho[indx_bndrz_x[6],indx_bndrz_y[4],(moisture_layer_height[0]+1)],
|
|
rho[indx_bndrz_x[6],indx_bndrz_y[4],(moisture_layer_height[1]+1)]]) + "\n")
|
|
f.write("XPS Cp, bottom face = "+ str(Cp[indx_bndrz_x[6],indx_bndrz_y[6],indx_bndrz_z[4]])+ "\n")
|
|
f.write("XPS rho, bottom face = "+ str(rho[indx_bndrz_x[6],indx_bndrz_y[6],indx_bndrz_z[4]]) + "\n")
|
|
|
|
f.write("soil_Cp = "+ str(soil_Cp)+ "\n")
|
|
f.write("soil_rho = "+ str(soil_rho)+ "\n")
|
|
f.write("soil_lambda = "+ str(soil_lambda) + "\n\n")
|
|
|
|
f.write("simulation timestep, dt = "+ str(dt)+ "\n")
|
|
f.write("output_temp_freq_h = "+ str(output_temp_freq_h)+ "\n")
|
|
f.write("visualization_output_freq_h = "+ str(visualization_output_freq_h) +"\n\n")
|
|
|
|
f.write("sand_L = "+ str(sand_L)+ "\n")
|
|
f.write("sand_W = "+ str(sand_W)+ "\n")
|
|
f.write("sand_H = "+ str(sand_H)+ "\n")
|
|
f.write("XPS_th = "+ str(XPS_th)+ "\n")
|
|
f.write("conc_th = "+ str(conc_th)+ "\n")
|
|
f.write("soil_top_th = "+ str(soil_top_th)+ "\n")
|
|
f.write("soil_nrthside_th = "+ str(soil_nrthside_th)+ "\n")
|
|
f.write("soil_th = "+ str(soil_th)+ "\n")
|
|
f.write("no_TC = "+ str(no_TC)+ "\n")
|
|
f.write("node_space = "+ str(node_space)+ "\n")
|
|
f.write("no_pwr = "+ str(no_pwr)+ "\n")
|
|
f.write("pwr_bott = "+ str(pwr_bott)+ "\n")
|
|
f.write("pwr_mid = "+ str(pwr_mid)+ "\n")
|
|
f.write("pwr_upr = "+ str(pwr_upr)+ "\n\n")
|
|
|
|
f.write("------------"+ "\n")
|
|
f.write("MESH SIZING:"+ "\n")
|
|
f.write("------------"+ "\n")
|
|
f.write("Soil(coarse) dx,dy,dz = " + str(dx_soil) + "m" + "\n")
|
|
f.write("Soil(fine) dx,dy,dz = " + str(dx_soilconc_boundary)+ "m on " + str(soilconc_boundary_th)+ "m"+ "\n")
|
|
f.write("Concrete dx,dy,dz = "+ str(Q3) + "m"+ "\n")
|
|
f.write("XPS dx,dy,dz = "+ str(Q4) + "m"+ "\n")
|
|
f.write("Sand (no power zone) dx = "+ str(Q5) + "m"+ "\n")
|
|
f.write("Sand (power zone) dx,dy = "+ str(dx_sand) + "m\n"+ "\n")
|
|
|
|
f.write("Sand dz on 0<z<0.4m of sand store = "+ str(dz1) + "m"+ "\n")
|
|
f.write("Sand dz on 0.4m<z<1.3m of sand store = "+ str(dz2) + "m"+ "\n")
|
|
f.write("Sand dz on 1.3m<z<2.2m of sand store = "+ str(dz3) + "m"+ "\n")
|
|
f.write("Sand dz on 2.2m<z<3.0m of sand store = "+ str(dz4) + "m"+ "\n")
|