TempGen is a daily temperature simulator developed in GoldSim that models stochastic, long-term minimum and maximum daily temperatures for a location. It builds upon the foundational work of Dee Allen Wright and the WGEN model (1983), originally implemented in FORTRAN, to deliver a robust simulation of precipitation and temperature patterns over extended periods. This portion of the WGEN model was isolated into its own model "TempGen" to provide a more modular approach to simulating weather in your GoldSim models. Now, you can choose to only simulate precipitation or add temperature as well, facilitating the realistic simulation of environmental processes affected by temperature, like evapotranspiration rates.
By leveraging statistical analysis of historical records, TempGen captures both seasonal changes and random daily fluctuations found in the historical records.
TempGen: Inputs and Settings
Input parameters for TempGen are calculated in a separate model called TempGen PAR. This model is saved separately since it only needs to be run once and is described in the next section.
The simulation settings should conform to the following:
- Time basis: Calendar Time
- Basic step: 1 day
Input data is entered in Data elements: Params_K, Params_U, and Cool_Start_Day as shown below.
Params_K is defined using a Data element with a vector data type to store the temperature values in terms of Kelvin (K):
- TXMD: The mean maximum temperature for dry days (K).
- TXMW: The mean maximum temperature for wet days (K).
- ATX: The amplitude of the seasonal cycle for maximum temperature (K).
- TN: The mean minimum temperature (K).
- ATN: The amplitude of the seasonal cycle for minimum temperature (K).
Params_U is defined using a Data element with a vector data type to store the dimensionless parameters that describe the variability in the temperature data:
-
- CVTX: The coefficient of variation for maximum temperature.
- ACVTX: The amplitude of the coefficient of variation for maximum temperature.
- CVTN: The coefficient of variation for minimum temperature.
- ACVTN: The amplitude of the coefficient of variation for minimum temperature.
TempGen: Model Description
TempGen is organized into two interdependent components that collectively produce the final temperature outputs. The following sections describe these components and their roles in the model.
Seasonal Trend
The Seasonal_Adjust script models the seasonal cycle of seasonal average maximum and minimum daily temperatures using a cosine function.
These seasonal adjustments represent the underlying temperature throughout the year, to which we will later adjust further to represent daily fluctuations from the seasonal trend. This simple function captures the cyclic nature of temperature changes throughout the year.
For dry days, the script calculates the maximum temperature using the equation:
txm = TXMD + ATX * dt
where:
- TXMD is the mean maximum temperature on dry days.
- ATX is a seasonal adjustment factor.
- dt = cos[0.0172 * (DayOfYear - Cool_Start_Day)]
- DayOfYear = day of the year in the simulation
- Cool_Start_Day = day transition to a cooler period begins. Default is 200.
For the minimum temperature, the script calculates:
tnm = TN + ATN * dt
Where:
- TN is the mean min temperature
- ATX is seasonal adjustment factor
- dt is described above
For wet days, TempGen adjusts seasonal maximum temperatures based on the difference between dry and wet days. For a detailed description of how the adjustments are calculated, refer to Appendix B. Adjusted seasonal maximum daily temperature is adjusted on wet days as shown in the example image below.
Finally, the adjusted seasonal maximum daily temperature and minimum daily temperature outputs are combined with the daily adjustments, which is described in the next section. Seasonal trend outputs are:
- tnm: The seasonal average minimum temperature
- tns: The baseline for minimum temperatures
- txxm: The adjusted seasonal average temperature
- txxs: The adjusted baseline for minimum temperatures
Daily Adjustments
The daily adjustments in TempGen use the same methodology used in the temperature component of WGEN (Richardson, 1984) are driven by a calibrated ARMA state-space framework (Box, 2015 and Kalman, 1960) that blends the influence of yesterday's conditions with today's random fluctuations. These are shown in the following equations.
The coefficients in the matrices were derived from a comprehensive statistical analysis of 20 years of temperature and solar radiation data across 31 U.S. locations (Richardson, 1982b) documented the seasonal and regional patterns of these correlation coefficients in the A and B matrices as shown below. For more information, refer to WGEN documentation. These 3×3 matrices are used to encapsulate the observed relationships in historical temperature data. Matrix a multiplies the previous state—effectively representing the system's memory—while matrix b scales the current random input, capturing the inherent variability of daily weather. The values used in TempGen and WGEN are shown below.
The updated state is then determined by adding these two components:
x = r + rr
This new state is used in subsequent time steps to continue the simulation.
Daily Temperature Output
The daily min and max temperatures are computed by combining the seasonal adjustments from the "Seasonal_Adjust" script with the updated state from the "x" script. The preliminary values tMin1 and tMax1 are calculated by applying the corresponding seasonal factors to the updated state. The model then ensures that the daily minimum is less than or equal to the daily maximum by assigning:
tMax1 = x[1] * txxs + txxm
tMin1 = x[2] * tns + tnm
tMin = min(tMin1, tMax1)
tMax = max(tMin1, tMax1)
The result is a stochastic daily time history of Tmax and Tmin, that is based on the analysis of historically measured temperature data for this location (see example plot below).
The model combines the deterministic seasonal patterns with stochastic state-space updates that capture the inherent variability of daily weather. This integrated approach provides a robust framework for modeling daily temperature behavior for water resources and environmental applications.
TempGen Parameter Generator
The TempGen Parameter Generator is used to generate the inputs for TempGen. It begins with a set of required time series inputs:
- Daily precipitation totals
- Daily minimum temperatures
- Daily maximum temperatures
In contrast to earlier implementations (Wright, 1983) that divided the year into fixed 28‐day periods, the current approach uses the true calendar. Within each month, the model aggregates the daily temperature records to compute key statistical measures. For each month, the code separately integrates the values for dry days and for wet days. For dry days (or for Tmin, where precipitation is not used to distinguish days), the integration yields:
- A count of dry days, XN
- The sum (SUM) of the daily temperature values.
- The sum of the squares (SS) of the daily temperature values.
From these integrations the monthly arithmetic mean is computed by dividing the sum by the count. The sample standard deviation is calculated by taking the square root of the average squared deviation from the mean (with the divisor equal to the number of days minus one). Finally, the coefficient of variation (CV) is determined by dividing the standard deviation by the mean, resulting in a dimensionless measure that normalizes the observed variability.
To capture the seasonal cycle present in the temperature data, the module applies a one‐harmonic Fourier analysis to the series of monthly statistics (such as the mean, standard deviation, and coefficient of variation) over the 12 months. For a given series of monthly values {x₁, x₂, …, xₙ} (where n = 12), the cosine and sine components are calculated as follows:
Here, x‾ is the mean of the monthly values.
The phase of the seasonal cycle is then determined by
This phase (ϕ) indicates the timing of the seasonal cycle, showing when the peak and trough of the cycle occur within the year. The amplitude, which reflects the magnitude of seasonal variation, is computed by dividing A by cos(ϕ):
This amplitude represents the extent of the seasonal fluctuations in the temperature data. This Fourier decomposition produces a smooth, compact representation of the seasonal behavior of the temperature statistics. For a full listing of the equations used to calculate the outputs, go to Appendix B.
The final outputs of the model are a series of generation parameters that are divided into two groups. The first group, denoted as Params_K, consists of parameters with physical units:
- TXMD = Tmax_Dry.XBAR # The mean maximum temperature for dry days (K).
- TXMW = TXMW = Tmax_Wet.XBAR # The mean maximum temperature for wet days (K).
- ATX = ATX = -1 × TmaxDry.C # The amplitude of the seasonal cycle for maximum temperature (K).
- TN = Tmin_Dry.XBAR # The mean minimum temperature (K).
- ATN = -1 × Tmin_Dry.C # The amplitude of the seasonal cycle for minimum temperature (K).
The second group, referred to as Params_U, comprises dimensionless parameters that describe the variability in the temperature data:
- CVTX = Tmax_Dry.XBAR2 # The coefficient of variation for maximum temperature.
- ACVTX = -1 × Tmax_Dry.C2 # The amplitude of the coefficient of variation for maximum temperature.
- CVTN = Tmin_Dry.XBAR2 # The coefficient of variation for minimum temperature.
- ACVTN = -1 × Tmin_Dry.C2 # The amplitude of the coefficient of variation for minimum temperature.
The values in the Final Value Result element “Temperature Params” can be copied by selecting and dragging with your mouse of the cells and pasting them into the inputs of TempGen.
Appendix A: Testing Results
The temperature simulator was tested at a location with 123 years of historical min and max daily temperature along with daily precipitation totals. Logan Utah was selected for this comparison. I constructed a PrecipGen model based on the measured historical precipitation so I could simulate the daily precipitation along with daily temperatures. This is important since the daily precipitation does impact the simulated temperatures. To compare historical and simulated daily minimum and maximum temperatures, I employ time shifting on the historical temperature data as a way to randomly sample the historical record. That way, I’m comparing a randomly sampled historical record to the output of the stochastic temperature simulation model. Below are the results when averaging the months.
Below is a similar chart showing the comparison of the average daily output instead of monthly averages.
Appendix B: GoldSim "Code"
While the model is not written in plain text, all of the functionality of the model can adequately be documented using pseudocode and comments.
TempGen Code
Inputs
Parameter | Description |
TXMD | Mean daily maximum temperature on dry days |
ATX | Amplitude for the seasonal variation of maximum temperature |
TXMW | Mean daily maximum temperature on wet days |
TN | Mean daily minimum temperature |
ATN | Amplitude for the seasonal variation of minimum temperature |
CVTX | Coefficient of variation for maximum temperature |
ACVTX | Amplitude correction for the CV of maximum temperature |
CVTN | Coefficient of variation for minimum temperature |
ACVTN | Amplitude correction for the CV of minimum temperature |
Cool_Start_Day | Phase shift for seasonal variation (default: day 200) |
PRCP | Linked to model output or time series |
Max_Sample | 2.6 Truncate normal distribution sampled for the random innovation vector |
Code:
# ======================================================
# GoldSim TempGen
# ======================================================
Array03 = Array_label Set, set members = [1, 2, 3]
a = matrix(0.567, 0.086, -0.002, 0.253, 0.504, -0.05,-0.006, -0.039, 0.244) #[Array03,Array03]>
b = matrix(0.781, 0, 0, 0.328, 0.637, 0, 0.238, -0.341, 0.873) #[Array03,Array03]>
Max_Sample = 2.6
e = Stochastic("Normal", mean=0, sd=1, truncate_maximum = Max_Sample) # Sampled daily [Array03]
r = vector(0) #[Array03]
rr = vector(0) #[Array03]
for (i = 1; ~i <= 3; i = ~i + 1):
for (j = 1; ~j <= 3; j = ~j + 1):
r[~i] = ~r[~i] + ~b[~i, ~j] * ~e[~j]
rr[~i] = ~rr[~i] + ~a[~i, ~j] * ~Result[~j]
x = ~r + ~rr
d1 = TXMD - TXMW
dt = cos(0.0172 * (DayOfYear - Cool_Start_Day))
txm = TXMD + ATX * ~dt
xcr1 = 0.06
if(CVTX + ACVTX * ~dt >= 0):
xcr1 = CVTX + ACVTX * ~dt
txs = (~txm * ~xcr1)
txm1 = ~txm - ~d1
txs1 = (~txm1 * ~xcr1)
txxs = ~txs
txxm = ~txm
Wet_Today = PRCP > 0 mm/d
if(Wet_Today):
txxs = ~txs1
txxm = ~txm1
tnm = TN + ATN * ~dt
xcr2 = 0.06
if(CVTN + ACVTN * ~dt >= 0):
xcr2 = CVTN + ACVTN * ~dt
tns = (~tnm * ~xcr2)
tMin1 = x[2] * tns + tnm
tMax1 = x[1] * txxs + txxm
tMin = min(tMax1, tMin1) #Minimum daily temperature after applying the correction factor
tMax = max(tMax1, tMin1) #Maximum daily temperature after applying the correction factor
tAvg = (tMax + tMin) / 2 #Average of Min and Max temperature
TempGen PAR
Code:
# ======================================================
# GoldSim TempGen Parameter Generation
# ======================================================
# Simulation Settings:
# Start and End dates = historical period of study, specified as dates
# Time step = 1 day
# Inputs
# Time series records with datetime index and float value on each consecutive calendar day of the historical time period.
Precipitation_TS = Time Series of daily precipitation totals
Tmax_TS = Time Series of Daily Maximum Temperature
Tmin_TS = Time Series of Daily Minimum Temperature
#Calculations performed in Containers MSD_Tmax and MSD_Tmin occur on each time step of the historical simulation period.
PRCP = Precipitation_TS(~datetime) # Lookup value by datetime
Tmax = Tmax_TS(~datetime) # Lookup value by datetime, convert to K
Tmin = Tmin_TS(~datetime) # Lookup value by datetime, convert to K
Wet_Today = PRCP >= 0 mmm/d
Dry_Today = not Wet_Today
#In both MSD_Tmax and MSD_Tmin Container, integrate the following over the period of simulation and store final values in monthly bins:
XN = Integrate(vector(if(row = Month and Dry_Today, 1, 0)) / 1d) #count all wet days
SUM = Integrate(vector(if(row = Month and Dry_Today, Tmax, 0K)) / 1 d) #Integrate values
SS = Integrate(vector(if(row = Month and Dry_Today, Tmax * Tmax, 0 K2)) / 1d) #Integrate values squared
XN1 = Integrate(vector(if(row = Month and Wet_Today, 1, 0)) / 1d) #count all wet days
SUM1 = Integrate(vector(if(row = Month and Wet_Today, Tmax, 0K)) / 1 d) #Integrate values
SS1 = Integrate(vector(if(row = Month and Wet_Today, Tmax * Tmax, 0 K2)) / 1d) #Integrate values squared
#When Integration is complete, at the end of the simulation, perform Fourier analysis for Tmax dry and wet, and Tmin dry
#In both Tmax_Dry and Tmax_Wet Containers (repeat below steps for each Container)
XM = vector(if(XN[row] <= 0, 0 K, SUM[row] / XN[row]))
SD = vector(if(XN[row] <= 0, 0 K, sqrt((SS[row] - SUM[row] * SUM[row] / XN[row]) / (XN[row] - 1))))
CX = SD / XM
S = sumv(XM)
S1 = sumv(SD)
S2 = sumv(CX)
XBAR = S / 12
XBAR1 = S1 / 12
XBAR2 = S2 / 12
#In Looping Container SumB_SumA (loop 12 times):
n = ~LoopCount
SUMA = SUMApv + (XM[n] - XBAR) * COS(6.2832 * n / 12)
SUMA1 = SUMA1pv + (SD[n] - XBAR1) * COS(6.2832 * n / 12)
SUMA2 = SUMA2pv + (CX[n] - XBAR2) * COS(6.2832 * n / 12)
SUMB = SUMBpv + (XM[n] - XBAR) * SIN(6.2832 * n / 12)
SUMB1 = SUMB1pv + (SD[n] - XBAR1) * SIN(6.2832 * n / 12)
SUMB2 = SUMB2pv + (CX[n] - XBAR2) * SIN(6.2832 * n / 12)
SUMApv = SUMA
SUMA1pv = SUMA1
SUMA2pv = SUMA2
SUMBpv = SUMB
SUMB1pv = SUMB1
SUMB2pv = SUMB2
A = SUMA * (2 / 12)
A1 = SUMA1 * (2 / 12)
A2 = SUMA2 * (2 / 12)
B = SUMB * (2 / 12)
B1 = SUMB1 * (2 / 12)
B2 = SUMB2 * (2 / 12)
#Phase
T = atan(-B / A)
T1 = atan(-B1 / A1)
T2 = atan(-B2 / A2)
#Amplitude
C = A / cos(T)
C1 = A1 / cos(T1)
C2 = A2 / cos(T2)
TXMD = Tmax_Dry.XBAR #Daily mean max temp (dry)
ATX = -1 * TmaxDry.C #Amplitude Max Temp (dry)
TXMW = Tmax_Wet.XBAR #Daily mean max temp (wet)
CVTX = Tmax_Dry.XBAR2 #Mean coefficient of variation of Tmax (dry) aka "u"
ACVTX = -1 * Tmax_Dry.C2 #Amplitude of coefficient of variation of Tmax (wet or dry) aka "C"
# Repeat all inside MSD_Tmin, doing same calculations but using Tmin as input.
# …Skipping to the end part:
TN = Tmin_Dry.XBAR #Daily mean min temp (dry)
ATN = -1 * Tmin_Dry.C #Amplitude Min Temp (dry)
CVTN = Tmin_Dry.XBAR2 #Mean coefficient of variation of Tmin (dry) aka "u"
ACVTN = -1 * Tmin_Dry.C2 #Amplitude of coefficient of variation of Tmin (wet or dry) aka "C"
References:
Richardson, C. W. (1982b). Dependence structure of daily temperature and solar radiation. Transactions of the ASAE, 25(3), 735–739.
Richardson, C. W., & Wright, D. A. (1984). WGEN: A Model for Generating Daily Weather Variables (USDA Agriculture Research Service Publication ARS-8). United States Department of Agriculture.
Box, G. E. P., Jenkins, G. M., Reinsel, G. C., & Ljung, G. M. (2015). Time Series Analysis: Forecasting and Control (5th ed.). Wiley.
Kalman, R. E. (1960). "A New Approach to Linear Filtering and Prediction Problems." Journal of Basic Engineering, 82(1), 35–45.
Comments
0 comments
Please sign in to leave a comment.