Why do properties differ when I call them from the main file compared to when I call them in a method?
    9 views (last 30 days)
  
       Show older comments
    
I'm working on an OOP assignment for an university and we have to simulate herds of cows, each herd as an object with methods like increasing in size and dying of cows. Now when I call the current cell grid on which the cows are, these values differ from each other when I call it in the main file versus when I call these locations of herds in the method of death.
%Blijkbaar kunnen er geen classes gemaakt worden in een live file
clc
clearvars
close
tic %voor de volgende 100 jaar neemt het 533 seconden (zonder objects)
%clearing console and variables
%setting some general parameters
numberOfLocations = 8; %8 error death
gridDimensions = 20; %20 error death
weeksSeason = 13;
countNYears = 0;
timeSim = 10; %10 error death %temporal resolution is a week and this for a 100 
% years with each year consisting of 52 weeks, type the amount of years
%Creating the grasslands environment
grasslands = zeros(gridDimensions, gridDimensions);
grasslands = grasslands + 10000;
matGrMod = [1, 1.5, 1, 0.5]; %marix with grass modifiers for one year
matGrMod = repmat(matGrMod, [1, timeSim]); %matrix with grass modifiers for a 100 years
%Using the provided file to randomly select starting locations
locations = startingLocations(numberOfLocations, gridDimensions);
%Using a txt file with 100 surnames to differentiate families and herds
FID = fopen('surname.txt');
data = textscan(FID, '%s');
fclose(FID);
names = string(data{:});
%Creating all the needed objects
herdArray = Herd.empty(3,0);
for i = 1:numberOfLocations
    herdArray(i) = Herd(names(i), i, 200, [locations(i,1), locations(i,2)]);
end
cowsArray = [];
%Starting the agent-based model simulation
for i = matGrMod % a for loop going through 13 weeks for each grass modifier
    for j = 1:weeksSeason
    countNYears = countNYears+ 1;
    grasslands = grasslands + (100*i);
    grasslands(grasslands>40000) = 40000;
    herdArray = herdArray.move(grasslands, gridDimensions);
    grasslands = herdArray.eat(grasslands);
    herdArray = herdArray.birth();
    subs = vertcat(herdArray.currentGridCell);
    indicesGrasslands = sub2ind(size(grasslands), subs(:,1), subs(:,2));
    if sum(grasslands(indicesGrasslands) < 0) >= 1
        [herdArray, dr, subsDeath] = herdArray.death(grasslands); %This object is delayed
        disp(dr)
    end
    cowsArray(end+1) =  sum(vertcat(herdArray.nCows));
    image(grasslands, 'CDataMapping','scaled')
    colorbar
    hold on
    scatter(subs(:,2), subs(:,1), 'MarkerFaceColor', 'r')
    axis square
    axis off
    hold off
    M(1)=getframe;
    pause(0.2)
    end
end
toc
The starting locations file is as follows:
function [locations] = startingLocations(numberOfLocations, gridDimensions)
if numberOfLocations > gridDimensions*gridDimensions
    throw(MException('startingLocations:tooManySamples', 'Trying to sample %d different positions from %d locations', numberOfLocations, gridDimensions*gridDimensions))
