CATRAS: Difference between revisions

From Cybis Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 10: Line 10:


[[Category: Dendro data format]] [[Category:Software]]
[[Category: Dendro data format]] [[Category:Software]]
==Technical details==
A Catras file could be read as a byte array i.e. as an array of 8-bit unsigned integers, meaning all with values in the range 0-255.
In the description below, the indexes of the array "arr" goes from 0 to n-1 where n is the number of bytes within the file.
<br>16-bit integer values are each stored as a pair of bytes. Certain parameters are stored at fixed index positions within the file. E.g.
<pre>
Dim registeredRings As Integer = arr(45) * 256 + arr(44)
</pre>
<p>Also the year number of the oldest ring is stored at fix positions:
<pre>
Dim firstYear As Integer = arr(54) + 256 * arr(55)
</pre>
The actual ring width data is surrounded by ring width data with very high ring width values.
Some times there are several such big ring width values both in the front and at the end of the series.
The code below removes those "zero-data", though it may possibly represent zero-rings as measured from
the heart of the sample and at the outer side of the sample.
Comments are stored using the old "IBM PC" character set.
The Catras file format is said to be able to store also information on latewood/earlywood, though to us the details of this are not known.
<pre>
'Visual Basic .NET code (Visual Studio 2008)
    Private Function readCATRAS_File(ByVal fileName As String, ByRef ringWidthArr() As Single, ByRef lastYear As Integer, ByRef comment As String) As Boolean
        On Error GoTo atExit
        Dim arr() As Byte
        arr = My.Computer.FileSystem.ReadAllBytes(fileName)
        Dim veryFirstIx As Integer = 0
        Dim veryLastIx As Integer = arr.Length - 1
        Dim registeredRings As Integer = arr(45) * 256 + arr(44)
        Dim firstYear As Integer = arr(54) + 256 * arr(55)
        Dim ixOfFirstDataPair As Integer = 128  'data at index 128 and 129 is always 241, 216 - more such pairs may be there! It is also sort of an end signature
        Dim ixOfLastDataPair As Integer = ixOfFirstDataPair + (registeredRings - 1) * 2  'the address of the first member of a ring width pair
        If ixOfLastDataPair + 1 > veryLastIx Then Return False
        'Find first non-zero ring
        Dim rWidth As Double, ring As Integer
        Dim ixOfCurrentPair As Integer
        Dim ixOfStartDataPair As Integer = ixOfFirstDataPair
        For ring = 0 To registeredRings - 1
            ixOfCurrentPair = ixOfFirstDataPair + 2 * ring
            rWidth = (arr(ixOfCurrentPair + 1) * 256 + arr(ixOfCurrentPair)) / 100
            If rWidth > 50 Then
                firstYear += 1  'ignore this zero ring
            Else
                ixOfStartDataPair = ixOfCurrentPair  'first non-zero ring width
                Exit For
            End If
        Next
        'Check also for zero rings at the trailing end:
        Dim stopAdr As Integer = ixOfLastDataPair
        Dim adr As Integer
        For adr = ixOfLastDataPair - 12 To ixOfLastDataPair Step 2  'check 6 last widths, where the very last certainly is zero
            rWidth = (arr(adr + 1) * 256 + arr(adr)) / 100
            If rWidth < 50 Then
                stopAdr = adr  'this is still a non-zero ring
            Else
                Exit For  'a zero ring found
            End If
        Next
        Dim rings As Integer = CInt((stopAdr + 1 - ixOfStartDataPair + 1) / 2)
        ReDim ringWidthArr(0 To rings)
        lastYear = firstYear + rings - 1
        Dim targetWidthIx As Integer
        Dim targetAdr As Integer = ixOfStartDataPair
        For ring = 1 To rings
            targetWidthIx = rings - ring + 1
            rWidth = (arr(targetAdr + 1) * 256 + arr(targetAdr)) / 100
            ringWidthArr(targetWidthIx) = CSng(rWidth)
            targetAdr += 2
        Next
        comment = ""
        For k As Integer = 0 To 43
            comment &= ibmPCToLatinChar(arr(k))
        Next
        Return True
atExit:
    End Function
    Function ibmPCToLatinChar(ByVal b As Byte) As Char
        'This conversion may not be complete
        Dim k As Integer
        If latinVersion Is Nothing Then
            ReDim latinVersion(0 To 255)
            For k = 0 To 255
                latinVersion(k) = Chr(k)
            Next
            latinVersion(134) = "å"c
            latinVersion(132) = "ä"c
            latinVersion(148) = "ö"c
            latinVersion(129) = "ü"c
            latinVersion(130) = "é"c
            latinVersion(135) = "ç"c
            latinVersion(145) = "æ"c
            latinVersion(164) = "ñ"c
            latinVersion(143) = "Å"c
            latinVersion(142) = "Ä"c
            latinVersion(153) = "Ö"c
            latinVersion(154) = "Ü"c
            latinVersion(144) = "É"c
            latinVersion(128) = "Ç"c
            latinVersion(146) = "Æ"c
            latinVersion(165) = "Ñ"c
        End If
        Return latinVersion(b)
    End Function
</pre>

Revision as of 22:47, 31 December 2009

CATRAS, Computer Aided Tree Ring Analysis System, a database solution. The system is described by R. W. Aniol (1983).[1][2]

Although the system is able to export in various formats, it uses non-text files with the filename extension .cat. There are programs available (e.g. CONVERT5) to convert such files into tucson-format.[3]

