TMY Weather Class Source Code

This is the source code for class that reads TMY (Typical Meteorological Year) files.

 

This is just to take a look at before you download -- if you want to download it, then download all the solar classes here:  Solar Tools Source

 

TMY Class:

'Solar Analysis Tools -
 'Copyright (C) 2005 Gary Reysa (gary@BuildItSolar.com)
 ' This program is free software; you can redistribute it and/or modify it
 ' under the terms of the GNU General Public License as published by the Free
 ' Software Foundation; either version 2 of the License, or (at your option)
 ' any later version.
 ' This program is distributed in the hope that it will be useful and encourage
 ' further development of solar tools, but   WITHOUT ANY WARRANTY; without even 
 ' the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 ' See the GNU General Public License   for more details.
' TMY class
' This class reads a TMY (Typical Meterlogal Year) weather files, and provides
' various methods to access the weather data 
'
' TMY weather files for many cities are available here:
' http://rredc.nrel.gov/solar/old_data/nsrdb/tmy2/
'
' This class is primarely intended to extract weather data from a TMY 
' for the purpose of driving a simulation that requires weather data.
'
' !!IMPORTANT NOTE!! that the TMY data is in SI units, but this class converts them to
' English units as it reads them.
' When you ask for TMY data from this class it will come out in English units!  <--------
' See notes for each field below.
' TODO:
'       Look at fixing up missing data
'       Should read the file header, and offer these fields as properties (e.g. city, ...)
'       Think about converting to an arraylist of TMYstruc
Imports System
Imports System.IO
Imports System.Math
    'TMY structure -- holds the data fields for one record from a TMY file -- there is one record
    ' for each hour of the year.
    ' Note: the units listed below are what is stored in array, many are converted from metric
    ' as read from the TMY files to English before storing in array wx
    Public Structure TMYstruc
        Dim Year As Short               'p 2 - 3  Year that data came from 69 to 90ish
        Dim Month As Single             'p 4 - 5  Month 
        Dim Day As Short                'p 6 - 7  Day
        Dim Hour As Short               'p 8 - 9  Hour
        Dim Ihorzext As Single          'p 10-13  Extraterrestrial Horz Rad (BTU/hr-ft^2)
        Dim Idnext As Single            'p 14-17  Extraterrestrial Direct Normal Rad (BTU/hr-ft^2)
        Dim Ihorzglo As Single          'p 18-21  Global Horz Rad (direct + diffuse) (BTU/hr-ft^2)
        Dim Idn As Single               'p 24-27  Direct Normal Radiation (BTU/hr-ft^2)
        Dim Ihorzdif As Single          'p 30-33  Diffuse rad on horz surface (BTU/hr-ft^2)
        Dim ILhorzglo As Single         'p 36-39  Total Illuminance on horz surf in (lux)
        Dim ILdn As Single              'p 42-45  Direct normal illuminance in (lux)
        Dim ILhorzdif As Single         'p 48-51  Diffuse illuminance on horz surf (lux)
        Dim SkyCov As Short             'p 60-65  Amount of sky dome covered in tenths
        Dim Tdb As Single               'p 68-71  Tempeerature - dry buld  (deg F)
        Dim Tdp As Single               'p 74-77  Temperature - dew pointbuld deg F
        Dim RH As Short                 'p 80-82  Relative Humidity (0 to 100)
        Dim Patm As Single              'p 85-88  Atmospheric pressure (lb/in^2)
        Dim WindDir As Short            'p 91-93  Wind Direction (0 to 360) calm is a zero
        Dim WindSpd As Single           'p 96-98  Wind speed in tenths of (MPH)
        Dim Viz As Single               'p 101-104 Visibility in tenths of miles
        Dim Ceil As Single              'p 107-111 Ceiling in ft (-1 indicates ulimited ceiling)
        Dim WxNow As String             'p 114-123 Present weather in a 10 diget code
        Dim Precip As Single            'p 124-126 Water precip in hour   (inches )     -- see Note 1
        Dim SnowDep As Single           'p 134-136 Snow depth in (inches) (for day or for hour?)
        Dim LastSnow As Short           'p 139-140 Days since last snowfall 
    ' keep these data sizes as small as possilbe there will be 365*24 = 8760 of them at 94 bytes each = 806k
    ' Note 1: Precipitable water does not mean actual rain in last hour -- it has something to do 
    '         with how much water is in the air?
    End Structure
