From 90b1689a2f35c9e5cca62ca2bd755bf79e28391e Mon Sep 17 00:00:00 2001
From: Mauco03 <marco.gaibotti@skywarder.eu>
Date: Sun, 20 Apr 2025 21:17:15 +0200
Subject: [PATCH] [coeff-transport][Wind] Added internal griddedInterpolant to
 wind

---
 classes/misc/Wind.m | 116 ++++++++++++++++++++++++++------------------
 1 file changed, 69 insertions(+), 47 deletions(-)

diff --git a/classes/misc/Wind.m b/classes/misc/Wind.m
index f3eb9a9..f3d6707 100644
--- a/classes/misc/Wind.m
+++ b/classes/misc/Wind.m
@@ -9,6 +9,7 @@ classdef Wind < Config
 %               - mission: Mission, mission object
 %               - varIn: (optional) config source. Alternative to config.m
 %               file
+
     properties(Dependent)
         altitudes               (1, :)
 
@@ -25,6 +26,9 @@ classdef Wind < Config
     end
     
     properties(Access = private)
+        isReady                 (1, 1)  logical                   % true if all properties are set
+        dataInerpolant          (1, 1)  griddedInterpolant      % [-] Interpolates [magnitude, azimuth, elevation]
+
         ALTITUDES
         
         MAGNITUDE_DISTRIBUTION  = ''
@@ -41,77 +45,71 @@ classdef Wind < Config
         elevation
         magnitude
     end
-    
-    properties(Access = private)
-        checks                  (1, 3)  logical                 % true if #[magnitude, azimuth, elevation] == #altitudes
-    end
 
     properties(Constant, Access = protected)
         configName = 'windConfig.m'
         variableName = 'windCustom'
     end
 
-    methods % Getters / Setters
-        function obj = set.altitudes(obj, value)
-            if length(value) ~= length(obj.ALTITUDES)
-                obj.ALTITUDES = value;
-                obj.magnitude = obj.updateDistribution(obj.MAGNITUDE_DISTRIBUTION, obj.MAGNITUDE_PARAMETERS);
-                obj.azimuth   = obj.updateDistribution(obj.AZIMUTH_DISTRIBUTION, obj.AZIMUTH_PARAMETERS);
-                obj.elevation = obj.updateDistribution(obj.ELEVATION_DISTRIBUTION, obj.ELEVATION_PARAMETERS);
-            else
-                obj.ALTITUDES = value;
-            end
+    methods % Getters
+        function value = get.altitudes(obj), value = obj.ALTITUDES; end
+
+        function value = get.magnitudeDistribution(obj), value = obj.MAGNITUDE_DISTRIBUTION; end
+        function value = get.azimuthDistribution(obj), value = obj.AZIMUTH_DISTRIBUTION; end
+        function value = get.elevationDistribution(obj), value = obj.ELEVATION_DISTRIBUTION; end
+            
+        function value = get.magnitudeParameters(obj), value = obj.MAGNITUDE_PARAMETERS; end
+        function value = get.azimuthParameters(obj), value = obj.AZIMUTH_PARAMETERS; end
+        function value = get.elevationParameters(obj), value = obj.ELEVATION_PARAMETERS; end
+    end
 
-            obj.checks(1) = length(obj.magnitude) == length(obj.ALTITUDES);
-            obj.checks(2) = length(obj.azimuth) == length(obj.ALTITUDES);
-            obj.checks(3) = length(obj.elevation) == length(obj.ALTITUDES);
+    methods % Setters
+        function obj = set.altitudes(obj, value)
+            obj.ALTITUDES = value;
+            obj = obj.updateAll();
         end
 
         function obj = set.magnitudeDistribution(obj, value)
             obj.MAGNITUDE_DISTRIBUTION = value;
+            obj.isReady = obj.checkProperties();
             obj.magnitude = obj.updateDistribution(value, obj.MAGNITUDE_PARAMETERS);
-            obj.checks(1) = length(obj.magnitude) == length(obj.ALTITUDES); 
+            obj = obj.updateInterpolant();
         end
 
         function obj = set.magnitudeParameters(obj, value)
             obj.MAGNITUDE_PARAMETERS = value;
+            obj.isReady = obj.checkProperties();
             obj.magnitude = obj.updateDistribution(obj.MAGNITUDE_DISTRIBUTION, value);
-            obj.checks(1) = length(obj.magnitude) == length(obj.ALTITUDES);
+            obj = obj.updateInterpolant();
         end
 
         function obj = set.azimuthDistribution(obj, value)
             obj.AZIMUTH_DISTRIBUTION = value;
+            obj.isReady = obj.checkProperties();
             obj.azimuth = obj.updateDistribution(value, obj.AZIMUTH_PARAMETERS);
-            obj.checks(2) = length(obj.azimuth) == length(obj.ALTITUDES); 
+            obj = obj.updateInterpolant();
         end
 
         function obj = set.azimuthParameters(obj, value)
             obj.AZIMUTH_PARAMETERS = value;
+            obj.isReady = obj.checkProperties();
             obj.azimuth = obj.updateDistribution(obj.AZIMUTH_DISTRIBUTION, value);
-            obj.checks(2) = length(obj.azimuth) == length(obj.ALTITUDES); 
+            obj = obj.updateInterpolant();
         end
 
         function obj = set.elevationDistribution(obj, value)
             obj.ELEVATION_DISTRIBUTION = value;
