Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
test/test_windfield.asv
test/.mat
test/test_windshear.asv
Simulations/2021_9T_Data/setup.mlx
Simulations/2021_9T_Data/setup.mlx
after_init_simulation_T.mat
flowfield_xyz_1_steps.mat
flowfield_xyz_2_steps.mat
input_T_1_steps.mat
input_T_2_steps.mat
input_setUpTmpWFAndRun_2_steps.mat
15 changes: 15 additions & 0 deletions FLORIDynCL/FLORIDynCL.m
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@
SimTime = Sim.StartTime;
for it = 1:Sim.nSimSteps
Sim.SimStep = it;
turbulence = T.States_T(201, 3);
display("Info: 1: "+turbulence);

% ========== PREDICTION ==========
% Iterate OPs and states
T = iterateOPs(T,Sim,paramFLORIS,paramFLORIDyn);
Expand All @@ -68,11 +71,23 @@
T.intOPs = interpolateOPs(T);

% ======= Set up temp Wind farms & run FLORIS
if it == 2
filename = "input_setUpTmpWFAndRun_"+Sim.nSimSteps+"_steps.mat";
save(filename, 'T', 'paramFLORIS', 'Wind');
display("Saved: "+filename);
end
[tmpM,T] = setUpTmpWFAndRun(T,paramFLORIS,Wind);
turbulence = T.States_T(201, 3);
display("Info: 4: "+turbulence);

M((it-1)*T.nT+1:it*T.nT,2:4) = tmpM;
M((it-1)*T.nT+1:it*T.nT,1) = SimTime;
T.States_T(T.StartI,3) = tmpM(:,2);
M_int{it} = T.red_arr;
turbulence = T.States_T(201, 3);
format long e
display(tmpM(:,2));
display("Info: 5: "+turbulence);

% ========== Get Wind field variables & correct values
[T,Wind] = correctVel(T,Wind,SimTime,paramFLORIS,tmpM);
Expand Down
Binary file modified Simulations/2021_9T_Data/setup.mlx
Binary file not shown.
13 changes: 13 additions & 0 deletions Visualization/PlotFlowField.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
function [Vis] = PlotFlowField(T,~,Wind,Sim,Vis,paramFLORIDyn,paramFLORIS,SimTime)
%PLOTFLOWFIELD Generate full flow field plot
% exportgraphics(gcf,'9T_flow.pdf','ContentType','vector')

filename = "input_T_"+Sim.nSimSteps+"_steps.mat";
save(filename, 'T');
display("Saved: "+filename);

%% Preallocate field
nM = countMeasurements(Vis.FlowField.Data);
nM = 3;
Expand All @@ -42,6 +47,14 @@
Z = getMeasurements(X,Y,nM,T.posNac(1,3),T,paramFLORIS,Wind,Vis);
end

out = "v_min: " + min(min(Z(:,:,3)));
out = sprintf('%s\n', out);
out = out + "v_max: " + max(max(Z(:,:,3)));
display(out);
filename = "flowfield_xyz_"+Sim.nSimSteps+"_steps.mat";
save(filename, 'X', 'Y', 'Z');
display("Saved: "+filename);

%% Generate & save plots
% figure
% contourf(X,Y,Z(:,:,1),40,'LineColor','none')
Expand Down
4 changes: 4 additions & 0 deletions bin/count_loc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (c) 2025 Uwe Fechner
# SPDX-License-Identifier: BSD-3-Clause

scc -x csv -x toml ..
68 changes: 39 additions & 29 deletions main.m
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@
% ======================================================================= %

%% MainFLORIDyn Center-Line model
% Improved FLORIDyn approach over the gaussian FLORIDyn model
% % Improved FLORIDyn approach over the gaussian FLORIDyn model
% Link folder with simulation data
tic()
pathToSimulation = '2021_9T_Data';

%% Load data from the simulation
Expand All @@ -30,6 +31,7 @@

% Get the settings for the wind field, visualization, controller and Sim.
[Wind, Vis, Sim, Con] = setup();
% Sim.Dyn.OPiteration='IterateOPs_average';

% Add according functions to the search path
addFLORISPaths;
Expand All @@ -48,47 +50,55 @@
%% ====== Init simulation
% Run initial conditions until no more change happens
T = initSimulation(T,Wind,Sim,Con,Vis,paramFLORIDyn,paramFLORIS);

Vis.FlowField.Plot.Online = false;
%% ============ RUN SIMULATION ============
% T := Simulation state (OP states, Turbine states, wind field states(OPs))
% M := Measurements from the simulation (T_red, T_addedTI, T_Ueff, T_pow)
toc()
tic
% Sim.EndTime = 20000;
Sim.nSimSteps = 2;

