File size: 3,866 Bytes
6ee917b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import Foundation


/// The required functions to implement a reader that provides derived variables
protocol GenericReaderDerived: GenericReaderProtocol {
    associatedtype Derived: RawRepresentableString
    associatedtype ReaderNext: GenericReaderProtocol
    
    var reader: ReaderNext { get }

    func get(derived: Derived, time: TimerangeDtAndSettings) throws -> DataAndUnit
    func prefetchData(derived: Derived, time: TimerangeDtAndSettings) throws
    
    func get(raw: ReaderNext.MixingVar, time: TimerangeDtAndSettings) throws -> DataAndUnit
    func prefetchData(raw: ReaderNext.MixingVar, time: TimerangeDtAndSettings) throws
}

/// Parameters for tilted radiation calculation
struct GenericReaderOptions {
    /// Tilt of a solar panel for GTI calculation. 0° horizontal, 90° vertical.
    private var tilt: Float
    
    /// Azimuth of a solar panel for GTI calculation. 0° south, -90° east, 90° west
    private var azimuth: Float
    
    public init(tilt: Float? = nil, azimuth: Float? = nil) {
        self.tilt = tilt ?? 0
        self.azimuth = azimuth ?? 0
    }
    
    /// Tilt of a solar panel for GTI calculation. 0° horizontal, 90° vertical. Throws out of bounds error.
    func getTilt() throws -> Float {
        guard tilt.isNaN || (tilt >= 0 && tilt <= 90) else {
            throw ForecastapiError.generic(message: "Parameter `&tilt=` must be within 0° and 90°")
        }
        return tilt
    }
    
    /// Azimuth of a solar panel for GTI calculation. 0° south, -90° east, 90° west. Throws out of bounds error.
    func getAzimuth() throws -> Float {
        guard azimuth.isNaN || (azimuth >= -180 && azimuth <= 180) else {
            throw ForecastapiError.generic(message: "Parameter `&azimuth=` must be within -180° and 180°")
        }
        return azimuth
    }
}

extension GenericReaderDerived {
    var modelLat: Float {
        reader.modelLat
    }
    
    /*var domain: ReaderNext.Domain {
        return reader.domain
    }*/
    
    var modelLon: Float {
        reader.modelLon
    }
    
    var modelElevation: ElevationOrSea {
        reader.modelElevation
    }
    
    var modelDtSeconds: Int {
        reader.modelDtSeconds
    }
    
    var targetElevation: Float {
        reader.targetElevation
    }
    
    func prefetchData(variable: VariableOrDerived<ReaderNext.MixingVar, Derived>, time: TimerangeDtAndSettings) throws {
        switch variable {
        case .raw(let raw):
            return try prefetchData(raw: raw, time: time)
        case .derived(let derived):
            return try prefetchData(derived: derived, time: time)
        }
    }
    
    func get(variable: VariableOrDerived<ReaderNext.MixingVar, Derived>, time: TimerangeDtAndSettings) throws -> DataAndUnit {
        switch variable {
        case .raw(let raw):
            return try get(raw: raw, time: time)
        case .derived(let derived):
            return try get(derived: derived, time: time)
        }
    }
    
    func getStatic(type: ReaderStaticVariable) throws -> Float? {
        return try reader.getStatic(type: type)
    }
    
    func prefetchData(variables: [VariableOrDerived<ReaderNext.MixingVar, Derived>], time: TimerangeDtAndSettings) throws {
        try variables.forEach { variable in
            try prefetchData(variable: variable, time: time)
        }
    }
}

/// A reader that does not modify reader. E.g. pass all reads directly to reader
protocol GenericReaderDerivedSimple: GenericReaderDerived {

}

extension GenericReaderDerivedSimple {
    func get(raw: ReaderNext.MixingVar, time: TimerangeDtAndSettings) throws -> DataAndUnit {
        try reader.get(variable: raw, time: time)
    }
    
    func prefetchData(raw: ReaderNext.MixingVar, time: TimerangeDtAndSettings) throws {
        try reader.prefetchData(variable: raw, time: time)
    }
}