-
Notifications
You must be signed in to change notification settings - Fork 2
/
points.py
214 lines (163 loc) · 5.74 KB
/
points.py
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# -*- coding: utf-8 -*-
""" Class representing XYZ and XY Points.
The class encapsulates data and metadata
for a particular point of lat/lon and height.
For instance, the class can be used to associate
wind speed or direction time series data with a certain
lat/lon and height.
Two classes are defined:
- XYPoint = Container of XYZ points, along with time series and metadata specific
to a geographical location
- XYZPoint = Container of time series and metadata of a specific
height.
A collection of points can represent model input to
interpolation functions or estimation routines.
Examples:
-Initialize an XYZ Point:
point.XYZPoint(20, 20, 50, 'model') # lat = 20, lon = 20, height = 50
Written by: Sagi Zisman ([email protected]) and Caleb Phillips ([email protected])
in collaboration with the National Renewable Energy Laboratories.
"""
from abc import ABC
import pandas as pd
class Point(ABC):
"""This class represents a base spatial point"""
_lat = None
_lon = None
_gid = None # If there exists a meaningful identifier for the point
# meta = None If metadata is needed further down the line
_point_type = None # Allowable types are 'model' or 'desired'
_time_series = None # A collection of time series objects
def __init__(self, lat, lon, point_type, gid=None, timeseries=None):
self._lat = lat
self._lon = lon
self._gid = gid
self._point_type = point_type
if timeseries is None:
self._time_series = []
else:
self._time_series = timeseries
@property
def lat(self):
return self._lat
@lat.setter
def lat(self, value):
self._lat = value
@property
def lon(self):
return self._lon
@lon.setter
def lon(self, value):
self._lon = value
@property
def gid(self):
return self._gid
@property
def is_model_point(self):
return self.is_model_point
@property
def point_type(self):
return self._point_type
def set_timeseries(self, timeseries):
"""
Appends a time series objects that represent valid time series
variables associated with the point.
"""
if type(timeseries) is list:
self._time_series += timeseries
else:
self._time_series.append(timeseries)
def get_timeseries_with_attribute(self, attribute):
for timeseries in self._time_series:
if timeseries._var == attribute:
return timeseries
# TODO: Raise AttributeNotFound Error
# concat_axis is valid if timeseries_set is 'all'
def save_timeseries(self,
filename,
identifier='',
timeseries_set='all',
concat_axis=1):
if timeseries_set == 'all':
concat_timeseries = \
pd.concat([
timeseries._timeseries for
timeseries in
self._time_series
], axis=concat_axis)
save_path = filename + \
(self._gid if
self._gid else
str(self._lat) + str(self._lon)) + \
'&' + identifier + '.csv'
concat_timeseries.to_csv(save_path)
return
class XYPoint(Point):
""" This class represents a type of horizontal point"""
_xyz_points = None
_surface_roughness = None
_displacement_height = None
def __init__(self,
lat,
lon,
point_type,
timeseries=None,
surface_roughness=None,
displacement_height=None):
self._surface_roughness = surface_roughness
self._displacement_height = displacement_height
super().__init__(lat, lon, point_type, timeseries)
# TODO: Add a raise exception code to signify that incompatible XYZ
# points were passed into the initializer
@classmethod
def from_xyz_points(cls, xyz_points):
current_point = None
for xyz_point in xyz_points:
if current_point is None or \
(xyz_point._lat == current_point._lat and
xyz_point._lon == current_point._lon):
current_point = xyz_point
# else:
# raise 'INCOMPATIBLE XY POINTS EXCEPTION'
xy_point = cls(lat=current_point.lat,
lon=current_point.lon,
point_type=current_point.point_type)
xy_point._xyz_points = xyz_points
return xy_point
@property
def xyz_points(self):
return self._xyz_points
@xyz_points.setter
def xyz_points(self, xyz_points):
self._xyz_points = xyz_points
@property
def surface_roughness(self):
return self._surface_roughness
@surface_roughness.setter
def surface_roughness(self, surface_roughness):
self._surface_roughness = surface_roughness
@property
def displacement_height(self):
return self._displacement_height
@displacement_height.setter
def displacement_height(self, displacement_height):
self._displacement_height = displacement_height
class XYZPoint(Point):
""" This class represents a unique spatial point"""
_height = None
_a_wtk_latlon = True
def __init__(self,
lat,
lon,
height,
point_type,
gid=None,
timeseries=None):
self._height = height
super().__init__(lat, lon, point_type, gid, timeseries)
@property
def height(self):
return self._height
@property
def a_wtk_latlon(self):
return self._a_wtk_latlon