filename = "after_init_simulation_T.mat";
save(filename, 'T');
display("Saved: "+filename);

[T,M,Vis,Mint] = FLORIDynCL(T,Wind,Sim,Con,Vis,paramFLORIDyn,paramFLORIS);
t = toc;
disp(['Sec. per sim. step: ' num2str(t/Sim.nSimSteps) ' with '...
num2str(T.nT) ' turbine(s), total sim. time: ' num2str(t) ' s.'])
%% Plotting & visualization

% Measurements
if Vis.Msmnts.Output
PlotMeasurements(T,M,Wind,Sim,Vis,paramFLORIDyn,paramFLORIS);
pause(0.1)
end
% % Measurements
% if Vis.Msmnts.Output
% PlotMeasurements(T,M,Wind,Sim,Vis,paramFLORIDyn,paramFLORIS);
% pause(0.1)
% end

% Flow Field
if Vis.FlowField.Plot.Post
PlotFlowField(T,M,Wind,Sim,Vis,paramFLORIDyn,paramFLORIS)
pause(0.1)
PlotFlowField(T,M,Wind,Sim,Vis,paramFLORIDyn,paramFLORIS);
pause(0.1);
end

% 3D Flow Field (.vtk for ParaView)
if Vis.FlowField3D.Generate
gen3DFlowField(T,M,Wind,Sim,Vis,paramFLORIDyn,paramFLORIS);
end

% Final state to skip initialization
if Sim.SaveFinalState
save([Sim.PathToSim 'T_final.mat'],'T')
end
% % 3D Flow Field (.vtk for ParaView)
% if Vis.FlowField3D.Generate
% gen3DFlowField(T,M,Wind,Sim,Vis,paramFLORIDyn,paramFLORIS);
% end

% Save movie if online plotting was activated
if Vis.FlowField.Plot.Online
Vis.Film.InProgress = false;
% Write saved frames as a movie to the simulation folder
v = VideoWriter(Vis.Film.MovFileEffU);
v.FrameRate = 20;
v.Quality = 100;
open(v)
writeVideo(v,Vis.Film.FrmFileEffU)
close(v)
end
% % Final state to skip initialization
% if Sim.SaveFinalState
% save([Sim.PathToSim 'T_final.mat'],'T')
% end
%
% % Save movie if online plotting was activated
% if Vis.FlowField.Plot.Online
% Vis.Film.InProgress = false;
% % Write saved frames as a movie to the simulation folder
% v = VideoWriter(Vis.Film.MovFileEffU);
% v.FrameRate = 20;
% v.Quality = 100;
% open(v)
% writeVideo(v,Vis.Film.FrmFileEffU)
% close(v)
% end
8 changes: 8 additions & 0 deletions test/create_random_numbers.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
% a vector.
clear all
rng(1234);
N=1000;

vec=randn(1,N);
filename = 'test/randn.mat';
save(filename, 'vec')
49 changes: 49 additions & 0 deletions test/test_single_turbine.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
clear all
addpath('./WindField/Velocity_Interpolation_wErrorCov/');

% Simple linear data: speed = 5 at t=0, speed = 15 at t=10
times = [0.0, 10.0];
speeds = [5.0, 15.0];
data = [times(:), speeds(:)]; % Column-wise concatenation

% Simple 2x2 identity Cholesky: noise still generated but uncorrelated
chol = chol(eye(2)); % chol returns upper triangular by default in MATLAB

% Define a WindVelMatrix function equivalent
wind = WindVelMatrix(data, chol);

% Test 5: Single turbine (scalar iT input)
iT_scalar = 1;
vel_scalar = getWindSpeedT(wind, iT_scalar, 5.0);

% assert(length(vel_scalar) == 1);
% assert(abs(vel_scalar(1) - 10.0) <= 3.0);


%% --- Supporting functions ---

function wind = WindVelMatrix(data, chol)
% Store data and chol in a struct (MATLAB equivalent of a Julia type)
wind.Data = data;
wind.CholSig = chol;
end