CDendro (at least the test/development version) is able to read most Catras formatted files.

References

  1. R. W. Aniol: Tree-ring analysis using CATRAS. Dendrochronologia 1:45–53 (1983)
  2. J. R. Pilcher: Sample Preparation, Cross-dating, and Measurement in: Methods of dendrochronology p.49, ISBN 978-0-7923-0586-6
  3. See list in Henri D. Grissino-Mayer's Ultimate Tree-Ring Web Pages: Software (at the end of the page).


Technical details

A Catras file could be read as a byte array i.e. as an array of 8-bit unsigned integers, meaning all with values in the range 0-255.

In the description below, the indexes of the array "arr" goes from 0 to n-1 where n is the number of bytes within the file.
16-bit integer values are each stored as a pair of bytes. Certain parameters are stored at fixed index positions within the file. E.g.

Dim registeredRings As Integer = arr(45) * 256 + arr(44)

Also the year number of the oldest ring is stored at fix positions:

Dim firstYear As Integer = arr(54) + 256 * arr(55)

The actual ring width data is surrounded by ring width data with very high ring width values. Some times there are several such big ring width values both in the front and at the end of the series. The code below removes those "zero-data", though it may possibly represent zero-rings as measured from the heart of the sample and at the outer side of the sample.

Comments are stored using the old "IBM PC" character set.

The Catras file format is said to be able to store also information on latewood/earlywood, though to us the details of this are not known.

'Visual Basic .NET code (Visual Studio 2008)
    Private Function readCATRAS_File(ByVal fileName As String, ByRef ringWidthArr() As Single, ByRef lastYear As Integer, ByRef comment As String) As Boolean
        On Error GoTo atExit
        Dim arr() As Byte
        arr = My.Computer.FileSystem.ReadAllBytes(fileName)
        Dim veryFirstIx As Integer = 0
        Dim veryLastIx As Integer = arr.Length - 1

        Dim registeredRings As Integer = arr(45) * 256 + arr(44)
        Dim firstYear As Integer = arr(54) + 256 * arr(55)

        Dim ixOfFirstDataPair As Integer = 128  'data at index 128 and 129 is always 241, 216 - more such pairs may be there! It is also sort of an end signature
        Dim ixOfLastDataPair As Integer = ixOfFirstDataPair + (registeredRings - 1) * 2  'the address of the first member of a ring width pair
        If ixOfLastDataPair + 1 > veryLastIx Then Return False

        'Find first non-zero ring
        Dim rWidth As Double, ring As Integer
        Dim ixOfCurrentPair As Integer
        Dim ixOfStartDataPair As Integer = ixOfFirstDataPair
        For ring = 0 To registeredRings - 1
            ixOfCurrentPair = ixOfFirstDataPair + 2 * ring
            rWidth = (arr(ixOfCurrentPair + 1) * 256 + arr(ixOfCurrentPair)) / 100
            If rWidth > 50 Then
                firstYear += 1  'ignore this zero ring
            Else
                ixOfStartDataPair = ixOfCurrentPair   'first non-zero ring width
                Exit For
            End If
        Next

        'Check also for zero rings at the trailing end:
        Dim stopAdr As Integer = ixOfLastDataPair
        Dim adr As Integer
        For adr = ixOfLastDataPair - 12 To ixOfLastDataPair Step 2   'check 6 last widths, where the very last certainly is zero
            rWidth = (arr(adr + 1) * 256 + arr(adr)) / 100
            If rWidth < 50 Then
                stopAdr = adr  'this is still a non-zero ring
            Else
                Exit For   'a zero ring found
            End If
        Next

        Dim rings As Integer = CInt((stopAdr + 1 - ixOfStartDataPair + 1) / 2)
        ReDim ringWidthArr(0 To rings)
        lastYear = firstYear + rings - 1

        Dim targetWidthIx As Integer
        Dim targetAdr As Integer = ixOfStartDataPair
        For ring = 1 To rings
            targetWidthIx = rings - ring + 1
            rWidth = (arr(targetAdr + 1) * 256 + arr(targetAdr)) / 100
            ringWidthArr(targetWidthIx) = CSng(rWidth)
            targetAdr += 2
        Next
        comment = ""
        For k As Integer = 0 To 43
            comment &= ibmPCToLatinChar(arr(k))
        Next

        Return True
atExit:
    End Function

    Function ibmPCToLatinChar(ByVal b As Byte) As Char
        'This conversion may not be complete
        Dim k As Integer
        If latinVersion Is Nothing Then
            ReDim latinVersion(0 To 255)
            For k = 0 To 255
                latinVersion(k) = Chr(k)
            Next
            latinVersion(134) = "å"c
            latinVersion(132) = "ä"c
            latinVersion(148) = "ö"c
            latinVersion(129) = "ü"c
            latinVersion(130) = "é"c
            latinVersion(135) = "ç"c
            latinVersion(145) = "æ"c
            latinVersion(164) = "ñ"c
            latinVersion(143) = "Å"c
            latinVersion(142) = "Ä"c
            latinVersion(153) = "Ö"c
            latinVersion(154) = "Ü"c
            latinVersion(144) = "É"c
            latinVersion(128) = "Ç"c
            latinVersion(146) = "Æ"c
            latinVersion(165) = "Ñ"c
        End If
        Return latinVersion(b)
    End Function