Cell array use, indexing and slicing in parallelization

조회 수: 11 (최근 30일)
Matthew Muscat
Matthew Muscat 2022년 4월 2일
댓글: Matthew Muscat 2022년 4월 3일
I have a problem with the parfor loop below. Essentially I get the following error: "Error: Unable to classify the variable 'inter_cnt' in the body of the parfor-loop."
I have tried to include enough information so that other variables make sense, while not distracting from the point.
I think it might be a problem with "slicing", because I know that you need to slice your variables properly when using a parfor.
If I comment out the "inter_cnt(...)" line (see code for relevant comment at the end of the while loop), then the code runs.
Please let me know if anymore information is necessary
% initializing first page of cell array
inter_cnt={'energy',enr(1);'coherent', 0;'compton', 0;'photoelectric', 0;'pair-triplet', 0;};
% re setting interaction counter for all other energies (pages)
for i= 2:length(enr)
inter_cnt_intermediate = {'energy',enr(i);'coherent', 0;'compton', 0;'photoelectric', 0;'pair-triplet', 0;};
inter_cnt=cat(3,inter_cnt,inter_cnt_intermediate);
end
N_particles = 0;
parfor j = 1:length(enr)
particle_num = 0;
while particle_num <= N_particles % a while loop that loops for each step the particle takes
% select the interaction
intr_gen = rand; % generate a random number
inter_type = interaction_selector(enr(j),intr_gen,M,mu_t); % call the interaction selector function
index_for_cell_interaction = find(strcmp([inter_cnt(:,1,1)], inter_type)); % finds the right index in the cell array containing the counts of each interaction
index_for_cell_energy = find([inter_cnt{1,2,:}] == enr(j)); % finds the right index in the cell array containing the counts of each interaction
inter_cnt{index_for_cell_interaction,2,index_for_cell_energy} = inter_cnt{index_for_cell_interaction,2,index_for_cell_energy} + 1; % increases the count for the interaction type that was chosen by interaction selector
% commenting out the above ^ line, the code runs without error
particle_num = particle_num+1;
end
end

채택된 답변

Walter Roberson
Walter Roberson 2022년 4월 2일
Inside the parfor loop, you can write to local variables all you want, but sometimes parfor will require you to clearly initialize the local variable inside the parfor loop in order for it to be certain that you mean the variable to be local.
Inside the parfor loop, you can write to non-local variables using indices that involve the parfor loop index variable only once, in form that must be equivalent to constant*variable+constant, and all other indices for the variables must be constant or : . And you cannot write to two different locations inside the same non-local variable inside the loop.
inter_cnt{j, 1} = 3; %okay in itself
inter_cnt{j, 2} = 4; %fail, can only write to one part of the variable in the same loop
Your index_for_cell_energy is calculated independent of your loop variable j, and also could refer to several different rows (parfor has no way of knowing that your strings are unique). Your index_for_cell_energy is calculated independent of your loop variable j, and also could refer to several different columns (no inherent reason why find([inter_cnt{1,2,:}] == enr(j)) would be scalar.) You are literally writing to one or more random locations in the array.
There is no this can be made to work with parfor in the form given.
What can be done, is instead of doing the increment of inter_cnt inside the parfor loop, just keep track of the index_for_cell_interaction and index_for_cell_energy (and make sure they are scalar.) Like
index_for_cell_interaction(j) = find(strcmp([inter_cnt(:,1,1)], inter_type)); % finds the right index in the cell array containing the counts of each interaction
index_for_cell_energy(j) = find([inter_cnt{1,2,:}] == enr(j)); % finds the right index in the cell array containing the counts of each interaction
then after the loop, use sparse() or accumarray() to total the counts.
  댓글 수: 4
Walter Roberson
Walter Roberson 2022년 4월 3일
Create a per-slice output, and assign to it at the end of the loop. For example, initialize inter_cnt just inside the start of the parfor and then at the end
all_inter_cnt(j) = inter_cnt;
then outside the parfor, do whatever is appropriate to bring the results all together, such as
cat(4, all_inter_cnt{:})
Matthew Muscat
Matthew Muscat 2022년 4월 3일
I managed to figure most of what you just said on my own! Indeed that's exactly what I did, except for the final step, I was just in the middle of trying to figure out how to produce a nice 3D cell array, instead of a cell array with cell arrays nested within. Thanks for your help, I have a better understanding of parfor now. Here is a sample of the code that runs now for people in the future with a similar question:
parfor j = 1:length(enr) % parallellized the
%particle_num=0;
inter_cnt_temp={'energy',enr(j);'coherent', 0;'compton', 0;'photoelectric', 0;'pair-triplet', 0;};
for particle_num = 1:N_particles % a while loop that loops for each step the particle takes
% select the interaction
intr_gen = rand; % generate a random number
inter_type = interaction_selector(enr(j),intr_gen,M,mu_t); % call the interaction selector function
index_interaction = find(strcmp([inter_cnt_temp(:,1)], inter_type)); % finds the right index in the cell array containing the counts of each interaction
inter_cnt_temp{index_interaction,2} = inter_cnt_temp{index_interaction,2} + 1; % increase the count of the appropriate interaction in the local interaction cell counter
end
inter_cnt_global{j}=inter_cnt_temp; % store the local total interaction counts (cell array) in a global cell array
end
inter_cnt_total = cat(3, inter_cnt_global{:}); % concatenate the counter cell array to make the data nice

댓글을 달려면 로그인하십시오.

추가 답변 (0개)

카테고리

Help CenterFile Exchange에서 Matrix Indexing에 대해 자세히 알아보기

Community Treasure Hunt

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

Start Hunting!

Translated by