% function vel = getWindSpeedT(wind, iT, tQuery)
% % Simple linear interpolation to get speed at time tQuery for turbine iT
% % Assuming wind.data(:,1) = times, wind.data(:,2) = speeds
%
% times = wind.data(:,1);
% speeds = wind.data(:,2);
%
% % Interpolate speed linearly at time tQuery
% speed_t = interp1(times, speeds, tQuery, 'linear');
%
% % Add noise using chol matrix (noise generation simplified)
% noise = wind.chol * randn(2,1);
%
% % For this example just take the first element noise as perturbation
% speed_noisy = speed_t + noise(1);
%
% % Return speed as scalar (for single turbine)
% vel = speed_noisy;
% end
136 changes: 136 additions & 0 deletions test/test_windfield.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
% dir_mode = Direction_Constant()
% WindDir = 270
% iT = [1, 2, 3]
% phi = getWindDirT(dir_mode, WindDir, iT, nothing)
% for ph in phi
% @test ph ≈ 270.0
% end

clear all
addpath('./WindField/Direction_Constant');
WindDir = 270;
iT = [1, 2, 3];
phi = getWindDirT(WindDir, iT);

tol = 1e-8; % set a tolerance for floating-point comparison
for i = 1:length(phi)
ph = phi(i);
assert(abs(ph - 270.0) < tol);
end
rmpath('./WindField/Direction_Constant')

% dir_mode = Direction_Constant_wErrCov()
% struct WindDirType
% Data::Float64
% CholSig::Matrix{Float64}
% end
% WindDir = WindDirType(270.0, cholesky(Matrix{Float64}(I, 3, 3)).L)
% iT = [1, 2, 3]
% phi = getWindDirT(dir_mode, WindDir, iT)
% result = [269.6402710931765, 271.0872084924286, 269.5804103830612]
% for (i, ph) in pairs(phi)
% @test ph ≈ result[i]
% end

clear all
addpath('./WindField/Direction_Constant_wErrorCov');
rng(1234);

% Cholesky factor of 3x3 identity
L = chol(eye(3), 'lower');

% WindDir structure
WindDir.Data = 270.0;
WindDir.CholSig = L;

iT = [1, 2, 3]';

% Expected result
result = [269.0527533560426, 270.54014974707036, 269.78339785902375];

phi = getWindDirT(WindDir, iT);
for i = 1:length(phi)
assert(abs(phi(i) - result(i)) < 1e-8, 'Test failed at index %d', i);
end
rmpath('./WindField/Direction_Constant_wErrorCov');

% dir_mode = Direction_EnKF_InterpTurbine()
% # Suppose WindDir is a matrix where each row is [time, phi_T0, phi_T1, ...]
% WindDir = [
% 0.0 10.0 20.0
% 1.0 12.0 22.0
% 2.0 14.0 24.0
% ]
% phi = getWindDirT_EnKF(dir_mode, WindDir, 1, 0.5)
% @test phi ≈ 11.0

clear all
addpath('./WindField/Direction_EnKF_InterpTurbine');
WindDir = [
0.0 10.0 20.0
1.0 12.0 22.0
2.0 14.0 24.0
];
phi = getWindDirT_EnKF(WindDir, 1, 0.5);
assert(abs(phi - 11.0) < 1e-8, 'Test failed');
rmpath('./WindField/Direction_EnKF_InterpTurbine');

% dir_mode = Direction_Interpolation_wErrorCov()
%
% # Example wind direction data (time, phi)
% wind_data = [
% 0.0 10.0;
% 5.0 20.0;
% 10.0 30.0
% ]
%
% # Example Cholesky factor (for 2 turbines)
% chol_sig = cholesky([1.0 0.5; 0.5 1.0]).L
%
% # Create WindDir instance
% WindDir = WindDirMatrix(wind_data, chol_sig)
%
% # Example turbine indices (for 2 turbines)
% iT = [1, 2]
%
% # Example time
% t = 7.0
%
% # Call the function
% phi = getWindDirT(dir_mode, WindDir, iT, t)
% @test size(phi) == (2,1)
% @test phi[1] ≈ 24.92903352636283
% @test phi[2] ≈ 24.363944731838128

clear all
addpath('./WindField/Direction_Interpolation_wErrorCov');

% Wind direction data: [time, direction]
wind_data = [
0.0, 10.0;
5.0, 20.0;
10.0, 30.0
];

% Cholesky factor (lower triangular)
chol_sig = chol([1.0 0.5; 0.5 1.0], 'lower');

% Structure to hold data
WindDir.Data = wind_data;
WindDir.CholSig = chol_sig;

% Turbine indices and time
iT = [1, 2]';
t = 7.0;

phi = getWindDirT(WindDir, iT, t);

% Test
assert(isequal(size(phi), [2,1]));
assert(abs(phi(1) - 25.84752589085377) < 1e-6);
assert(abs(phi(2) - 25.140544918823198128) < 1e-6);

rmpath('./WindField/Direction_Interpolation_wErrorCov');

disp('All tests passed.');

Loading