+            obj.isReady = obj.checkProperties();
             obj.elevation = obj.updateDistribution(value, obj.ELEVATION_PARAMETERS);
-            obj.checks(3) = length(obj.elevation) == length(obj.ALTITUDES); 
+            obj = obj.updateInterpolant();
         end
 
         function obj = set.elevationParameters(obj, value)
             obj.ELEVATION_PARAMETERS = value;
+            obj.isReady = obj.checkProperties();
             obj.elevation = obj.updateDistribution(obj.ELEVATION_DISTRIBUTION, value);
-            obj.checks(3) = length(obj.elevation) == length(obj.ALTITUDES); 
+            obj = obj.updateInterpolant();
         end
-
-        function value = get.altitudes(obj), value = obj.ALTITUDES; end
-
-        function value = get.magnitudeDistribution(obj), value = obj.MAGNITUDE_DISTRIBUTION; end
-        function value = get.azimuthDistribution(obj), value = obj.AZIMUTH_DISTRIBUTION; end
-        function value = get.elevationDistribution(obj), value = obj.ELEVATION_DISTRIBUTION; end
-            
-        function value = get.magnitudeParameters(obj), value = obj.MAGNITUDE_PARAMETERS; end
-        function value = get.azimuthParameters(obj), value = obj.AZIMUTH_PARAMETERS; end
-        function value = get.elevationParameters(obj), value = obj.ELEVATION_PARAMETERS; end
     end
 
     methods
@@ -123,18 +121,8 @@ classdef Wind < Config
             obj@Config(mission, varIn);
         end
 
-        function obj = updateAll(obj)
-            obj.magnitude = obj.updateDistribution(obj.MAGNITUDE_DISTRIBUTION, obj.MAGNITUDE_PARAMETERS);
-            obj.azimuth   = obj.updateDistribution(obj.AZIMUTH_DISTRIBUTION, obj.AZIMUTH_PARAMETERS);
-            obj.elevation = obj.updateDistribution(obj.ELEVATION_DISTRIBUTION, obj.ELEVATION_PARAMETERS);
-
-            obj.checks(1) = length(obj.magnitude) == length(obj.ALTITUDES);
-            obj.checks(2) = length(obj.azimuth) == length(obj.ALTITUDES);
-            obj.checks(3) = length(obj.elevation) == length(obj.ALTITUDES);
-        end
-
         function [uw, vw, ww] = getVels(obj, z)
-            if ~all(obj.checks)
+            if ~obj.isReady
                 error(['Parameters and distributions must be the same ' ...
                     'size as altitudes or scalar']);
             end
@@ -144,18 +132,52 @@ classdef Wind < Config
                 vw = round( - obj.magnitude * sin(obj.azimuth) * cos(obj.elevation), 6);
                 ww = round( - obj.magnitude * (-sin(obj.elevation)), 6);
             else
-                mag = interpLinear(obj.altitudes, obj.magnitude, z, true);
-                az = interpLinear(obj.altitudes, obj.azimuth, z, true);
-                el = interpLinear(obj.altitudes, obj.elevation, z, true);
+                data = obj.dataInerpolant(z);
+                mag = data(1); az = data(2); el = data(3);
 
                 uw = round( - mag * cos(az) * cos(el), 6);
                 vw = round( - mag * sin(az) * cos(el), 6);
                 ww = round( - mag * (-sin(el)), 6);
             end
         end
+
+        function obj = updateAll(obj)
+            obj.magnitude = obj.updateDistribution(obj.MAGNITUDE_DISTRIBUTION, obj.MAGNITUDE_PARAMETERS);
+            obj.azimuth   = obj.updateDistribution(obj.AZIMUTH_DISTRIBUTION, obj.AZIMUTH_PARAMETERS);
+            obj.elevation = obj.updateDistribution(obj.ELEVATION_DISTRIBUTION, obj.ELEVATION_PARAMETERS);
+
+            obj.isReady = obj.checkProperties();
+            obj = obj.updateInterpolant();
+        end
+
+        function obj = updateInterpolant(obj)
+            % UPDATEINTERPOLANT: Interpolates [magnitude; azimuth; elevation] based on altitude
+            %
+            %   Returns:
+            %       - interpolant: griddedInterpolant for [magnitude; azimuth; elevation]
+
+            if ~obj.isReady, return; end
+            if isscalar(obj.ALTITUDES), return; end
+
+            % Prepare data for interpolation
+            data = [obj.magnitude; obj.azimuth; obj.elevation];
+            gridVec = obj.ALTITUDES;
+
+            % Create gridded interpolant
+            obj.dataInerpolant = griddedInterpolant(gridVec, data', 'linear', 'nearest');
+        end
     end
 
     methods(Access = private)
+        function ready = checkProperties(obj)
+            % Check if STATIC, DYNAMIC, GEOMETRY, and STATE are non-empty
+
+            ready = ...
+                length(obj.magnitude) == length(obj.ALTITUDES) && ...
+                length(obj.azimuth) == length(obj.ALTITUDES) && ...     
+                length(obj.elevation) == length(obj.ALTITUDES);
+        end
+
         function vec = updateDistribution(obj, dist, parameters)
             s = length(obj.ALTITUDES);
             vec = [];
-- 
GitLab