open-wether / Sources /App /Helper /Array3D.swift
soiz1's picture
Migrated from GitHub
6ee917b verified
import Foundation
struct Array3D {
var data: [Float]
/// slowest
let dim0: Int
let dim1: Int
/// Fastest dim
let dim2: Int
var count: Int {
return dim0 * dim1 * dim2
}
public init(data: [Float], dim0: Int, dim1: Int, dim2: Int) {
if (data.count != dim0 * dim1 * dim2) {
fatalError("Wrong Array3D dimensions. dim0=\(dim0) dim1=\(dim1) dim2=\(dim2) count=\(data.count)")
}
self.data = data
self.dim0 = dim0
self.dim1 = dim1
self.dim2 = dim2
}
public init(repeating: Float, dim0: Int, dim1: Int, dim2: Int) {
self.data = [Float](repeating: repeating, count: dim0 * dim1 * dim2)
self.dim0 = dim0
self.dim1 = dim1
self.dim2 = dim2
}
@inlinable subscript(d0: Int, d1: Int, d2: Int) -> Float {
get {
assert(d0 < dim0, "dim0 subscript invalid: \(d0) with dim0=\(dim0)")
assert(d1 < dim1, "dim1 subscript invalid: \(d1) with dim1=\(dim1)")
assert(d2 < dim2, "dim2 subscript invalid: \(d2) with dim2=\(dim2)")
return data[d0 * dim1 * dim2 + d1 * dim2 + d2]
}
set {
assert(d0 < dim0, "dim0 subscript invalid: \(d0) with dim0=\(dim0)")
assert(d1 < dim1, "dim1 subscript invalid: \(d1) with dim1=\(dim1)")
assert(d2 < dim2, "dim2 subscript invalid: \(d2) with dim2=\(dim2)")
data[d0 * dim1 * dim2 + d1 * dim2 + d2] = newValue
}
}
}
public struct Array3DFastTime {
public var data: [Float]
public let nLocations: Int
public let nLevel: Int
public let nTime: Int
public init(data: [Float], nLocations: Int, nLevel: Int, nTime: Int) {
if (data.count != nLocations * nTime * nLevel) {
fatalError("Wrong Array2DFastTime dimensions. nLocations=\(nLocations) nLevel=\(nLevel) nTime=\(nTime) count=\(data.count)")
}
self.data = data
self.nLocations = nLocations
self.nLevel = nLevel
self.nTime = nTime
}
public init(nLocations: Int, nLevel: Int, nTime: Int) {
self.data = .init(repeating: .nan, count: nLocations * nTime * nLevel)
self.nLocations = nLocations
self.nTime = nTime
self.nLevel = nLevel
}
@inlinable subscript(location: Int, level: Int, time: Int) -> Float {
get {
precondition(location < nLocations, "location subscript invalid: \(location) with nLocations=\(nLocations)")
precondition(level < nLevel, "level subscript invalid: \(level) with nLevel=\(nLevel)")
precondition(time < nTime, "time subscript invalid: \(time) with nTime=\(nTime)")
return data[location * nTime * nLevel + level * nTime + time]
}
set {
precondition(location < nLocations, "location subscript invalid: \(location) with nLocations=\(nLocations)")
precondition(level < nLevel, "level subscript invalid: \(level) with nLevel=\(nLevel)")
precondition(time < nTime, "time subscript invalid: \(time) with nTime=\(nTime)")
data[location * nTime * nLevel + level * nTime + time] = newValue
}
}
@inlinable subscript(location: Int, level: Int, time: Range<Int>) -> ArraySlice<Float> {
get {
precondition(location < nLocations, "location subscript invalid: \(location) with nLocations=\(nLocations)")
precondition(level < nLevel, "level subscript invalid: \(level) with nLevel=\(nLevel)")
precondition(time.upperBound <= nTime, "time subscript invalid: \(time) with nTime=\(nTime)")
return data[time.add(location * nTime * nLevel + level * nTime)]
}
set {
precondition(location < nLocations, "location subscript invalid: \(location) with nLocations=\(nLocations)")
precondition(level < nLevel, "level subscript invalid: \(level) with nLevel=\(nLevel)")
precondition(time.upperBound <= nTime, "time subscript invalid: \(time) with nTime=\(nTime)")
data[time.add(location * nTime * nLevel + level * nTime)] = newValue
}
}
/// One spatial field into time-series array
@inlinable subscript(location: Range<Int>, level: Int, time: Int) -> [Float] {
get {
precondition(location.upperBound <= nLocations, "location subscript invalid: \(location) with nLocations=\(nLocations)")
precondition(level < nLevel, "level subscript invalid: \(level) with nLevel=\(nLevel)")
precondition(time < nTime, "time subscript invalid: \(nTime) with nTime=\(nTime)")
var out = [Float]()
out.reserveCapacity(location.count)
for loc in location {
out.append(self[loc, level, time])
}
return out
}
set {
precondition(location.upperBound <= nLocations, "location subscript invalid: \(location) with nLocations=\(nLocations)")
precondition(level < nLevel, "level subscript invalid: \(level) with nLevel=\(nLevel)")
precondition(time < nTime, "time subscript invalid: \(nTime) with nTime=\(nTime)")
precondition(newValue.count == location.count, "Array and location count do not match")
for (loc, value) in zip(location, newValue) {
data[loc * nTime * nLevel + level * nTime + time] = value
}
}
}
@inlinable subscript(location: Range<Int>, level: Int, time: Range<Int>) -> ArraySlice<Float> {
get {
precondition(location.upperBound <= nLocations, "location subscript invalid: \(location) with nLocations=\(nLocations)")
precondition(level < nLevel, "level subscript invalid: \(level) with nLevel=\(nLevel)")
precondition(time.upperBound <= nTime, "time subscript invalid: \(nTime) with nTime=\(nTime)")
var out = [Float]()
out.reserveCapacity(location.count * time.count)
for loc in location {
out.append(contentsOf: self[loc, level, time])
}
return ArraySlice(out)
}
set {
precondition(location.upperBound <= nLocations, "location subscript invalid: \(location) with nLocations=\(nLocations)")
precondition(level < nLevel, "level subscript invalid: \(level) with nLevel=\(nLevel)")
precondition(time.upperBound <= nTime, "time subscript invalid: \(nTime) with nTime=\(nTime)")
precondition(newValue.count == location.count, "Array and location count do not match")
for loc in location {
data[time.add(loc * nTime * nLevel + level * nTime)] = newValue[(time.count * loc ..< time.count * (loc+1)).add(newValue.startIndex)]
}
}
}
/// One spatial field into time-series array
@inlinable subscript(location: Range<Int>, level: Int, time: Int) -> ArraySlice<Float> {
get {
precondition(location.upperBound <= nLocations, "location subscript invalid: \(location) with nLocations=\(nLocations)")
precondition(level < nLevel, "level subscript invalid: \(level) with nLevel=\(nLevel)")
precondition(time < nTime, "time subscript invalid: \(nTime) with nTime=\(nTime)")
var out = [Float]()
out.reserveCapacity(location.count)
for loc in location {
out.append(self[loc, level, time])
}
return ArraySlice(out)
}
set {
precondition(location.upperBound <= nLocations, "location subscript invalid: \(location) with nLocations=\(nLocations)")
precondition(level < nLevel, "level subscript invalid: \(level) with nLevel=\(nLevel)")
precondition(time < nTime, "time subscript invalid: \(nTime) with nTime=\(nTime)")
precondition(newValue.count == location.count, "Array and location count do not match")
for (loc, value) in zip(location, newValue) {
data[loc * nTime * nLevel + level * nTime + time] = value
}
}
}
}