0001 classdef Variogram
0002
0003
0004 properties
0005 a;
0006 c0;
0007 c1;
0008 model;
0009 variogramFun;
0010 hExp;
0011 gammaExp;
0012 optimNugget;
0013 distType;
0014 end
0015
0016 methods
0017 function obj = Variogram(x, y, z, varargin)
0018
0019
0020
0021
0022
0023 validDistanceType = @(x) ischar(x) && strcmpi(x, 'euclidean') || strcmpi(x, 'haversine');
0024 validNumBins = @(x) isscalar(x) && x > 0;
0025 validModelType = @(x) ischar(x) && ...
0026 strcmpi(x, 'spherical') || ...
0027 strcmpi(x, 'exponential') || ...
0028 strcmpi(x, 'gaussian');
0029
0030 p = inputParser;
0031 addParameter(p, 'DistanceType', 'euclidean', validDistanceType);
0032 addParameter(p, 'Model', 'spherical', validModelType);
0033 addParameter(p, 'InitialA', -1, @isscalar);
0034 addParameter(p, 'InitialC1', -1, @isscalar);
0035 addParameter(p, 'InitialC0', -1, @isscalar);
0036 addParameter(p, 'OptimNugget', false, @islogical);
0037 addParameter(p, 'NumBins', 10, validNumBins);
0038 parse(p, varargin{:});
0039
0040 obj.optimNugget = p.Results.OptimNugget;
0041 obj.distType = p.Results.DistanceType;
0042
0043
0044 [obj.hExp, obj.gammaExp] = Variogram.experimentalVariogram(x, y, z, p.Results.NumBins, obj.distType);
0045
0046
0047 obj = obj.fitModel(p.Results.Model, [p.Results.InitialA, p.Results.InitialC1, p.Results.InitialC0]);
0048 end
0049
0050 function val = eval(obj, h)
0051
0052
0053
0054
0055 val = obj.variogramFun(h, [obj.a, obj.c1, obj.c0]);
0056 end
0057
0058 function obj = fitModel(obj, modelType, initialGuess)
0059
0060
0061 obj.model = modelType;
0062 switch lower(obj.model)
0063 case 'spherical'
0064 obj.variogramFun = @(h, b)sphericalVariogramModel(h, b(1), b(2), b(3));
0065 case 'exponential'
0066 obj.variogramFun = @(h, b)exponentialVariogramModel(h, b(1), b(2), b(3));
0067 case 'gaussian'
0068 obj.variogramFun = @(h, b)gaussianVariogramModel(h, b(1), b(2), b(3));
0069 otherwise
0070 error('Unknown variogram model');
0071 end
0072
0073
0074 if initialGuess(1) < 0
0075 initialGuess(1) = max(obj.hExp)*2/3;
0076 end
0077 if initialGuess(2) < 0
0078 initialGuess(2) = max(obj.gammaExp);
0079 end
0080 if initialGuess(3) < 0
0081 initialGuess(3) = 0;
0082 end
0083
0084
0085 lb = [0 0 0];
0086
0087 ub = [inf max(obj.gammaExp) max(obj.gammaExp)];
0088 if ~obj.optimNugget
0089
0090
0091
0092 ub(3) = 0;
0093 end
0094
0095
0096 options = optimset('MaxFunEvals', 10000000);
0097 objectiveFun = @(b) sum((obj.variogramFun(obj.hExp, b)-obj.gammaExp).^2);
0098
0099
0100 [b, fval, exitflag, output] = fminsearchbnd(objectiveFun, initialGuess, lb, ub, options);
0101
0102 obj.a = b(1);
0103 obj.c1 = b(2);
0104 obj.c0 = b(3);
0105 end
0106
0107 function plot(obj)
0108 figure;
0109 plot(obj.hExp, obj.gammaExp, 'rs','MarkerSize', 10);
0110 hold on;
0111 fplot(@(x)obj.variogramFun(x, [obj.a, obj.c1, obj.c0]), [0 max(obj.hExp)]);
0112 hold off;
0113 end
0114 end
0115
0116 methods (Static)
0117 function [h, g] = experimentalVariogram(x, y, z, numBins, distType)
0118
0119
0120
0121 if strcmpi(distType, 'euclidean')
0122 dists = pdist([x y]);
0123 elseif strcmpi(distType, 'haversine')
0124 dists = pdist([x y], @haversine);
0125 else
0126 error('Unknown distance type');
0127 end
0128
0129
0130
0131 gammas = pdist(z, @Variogram.gamma);
0132
0133
0134 edges = linspace(0,max(dists).*.3,numBins+1);
0135 [N, edges, bin] = histcounts(dists, edges);
0136 h = edges(2:end)';
0137
0138
0139 g = zeros(numBins, 1);
0140 for i = 1:numBins
0141
0142 gs = gammas(bin == i);
0143
0144
0145 g(i) = mean(gs);
0146 end
0147 end
0148
0149 function g = gamma(v1, v2)
0150 g = 0.5*(v1-v2).^2;
0151 end
0152 end
0153 end
0154