end
rng(804694) % replace 'shuffle' with your r-number here
[X,Y] = meshgrid(1:gridDimensions, 1:gridDimensions);
allLocations = horzcat(reshape(X,[],1), reshape(Y,[],1));
locationIdxs = randsample(size(allLocations, 1), numberOfLocations);
locations = allLocations(locationIdxs,:);
end
And the following file is the herd object file.
classdef Herd < matlab.mixin.SetGet
    properties
        owner;
        id;
        nCows{mustBePositive, mustBeInteger}; 
        currentGridCell(1,2);
    end
    properties(Dependent)
        arrayLocationsCows;
    end
    methods
        function newHerd = Herd(owner, id, nCows, currentGridCell)
                if nargin == 4 % if all four arguments (owner, id, nCows, currentGridCell) are given to the Constructor
                    newHerd.owner = owner;
                    newHerd.id = id;
                    newHerd.nCows = nCows;
                    newHerd.currentGridCell = currentGridCell;
                end
        end
        function self = birth(self)
            n = vertcat(self.nCows);
            birthRate = n./208;
            indices = find(birthRate >= 1);
            nPlusOne = n + ((birthRate-floor(birthRate))>rand(size(birthRate)));
            nPlusOne(indices) = nPlusOne(indices)+1;
            nPlusOne = num2cell(nPlusOne);
            [self.nCows] = nPlusOne{:};
        end
        %This self.currentGridCell is behind 1 step
        function [self, dr, subs] = death(self, grasslands)
            subs = vertcat(self.currentGridCell);
            indices = sub2ind(size(grasslands), subs(:,1), subs(:,2));
            grasslandsIndexed =grasslands(indices);
            indicesDeath = find(grasslandsIndexed < 0);
            member = ismember(indices, indicesDeath);
            indicesMember = member == 1;
            vectorCows = horzcat(self.nCows);
            vectorCowsDeath = vectorCows(indicesMember);
            fsf = 1 + ((grasslands(indicesDeath)./(10.*vectorCowsDeath)));
            dr = (vectorCowsDeath.*0.05.*fsf)./52;
            dr = (floor(dr));
            vectorCows(indicesMember) = vectorCows(indicesMember) - dr;
            vectorCows = num2cell(vectorCows);
            [self.nCows] = vectorCows{:};
        end
        function grasslands = eat(self, grasslands) %Give the self argument first as: When you use an ...
            % object method using dot syntax on an object, then the object is always passed as the first parameter to the method
            %Here self is an array so horzcat needs to be used.
            slice = vertcat(self.currentGridCell); %combining all the herds locations
            indices = sub2ind(size(grasslands), slice(:, 1), slice(:,2)); %changing subscript indexing to linear indexing
            grasslands(indices)  = grasslands(indices) - (vertcat(self.nCows).*30);
        end
        function  self = move(self, grasslands, gridDimensions) 
            slice = vertcat(self.currentGridCell); %combining all the herds locations
            %All the directions the herd can move
            indicesPlusOne = (slice(:, 1)+1);
            indicesPlusOne(indicesPlusOne > gridDimensions) = gridDimensions;
            indicesMinusOne = (slice(:, 1)-1);
            indicesMinusOne(indicesMinusOne == 0) = 1;
            jndicesPlusOne = (slice(:,2)+1);
            jndicesPlusOne(jndicesPlusOne > gridDimensions) = gridDimensions;
            jndicesMinusOne = (slice(:,2)-1);
            jndicesMinusOne(jndicesMinusOne == 0) = 1;
            indicesPlusOne = sub2ind(size(grasslands), indicesPlusOne, slice(:,2)); %changing subscript indexing to linear indexing
            indicesMinusOne = sub2ind(size(grasslands), indicesMinusOne, slice(:,2));
            jndicesPlusOne = sub2ind(size(grasslands), slice(:, 1), jndicesPlusOne);
            jndicesMinusOne = sub2ind(size(grasslands), slice(:, 1), jndicesMinusOne);
            trackArray = horzcat(indicesPlusOne, indicesMinusOne, jndicesPlusOne, jndicesMinusOne); %array with all possible movements
            grAmountArray = horzcat(grasslands(indicesPlusOne), grasslands(indicesMinusOne), grasslands(jndicesPlusOne), grasslands(jndicesMinusOne)); %array with all the grass amounts according
            %to possible movements, n x 4
            %selecting random cells if amount of grass is equal in 2, 3 or
            %4 neighbouring cells
            numRows = size(grAmountArray, 1);
            rowMax = max(grAmountArray, [], 2);
            isRowMax = grAmountArray == rowMax;
            S = isRowMax.*rand(size(grAmountArray));
            [~, selectedColumn] = max(S, [], 2);
            indices = [(1:numRows)' selectedColumn];
            indices = sub2ind(size(grAmountArray), indices(:, 1), indices(:, 2));
            indicesGrasslands = trackArray(indices);
            [row, col] = ind2sub(size(grasslands), indicesGrasslands);
            indicesHerdsUpdate = horzcat(row, col);
            indicesHerdsUpdate = num2cell(indicesHerdsUpdate, 2);
            [self.currentGridCell] = indicesHerdsUpdate{:};
            A = vertcat(self.currentGridCell);
            [~,W] = unique(A,'rows','stable'); %checking if no two herds are on the same gridcell
            D = setdiff(1:size(A,1),W); %indices of duplicate rows.
            %if there are herds in the same gridcell, the herd which is
            %further down the list will be seen as duplicate and moved to a
            %random neighbouring cell but not according to the amount of
            %grass
                 if isempty(D) ~= 1
                     C = randi(4);
                     if C ==1
                        A(D) =  A(D) + 1;
                        A(A > gridDimensions) = gridDimensions;
                     elseif C == 2
                         A(D) =  A(D) - 1;
                         A(A == 0) = 1;
                     elseif C == 3
                         r = A(:, 2);
                         r(D) = r(D) +1;
                         A(:, 2) = r;
                         A(A > gridDimensions) = gridDimensions;
                     else
                         r = A(:, 2);
                         r(D) = r(D) - 1;
                         A(:, 2) = r;
                         A(A == 0) = 1;
                     end
                 end
             indicesHerdsUpdate = num2cell(A, 2);
             [self.currentGridCell] = indicesHerdsUpdate{:};
        end
        function self = splitHerd(self)
            if sum(vercat(self.nCows) >= 1000) > 1
                self.nCows = ceil((self.nCows)/2);
                newNewHerd = Herd(self.owner + '_split', floor((self.nCows)/2), self.currentGridCell);
            end
        end
    end
end
When you compare the "subs" and "subsDeath" variable these differ so the "dr" variable is empty. The death method such have herds lose cows when the gridcell on which they are has negative grass. But due to this difference in subscripts the array of how many cows they should lose in each herd is empty and the method throws up an error. I do not understand why this is the case because in the main file I use "subs = vertcat(herdArray.currentGridCell);" to get the current locations of all herds but this differs from the "subs = vertcat(herdArray.currentGridCell);" I use in the method of death although nothing should have changed the locations in the mean time.
0 Comments
Answers (1)
  Sandeep
    
 on 27 Jul 2023
        Hi Aron,
It appears that you are encountering an error related to the death method in the Herd class. Specifically, the subs and subsDeath variables have different values, resulting in an empty dr variable and causing the error. One possible reason for this discrepancy is that the currentGridCell property of the Herd objects is not updated correctly. It's crucial to ensure that the currentGridCell property is updated whenever a herd moves or changes its location.
To resolve this issue, you should check the following:
1. Verify that the currentGridCell property is correctly updated whenever a herd moves. Make sure the property is updated in the move method of the Herd class and that the updated value is stored correctly.
2. Ensure that the currentGridCell property is not modified or updated elsewhere in your code before calling the death method. Check for unintended modifications or assignments to the currentGridCell property that might affect the comparison.
By carefully reviewing the code and ensuring that the currentGridCell property is updated correctly, you should be able to resolve the discrepancy between subs and subsDeath and prevent the error in the death method.
0 Comments
See Also
Categories
				Find more on Construct and Work with Object Arrays in Help Center and File Exchange
			
	Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!