Public Class TMYcls
    Private mTMYHeaderString As String
    ' wx array of TMY strucs holds a full year of TMY data -- one TMYstruc for each hour of year
    ' index zero holds nothing -- index one holds first record
    ' index for hour 1 of day 10 is 10*24 + 1 = 241  -- 
    ' hour 1 goes from midnight to 1am, 2 from 1am to 2am ... 24 from 11pm to 12midnight
    Private wx(365 * 24 + 1) As TMYstruc
    Private aDate As Date

    'Returns a TMYstruc for the hour index passed 
    Public Function TMYrec(ByVal ix As Integer) As TMYstruc
    If (ix >= 1) And (ix <= 365 * 24) Then
        Return wx(ix)
    Else
        Return Nothing
    End If
    End Function
' !!!! fix this -- want month 1 to jan (not month 0 is jan) -- this may be ok
'      want day 1 of month to be day one, not day zero is day 1
    ' returns TMYstruc for the Month, Day Of Month, and Hour passed
    Public Function TMYrecForDate(ByVal Month As Short, ByVal DayOfMonth As Short, ByVal Hr As Short) As TMYstruc
        aDate = DateSerial(2001, Month, DayOfMonth)
        Dim DOY As Integer = aDate.DayOfYear()
        If DOY > 365 Then DOY = 365
        If DOY < 1 Then DOY = 1
        Return TMYrec((DOY - 1) * 24 + Hr)
    End Function
    Public Function TMYrecIndexForDate(ByVal Month As Short, ByVal DayOfMonth As Short, ByVal Hr As Short) As Integer
        aDate = DateSerial(2001, Month, DayOfMonth)
        Dim DOY As Integer = aDate.DayOfYear()
        If DOY > 365 Then DOY = 365
        If DOY < 1 Then DOY = 1
        Return (DOY - 1) * 24 + Hr
    End Function

    Public Function TMYHeader() As String
        Return mTMYHeaderString
    End Function
    ' Fix Missing Data -- replace missing data with reasonable interpolations
    Public Sub FixMissingData()
        ' to be added
    End Sub
    ' Opens the passed TMY data file, and reads the data into array wx of TMY structures
    ' Returns true if successful, otherwise returns false
    Public Function ReadTMYFile(ByVal FN As String) As Boolean
        Dim sr As StreamReader
        ' Create an instance of StreamReader to read from a file.
        Try
            sr = New StreamReader(FN)
        Catch ex As Exception
            Console.WriteLine("TMYcls:ReadTMYFile: can't open TMY file: " & FN)
            Return False
        End Try
        Dim s As String
            ' Read and display the lines from the file until the end 
        ' of the file is reached.
        ' read the header line
        mTMYHeaderString = sr.ReadLine()
        Dim ix As Integer = 0
        ' don't use the zeroth entry in wx array
        wx(ix) = Nothing
        ix += 1
        Do
            s = sr.ReadLine()
            'Console.WriteLine(s)
            If (s Is Nothing) Then
            Else
                wx(ix).Year = s.Substring(1, 2)                'p 2 - 3  Year that data came from 69 to 90ish
                    wx(ix).Year = wx(ix).Year + 1900
                wx(ix).Month = s.Substring(3, 2)             'p 4 - 5  Month 
                wx(ix).Day = s.Substring(5, 2)               'p 6 - 7  Day
                wx(ix).Hour = s.Substring(7, 2)              'p 8 - 9  Hour
                wx(ix).Ihorzext = s.Substring(9, 4)          'p 10-13  Extraterrestrial Horz Rad
                    wx(ix).Ihorzext = wx(ix).Ihorzext * 0.317           ' convert to BTU/hr-ft^2
                wx(ix).Idnext = s.Substring(13, 4)           'p 14-17  Extraterrestrial Direct Normal Rad
                    wx(ix).Idnext = wx(ix).Idnext * 0.317               ' convert to BTU/hr-ft^2
                wx(ix).Ihorzglo = s.Substring(17, 4)          'p 18-21  Global Horz Rad (direct + diffuse) w/m^2
                    wx(ix).Ihorzglo = wx(ix).Ihorzglo * 0.317           ' convert to BTU/hr-ft^2
                wx(ix).Idn = s.Substring(23, 4)               'p 24-27  Direct Normal Rad w/m^2
                    wx(ix).Idn = wx(ix).Idn * 0.317                     ' convert to BTU...
                wx(ix).Ihorzdif = s.Substring(29, 4)          'p 30-33  Diffuse rad on horz surface w/m^2
                    wx(ix).Ihorzdif = wx(ix).Ihorzdif * 0.317           ' convert to BTU...
                wx(ix).ILhorzglo = s.Substring(35, 4)         'p 36-39  Total Illuminance on horz surf in lux/100
                    wx(ix).ILhorzglo = wx(ix).ILhorzglo * 100           ' convert to lux 
                wx(ix).ILdn = s.Substring(41, 4)              'p 42-45  Direct normal illuminance in lux/100
                    wx(ix).ILdn = wx(ix).ILdn * 100.0              ' conver to lux
                wx(ix).ILhorzdif = s.Substring(47, 4)         'p 48-51  Diffuse illuminance on horz surf in lux/100
                    wx(ix).ILhorzdif = wx(ix).ILhorzdif * 100               ' convert to lux
                wx(ix).SkyCov = s.Substring(59, 2)             'p 60-65  Amount of sky dome covered in tenths
                wx(ix).Tdb = s.Substring(67, 4)               'p 68-71  Tempeerature - dry buld  deg C
                    wx(ix).Tdb = (wx(ix).Tdb / 10.0) * 1.8 + 32   ' remove 10 multiplier and convert from deg C to deg F
                wx(ix).Tdp = s.Substring(73, 4)               'p 74-77  Temperature - dew pointbuld deg C
                    wx(ix).Tdp = (wx(ix).Tdp / 10.0) * 1.8 + 32  ' convert to deg F
                wx(ix).RH = s.Substring(79, 3)                'p 80-82  Relative Humidity (0 to 100)
                wx(ix).Patm = s.Substring(84, 4)              'p 85-88  Atmospheric pressure millibars
                    wx(ix).Patm = wx(ix).Patm * 0.0145              ' convert from millibar to lb/in^2
                wx(ix).WindDir = s.Substring(90, 3)            'p 91-93  Wind Direction (0 to 360) calm is a zero
                wx(ix).WindSpd = s.Substring(95, 3)           'p 96-98  Wind speed in tenths of M/Sec (0 to 400) 400 = 40.0 m/sec
                    wx(ix).WindSpd = (wx(ix).WindSpd / 10.0) * 2.237  ' remove multiplier of 10 and convert to MPH
                wx(ix).Viz = s.Substring(100, 4)               'p 101-104 Visibility in tenths of km (eg 1609 = 160.9 km/hr)
                    wx(ix).Viz = (wx(ix).Viz / 10.0) * 0.6214           'remove multiplier, and convert to mi
                wx(ix).Ceil = s.Substring(106, 5)              'p 107-111 Ceiling in meters (0 to 30450)
                If (wx(ix).Ceil = 77777) Then : wx(ix).Ceil = -1
                Else : wx(ix).Ceil = wx(ix).Ceil / 3.281
                End If                'convert from meter to feet
                wx(ix).WxNow = s.Substring(113, 10)             'p 114-123 Present weather in a 10 diget code
                wx(ix).Precip = s.Substring(123, 3)            'p 124-126 Water precip in hour   mm
                    wx(ix).Precip = wx(ix).Precip / 25.4            ' convert from mm to inches
                wx(ix).SnowDep = s.Substring(133, 3)           'p 134-136 Snow depth in cm (for day or for hour?)
                    wx(ix).SnowDep = wx(ix).SnowDep / 2.54          ' convert from cm to inches
                wx(ix).LastSnow = s.Substring(138, 2)          'p 139-140 Days since l= s.SubString(t snowfall
                If (wx(ix).LastSnow = 99) Then wx(ix).LastSnow = -1
                'Console.WriteLine("wx: year {0}   Month {1}    Day     {2}", wx(ix).Year, wx(ix).Month, wx(ix).Day)
                'Console.WriteLine("wx: Idn  {0}   Ceil {1}     LastSnw {2}", wx(ix).Idn, wx(ix).Ceil, wx(ix).LastSnow)
                ix = ix + 1
            End If
        Loop Until s Is Nothing
        sr.Close()
        Return True
    End Function
    Public Sub WxAtIx(ByVal ix As Integer)
        Console.WriteLine("Wx({0})", ix)
        Console.WriteLine("Year             {0,7}   ", wx(ix).Year)         ' = s.Substring(1, 2)                'p 2 - 3  Year that data came from 69 to 90ish
        Console.WriteLine("Month            {0,7}   ", wx(ix).Month)       ' = s.Substring(3, 2)             'p 4 - 5  Month 
        Console.WriteLine("Day              {0,7}   ", wx(ix).Day)      ' = s.Substring(5, 2)               'p 6 - 7  Day
        Console.WriteLine("Hour             {0,10:F2} ", wx(ix).Hour)     ' = s.Substring(7, 2)              'p 8 - 9  Hour
        Console.WriteLine("Ihorzext         {0,10:F2} ", wx(ix).Ihorzext) ' = s.Substring(9, 4)          'p 10-13  Extraterrestrial Horz Rad
        Console.WriteLine("Idnext           {0,10:F2} ", wx(ix).Idnext)   ' = s.Substring(13, 4)           'p 14-17  Extraterrestrial Direct Normal Rad
        Console.WriteLine("Ihorzglo         {0,10:F2} ", wx(ix).Ihorzglo) ' = s.Substring(17, 4)          'p 18-21  Global Horz Rad (direct + diffuse) w/m^2
        Console.WriteLine("Idn              {0,10:F2} ", wx(ix).Idn)      ' = s.Substring(23, 4)               'p 24-27  Direct Normal Rad w/m^2
        Console.WriteLine("Ihorzdif         {0,10:F2} ", wx(ix).Ihorzdif) ' = s.Substring(29, 4)          'p 30-33  Diffuse rad on horz surface w/m^2
        Console.WriteLine("ILhorzglo        {0,7} ", wx(ix).ILhorzglo) ' = s.Substring(35, 4)         'p 36-39  Total Illuminance on horz surf in Klux (0 to 130)
        Console.WriteLine("ILdn             {0,7} ", wx(ix).ILdn)      ' = s.Substring(41, 4)              'p 42-45  Direct normal illuminance in Klux
        Console.WriteLine("ILhorzdif        {0,7} ", wx(ix).ILhorzdif) ' = s.Substring(47, 4)         'p 48-51  Diffuse illuminance on horz surf
        Console.WriteLine("SkiCov           {0,10:F2} ", wx(ix).SkyCov)    ' = s.Substring(59, 2)             'p 60-65  Amount of sky dome covered in tenths
        Console.WriteLine("Tdb              {0,10:F2} ", wx(ix).Tdb)       ' = s.Substring(67, 4)               'p 68-71  Tempeerature - dry buld  deg C
        Console.WriteLine("Tdp              {0,10:F2} ", wx(ix).Tdp)       ' = s.Substring(73, 4)               'p 74-77  Temperature - dew pointbuld deg C
        Console.WriteLine("RH               {0,7} ", wx(ix).RH)        ' = s.Substring(79, 3)                'p 80-82  Relative Humidity (0 to 100)
        Console.WriteLine("Patm             {0,10:F2} ", wx(ix).Patm)      ' = s.Substring(84, 4)              'p 85-88  Atmospheric pressure millibars
        Console.WriteLine("WindDir          {0,7} ", wx(ix).WindDir)   ' = s.Substring(90, 3)            'p 91-93  Wind Direction (0 to 360) calm is a zero
        Console.WriteLine("WindSpd          {0,10:F2} ", wx(ix).WindSpd)   ' = s.Substring(95, 3)           'p 96-98  Wind speed in tenths of M/Sec (0 to 400) 400 = 40.0 m/sec
        Console.WriteLine("Viz              {0,10:F2} ", wx(ix).Viz)       ' = s.Substring(100, 4)               'p 101-104 Visibility in tenths of km (eg 1609 = 160.9 km/hr)
        Console.WriteLine("Ceil             {0,7} ", Round(wx(ix).Ceil))      ' = s.Substring(106, 5)              'p 107-111 Ceiling in meters (0 to 30450)
        Console.WriteLine("WxNow            {0,10:F2} ", wx(ix).WxNow)     ' = s.Substring(113, 10)             'p 114-123 Present weather in a 10 diget code
        Console.WriteLine("Precip           {0,10:F2} ", wx(ix).Precip)    ' = s.Substring(123, 3)            'p 124-126 Water precip in hour   mm
        Console.WriteLine("SnowDep          {0,10:F2} ", wx(ix).SnowDep)   ' = s.Substring(133, 3)           'p 134-136 Snow depth in cm (for day or for hour?)
        Console.WriteLine("LastSnow         {0,7} ", wx(ix).LastSnow)  ' = s.Substring(138, 2)          'p 139-140 Days since l= s.SubString(t snowfall
    End Sub
End Class