Why do properties differ when I call them from the main file compared to when I call them in a method?

1 view (last 30 days)
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.

Answers (1)

Sandeep
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.

Categories

Find more on Construct and Work with Object Arrays in Help Center and File Exchange

Products


Release

R2022b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!