-
Notifications
You must be signed in to change notification settings - Fork 0
/
optimizeKaticBody.jl
317 lines (276 loc) · 9.72 KB
/
optimizeKaticBody.jl
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
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
using Snopt
using Plots
using LatinHypercubeSampling
###################################################################################
# Functions
# To account for different wind directions this function rotates the coordinate
# frame of the turbines to line them with the wind
function rotateFrame(theta,turbines,n)
R = [cosd(theta) sind(theta) 0; -sind(theta) cosd(theta) 0; 0 0 1]
temp = zeros(3,n)
for i = 1:n
temp[:,i] = R*[turbines[1:2,i];0]
temp[3,i] = turbines[3,i]
end
return temp
end
# Resets the coordinate frame to give positions of turbines
function resetTurbineFrame(theta,turbines,n)
theta = -theta
R = [cosd(theta) sind(theta) 0; -sind(theta) cosd(theta) 0; 0 0 1]
temp = zeros(3,n)
for i = 1:n
temp[:,i] = R*[turbines[1:2,i];0]
end
return temp[1:2,:]
end
# function to calculate the wake deficit (1-v/u) from a single turbine
function wakeDeficit(Ct,k,x,D)
return (1-sqrt(1-Ct))/((1+2*k*x/D)^2)
end
# fuction to calculate wake deficit of multiple combined wakes (pass in array of deficits)
function wakeInteractionDeficit(deficit)
total = 0
for def in deficit
total += def^2
end
return sqrt(total)
end
# d is in terms of the diameter (0.5 D)
# calculates the area of a slice that goes to the edges of the turbine
function calculateAreaOfTurbineSegment(d)
theta = 2*acos(1-2*d)
return (0.5*(theta-sin(theta)))/pi
end
# d1 and d2 are in terms of the diameter d2 > d1
# uses multiple percent areas of the turbine given by
# calculateAreaOfTurbineSegment to calculate percent areas of slices
# that dont extend to the edges
function calculatePercentAreaOfTurbineSlice(d1, d2)
if d1 == d2
return 0
end
if d2 < d1
temp = d1
d1 = d2
d2 = temp
end
if d1 < 0.5
if d2 <= 0.5
return calculateAreaOfTurbineSegment(d2) - calculateAreaOfTurbineSegment(d1)
elseif d2 > 0.5
return 1 - calculateAreaOfTurbineSegment(d1) - calculateAreaOfTurbineSegment(1-d2)
end
elseif d1 >= 0.5
if d2 > 0.5
return calculateAreaOfTurbineSegment(1-d1) - calculateAreaOfTurbineSegment(1-d2)
end
end
error("Error in calculatePercentAreaOfTurbineSlice")
end
function calculateDeficitOnSingleTurbine(turbines,Ct,k,numTurbine,n)
rightTurbineEdge = turbines[1,numTurbine] + .5*turbines[3,numTurbine]
leftTurbineEdge = turbines[1,numTurbine] - .5*turbines[3,numTurbine]
# wakes: Row 1 is where the left edge of the wake hits the turbine (.3 D)
# row 2 is when the right edge of the wake hits the turbine
# row 3 is the deficit of the single wake
wakes = zeros(3,n)
for i = 1:n
if i == numTurbine # a turbine is not affected by its own wake
continue
end
if turbines[2,i] <= turbines[2,numTurbine] # ignore turbines behind current turbine
continue
end
# calculate wake range at the distance from the turbine i
ranges = turbines[3,i]+k*(abs(turbines[2,i] - turbines[2,numTurbine]))
rightWakeEdge = turbines[1,i] + ranges
leftWakeEdge = turbines[1,i] - ranges
# if numTurbine falls in range determine which sections are affected
if (leftTurbineEdge >= rightWakeEdge) || (rightTurbineEdge <= leftWakeEdge)
# wake does not affect the turbine
continue
end
# The wake must affect the turbine, determine the center point of that effect and the radius
right = false
left = false
if rightWakeEdge <= rightTurbineEdge # right edge of wake hits turbine
right = true
end
if leftWakeEdge >= leftTurbineEdge # left edge of wake hits turbine
left = true
end
# calculate the deficit of this wake
wakes[3,i] = wakeDeficit(Ct,k,abs(turbines[2,i] - turbines[2,numTurbine]),turbines[3,i])
# define wake effect area with center and radius relative to the diameter
if right && left
# find where both edges of the wake hit the turbine relative to turbine's left edge
# in terms of the diameter
leftHit = (leftWakeEdge - leftTurbineEdge)/turbines[3,numTurbine]
rightHit = (rightWakeEdge - leftTurbineEdge)/turbines[3,numTurbine]
elseif right
# find where right edge of wake hits the turbine relative to left edge
leftHit = 0
rightHit = (rightWakeEdge - leftTurbineEdge)/turbines[3,numTurbine]
elseif left
# find where left edge of wake hits the turbine relative to the right edge
leftHit = (leftWakeEdge - leftTurbineEdge)/turbines[3,numTurbine]
rightHit = 1
elseif !right && !left
leftHit = 0
rightHit = 1
end
# store wake edges in wakes
wakes[1,i] = leftHit
wakes[2,i] = rightHit
end
# remove non-affecting wakes
remove = []
for i = 1:n
if wakes[2,i] == 0
remove = vcat(remove,i)
end
end
wakes = wakes[:,setdiff(1:end, tuple(remove...))]
if isempty(wakes)
return 0
end
# determine where wakes overlap and determine how much area is affected by
# different single wakes and wake combinations
order = zeros(size(wakes,1)*size(wakes,2),3)
for i = 1:size(wakes,1)
f = (i-1)*size(wakes,2)+1
l = f + size(wakes,2)-1
order[f:l,1] .= i
order[f:l,2] .= 1:size(wakes,2)
end
for i = 1:size(order,1)
row = convert(Int32,order[i,1])
col = convert(Int32,order[i,2])
order[i,3] = wakes[row,col]
end
order = sortslices(order,dims=1,by=x->x[3],rev=false)
# order is a list ordered by the third column with columns 1 and 2 being
# the row and column in wake at which the edge is located
active = convert(Array{Int8},zeros(length(wakes),1))
active[convert(Int32,order[1,2])] = 1
d1 = order[1,3]
totalArea = 0
totalDeficit = 0
def = transpose(wakes[3,:])
for i = 2:size(order,1)
d2 = order[i,3] # what is the distance of this point
currentDeficit = wakeInteractionDeficit(def .* active)
totalArea += calculatePercentAreaOfTurbineSlice(d1,d2)
totalDeficit += calculatePercentAreaOfTurbineSlice(d1,d2) * currentDeficit
if order[i,1] == 1 # start of stop the wake
active[convert(Int32,order[i,2])] = 1
else
active[convert(Int32,order[i,2])] = 0
end
d1 = d2
end
# println(totalArea)
# println(totalDeficit)
return totalDeficit
end
function calculateFarmDeficit(turbines,Ct,k,n)
deficit = 0
for i = 1:n
deficit += calculateDeficitOnSingleTurbine(turbines,Ct,k,i,n)
end
return deficit
end
#############################################################################
function farm(g, df, dg, x, deriv)
turbines = zeros(3,convert(Int32,length(x)/2))
diameter = 0.5
for i = 1:size(turbines,2)
# Set the turbines in a straight line along the center of the space provided with
# equal diameter
turbines[1,i] = x[(i*2)-1]
turbines[2,i] = x[(i*2)]
turbines[3,i] = diameter
end
# Set constants
k = 0.01 #determines the angle at which the wake expands at
Ct = 0.9 #thrust coefficient of the turbine
# Declare wind direction from North is 0, from East is 90
windDirection = 0
# Rotate the frame
turbines = rotateFrame(windDirection,turbines,n)
# Calculate the deficit
farmDeficit = calculateFarmDeficit(turbines,Ct,k,n)
fail = false
# Reset the frames
turbines = resetTurbineFrame(windDirection,turbines,n)
# reset wake frame
return farmDeficit, fail
end
# Create turbines
maxBox = 10
diameter = 0.5
n = 10 #number of turbines
x0 = []
starts = 20
plan = randomLHC(starts,n*2)
plan = plan .- 1
plan = plan .* maxBox/(starts-1)
xFinal = 0
obj = 0
for i = 1:starts
global x0 = plan[i,:]
lx = zeros(length(x0))
ux = zeros(length(x0)) .+ maxBox
lg = []
ug = []
rows = []
cols = []
xopt, fopt, info, out = snopta(farm, x0, lx, ux, lg, ug, rows, cols)
if i == 1
global xFinal = xopt
global obj = fopt
else
if fopt < obj
global xFinal = xopt
global obj = fopt
end
end
println(i)
end
# println(xFinal)
println(obj)
newTurbines = zeros(3,convert(Int32,length(xFinal)/2))
for i = 1:size(newTurbines,2)
# Set the turbines in a straight line along the center of the space provided with
# equal diameter
newTurbines[1,i] = xFinal[(i*2)-1]
newTurbines[2,i] = xFinal[(i*2)]
newTurbines[3,i] = diameter
end
windDirection = 0
newTurbines = rotateFrame(windDirection,newTurbines,n)
plots = zeros(n,4,3)
wakeLength = 20
k = 0.01
R = [cosd(-windDirection) sind(-windDirection) 0; -sind(-windDirection) cosd(-windDirection) 0; 0 0 1]
for i = 1:n # for each turbine
plots[i,1,1] = newTurbines[1,i] - .5*(newTurbines[3,i]/2 + 2*k*wakeLength) # left wake x
plots[i,1,2] = newTurbines[2,i] - wakeLength # left wake y
plots[i,2,1] = newTurbines[1,i] - newTurbines[3,i]/2 # left edge turbine x
plots[i,2,2] = newTurbines[2,i] # left edge turbine y
plots[i,3,1] = newTurbines[1,i] + newTurbines[3,i]/2 # right edge turbine x
plots[i,3,2] = newTurbines[2,i] # right edge turbine y
plots[i,4,1] = newTurbines[1,i] + .5*(newTurbines[3,i]/2 + 2*k*wakeLength) # right wake x
plots[i,4,2] = newTurbines[2,i] - wakeLength # right wake y
# rotate
for j = 1:4
plots[i,j,:] = R*plots[i,j,:]
end
if i == 1
plot(plots[i,:,1],plots[i,:,2],xlim=(-1,maxBox+1),ylim=(-1,maxBox+1),legend=false)
else
plot!(plots[i,:,1],plots[i,:,2])
end
end
savefig("optim.pdf")