Hello I am currently trying to find out the best way of identifying how many items have been added to an array in Fortran. To better explain the question I have simplified the system I am working with to act as an example.
Let’s say I have a box with 11 atoms bouncing around in it. At each timeframe I identify all atoms that are within a certain distance of my favourite atom, atom_α, and add them to an array named array_C, (of length 10). Now I would then like to iterate over array_C and perform calculations on the atoms in it. In python this would be no big deal as the list is long as the number of elements in it. In fortran the list/array is defined by you, and is as long as you say it is (in this case 10). As the other atoms could be far or close to atom_α the array, array_C, could contain 0, 10 or any number of atoms between. So if I was to loop over array_C I may loop over an “empty” cell or a cell that had not been overwritten from the last step causing all sorts of problems. How would I deal with this issue or is it simply a case of keeping track of the number of atoms I added to the array and then doing a do loop over it using that value?
In reality there are around 4000 atoms and each atom is a “Class” like object each containing, amongst other things, their own “array_C” listing which other atoms are close to it.
Thank you for your time.
You should declare an array to have length greater than what you expect to need. When adding elements to that array, keep track of the number of elements you have added (called numElements in the example). Then you can loop from 1 to numElements - elements of the array greater than that number are not used in that timestep. For example:
integer, parameter :: maxElements = 10000
integer :: i, numElements
real :: curData, myData(maxElements)
numElements = 0
! Adding elements to list
do ! Over all atoms
if ! Atom is close
! Include atom in list myData
! and increment numElements
numElements = numElements + 1
if (numElements > maxElements) then
! Error
endif
myData(numElements) = ...
endif
enddo
! Now loop over list
do i=1,numElements
curData = myData(i)
! Calculations with curData
enddo
Does that make sense? I agree with vlad that the question is difficult to understand so please give us more specifics if you need more answers.
Related
I'm programming this in Java but don't worry about the language you choose to respond in. This is more of a logical question.
I've got an array of size n of items say: [a, b, c...]. I've got a second empty array of size p. Note that the empty array of size p will always be larger than the previous array size n. I want to iterate over all the combinations of placements of elements from the first array into the empty array. (Note that items in the populated array will always be in that order. The order they come in cannot change; however, the space between element placing can change.
Examples of combinations are (assume n=3 and p=5):
n = 3 = [a, b, c]
could make:
[a,b,c,_,_]
[a,b,_,c,_]
[a,b,_,_,c]
[a,_,b,c,_]
[a,_,b,_,c]
[a,_,_,b,c]
[_,a,b,c,_]
etc...
I know that I would start by shifting the last element all the way to the end 1 by 1 then shifting the second element over by 1 and repeating the shift of the last element until the second last element is at the end as well and thus requiring the third and final element to be shifted over once and repeat.
The problem I'm having is representing this in code. The sizes of the arrays are variables and not known to me but I know for a fact that n < p. I don't need the number of combinations it can make. I would like to have code that gives me the iteration to make the combinations so I can do further checks.
If anyone could help me represent this in code, it would be extremely helpful.
Working in MATLAB R2017a. I'm trying to optimise a piece of code I'm working on. It uses arrays to store field values on a grid.
In order to create a specific function in a field array I originally used the straight forward method of two for loops iterating over all the array elements. But i know for loops are slow so since then I came back and tried my best to remove them. However I could only manage to remove one of the loops; leaving me with this:
for n = 1:1:K
%%% define initial pertubation
t=n*dt;
% create array for source Ez field.
xtemps = (1:Ng)*dX;
for k = 1:Ng
ztemp = k*dX;
Ez0(k,:) = THzamp * (1/(1+exp(-(t-stepuppos)))) * exp(-((xtemps-...
THzstartx).^2)./(bx^2)) .* (t-((ztemp-THzstartz)/vg))*exp(-((t-((ztemp-...
THzstartz)/vg))^2)/(bt^2));
end
The important bit here is the last 5 lines, but I figured the stuff before might be important for context. I've removed the for loop looping over the x coordinates. I want to vectorize the z/k for loop but I can't figure out how to distinguish between the dimensions with the array oporators.
Edit: THzamp, stepuppos, bx, bt, THzstartz, THzstartx are all just scalars, they control the function (Ez0) I'm trying to create. dX and t are also just scalars. Ez0 is a square array of size Ng.
What I want to achieve is to remove the for loop that loops over k, so that that the values of ztemp are defined in a vector (like xtemps already is), rather than individually in the loop. However, I don't know how I'd write the definition of Ez0 in that case.
First time posting here, if I'm doing it wrong let me know. If you need more info just ask.
It isn't clear if n is used in the other headers and as stated in the comments your sizes aren't properly defined so you'll have to ensure the sizes are correct.
However, you can give this vectorize code a try.
n = 1:K
%%% define initial pertubation
t=n*dt;
% create array for source Ez field.
xtemps = (1:Ng)*dX;
for k = 1:Ng
ztemp = k*dX;
Ez0(k,:) = THzamp .* (1./(1+exp(-(t-stepuppos)))) .* exp(-((xtemps-...
THzstartx).^2)./(bx^2)) .* (t-((ztemp-THzstartz)/vg)).*exp(-((t-((ztemp-...
THzstartz)/vg)).^2)/(bt.^2));
end
So now t has the size K you'll need to ensure stepupposand (ztemp-THzstartz)/vg) have the same size K. Also you can take a look at vectors vs array operators here.
I use the command find quite a lot in matlab, and I wonder how to translate this smartly in fortran to extract a slice of an array. In matlab you can slice with either logicals or indexes, but in fortran you need indexes to slice. I'm aware of the intrinsic subroutines pack et al, but have never used them. Also, since I'm dealing with big matrices, I would like to avoid duplicating memory. I want the sliced matrix to be manipulated within a subroutine. I've read somewhere that slices of array were not duplicated. I don't know how this the slicing in done in matlab though. I'm puzzled also because in matlab some allocations are transparent to you.
I'd like to know how to reproduce the examples below, and make sure I'm not duplicating stuff in memory and that it's actually elegant to do so. Otherwise, I would forget about slicing and just send the whole matrix(since it's by reference) and loop through an index array I...
Matlab example 1: simply reproducing find
v=[1 2 3 4];
I=find(v==3);
Matlab example 2:
m=rand(4,4);
bools=logical([ 1 0 0 1]);
I=find(bools==1);
% which I could also do like:
I=1:size(m,1);
I=I(bools);
for i=1:length(I)
% here dealing with m(I(i)),:) and do some computation
% etc.
Example 3: just call a subroutine on m(I,:) , but using directly booleans for slicing
foo( m(bools, :) , arg2, arg3 )
In advance thank you for your help!
Fortran doesn't have an exact match for Matlab's find but you can generally use either where or forall, and sometimes both, to replace its functionality.
For example, given an array v such as you have in your first example, the Fortran statement
where (v==3) do_stuff
will operate only on the elements of v which are equal to 3. This doesn't get you the indices of those elements as find does, but much of the use of find is for selecting elements for having stuff done to them, and in most of those cases the where construct is applicable.
Given v as before, and an index array ix which, in Fortran, is an array of logicals like this:
[.true., .false., .false., .true.]
you can use ix, so long as it is the same shape as v, in masked array assignments such as
where (ix) v = some_value
ix doesn't have to be an array of logicals, it can be an array of any type, if it were an array of reals you might have an expression such as
where (ix>=0.0) v = some_value
I don't think that any of the current Fortran compilers make copies of arrays to implement where constructs. I'll leave you to read about the forall construct.
Don't forget, either, that you can use arrays as indices for Fortran arrays, so the expression
v([1,3]) = 0
sets elements 1 and 3 of v to 0. You can, of course, use multiple array indices if your array has rank greater than 1.
When you start using this sort of indexing to pass non-contiguous sections of an array to a sub-program, then you have to start worrying about copying into temporary arrays (if that's the sort of thing that you want to worry about). I believe that compilers may make temporary copies if you do something like
call my_subroutine(array(1:12:3, 2:12:4))
to enable the subroutine, which does not know the indices of the elements of the array section at run-time, to operate on what it 'sees' as a contiguous array.
You can use "pack" with an implied do loop:
I = pack([(j,j=1,size(v))],v==3)
Bellow, in FORTRAN CODE, is an example of a subroutine that makes the equivalent of find in matlab or scilab. In the examples below, we want to (a) find the position of the vector where the vector is equal to 22 (b) find the positions of even numbers in a vector
PROGRAM Principal
REAL*8 A(8)
INTEGER n, npos, pos(8)
n=8
A = (/ 19, 20, 21, 22, 23, 24, 25, 26 /)
! Find the positions of vector A that is equal to 22
CALL FindInVector(n,A==22,npos,pos)
WRITE(*,*) pos(1:npos)
! Find the positions of vector A that contains even numbers
CALL FindInVector(n,ABS(A/2.d0-INT(A/2.d0))<1.d-2,npos,pos)
WRITE(*,*) pos(1:npos)
END PROGRAM Principal
!________________________________________________________________
! Subroutine that find positions of a vector of logicals TF (True or False). The first npos elements contains the response.
SUBROUTINE FindInVector(n,TF,npos,pos)
! Inlet variables
INTEGER,INTENT(IN):: n ! Dimension of logical vector
LOGICAL,INTENT(IN):: TF(n) ! Logical vector (True or False)
! Outlet variables
INTEGER npos ! number of "true" conditions
INTEGER pos(n) ! position of "true" conditions
! Internal variables
INTEGER i ! counter
INTEGER v(n) ! vector of all positions
pos = 0 ! Initialize pos
FORALL(i=1:n) v(i) = i ! Enumerate all positions
npos = COUNT(TF) ! Count the elements of TF that are .True.
pos(1:npos)= pack(v, TF) ! With Pack function, verify position of true conditions
ENDSUBROUTINE FindInVector
I think a simpler version is possible, see the subroutine below. The example shows how to find the values smaller than 0.1 in array x.
program test
real, dimension(:), allocatable :: x
integer, dimension(:), allocatable :: zeros
x=[1.,2.,3.,4.,0.,5.,6.,7.,0.,8.]
call find_in_array(x<0.01,zeros)
write(*,*)zeros
contains
subroutine find_in_array(TF,res)
! Dummy arguments
logical, dimension(:), intent(in) :: TF ! logical array
integer, dimension(:), allocatable, intent(out) :: res ! positions of true
! elements
! Local arrays
integer, dimension(:), allocatable :: pos
pos=[(i,i=1,size(TF))]
!pos=[1:size(TF)] ! valid on Intel compiler
res=pack(pos,TF)
end subroutine find_in_array
end program test
Is there any way to "vector" assign an array of struct.
Currently I can
edges(1000000) = struct('weight',1.0); //This really does not assign the value, I checked on 2009A.
for i=1:1000000; edges(i).weight=1.0; end;
But that is slow, I want to do something more like
edges(:).weight=[rand(1000000,1)]; //with or without the square brackets.
Any ideas/suggestions to vectorize this assignment, so that it will be faster.
Thanks in advance.
This is much faster than deal or a loop (at least on my system):
N=10000;
edge(N) = struct('weight',1.0); % initialize the array
values = rand(1,N); % set the values as a vector
W = mat2cell(values, 1,ones(1,N)); % convert values to a cell
[edge(:).weight] = W{:};
Using curly braces on the right gives a comma separated value list of all the values in W (i.e. N outputs) and using square braces on the right assigns those N outputs to the N values in edge(:).weight.
You can try using the Matlab function deal, but I found it requires to tweak the input a little (using this question: In Matlab, for a multiple input function, how to use a single input as multiple inputs?), maybe there is something simpler.
n=100000;
edges(n)=struct('weight',1.0);
m=mat2cell(rand(n,1),ones(n,1),1);
[edges(:).weight]=deal(m{:});
Also I found that this is not nearly as fast as the for loop on my computer (~0.35s for deal versus ~0.05s for the loop) presumably because of the call to mat2cell. The difference in speed is reduced if you use this more than once but it stays in favor of the for loop.
You could simply write:
edges = struct('weight', num2cell(rand(1000000,1)));
Is there something requiring you to particularly use a struct in this way?
Consider replacing your array of structs with simply a separate array for each member of the struct.
weights = rand(1, 1000);
If you have a struct member which is an array, you can make an extra dimension:
matrices = rand(3, 3, 1000);
If you just want to keep things neat, you could put these arrays into a struct:
edges.weights = weights;
edges.matrices = matrices;
But if you need to keep an array of structs, I think you can do
[edges.weight] = rand(1, 1000);
The reason that the structs in your example don't get initialized properly is that the syntax you're using only addresses the very last element in the struct array. For a nonexistent array, the rest of them get implicitly filled in with structs that have the default value [] in all their fields.
To make this behavior clear, try doing a short array with clear edges; edges(1:3) = struct('weight',1.0) and looking at each of edges(1), edges(2), and edges(3). The edges(3) element has 1.0 in its weight like you want; the others have [].
The syntax for efficiently initializing an array of structs is one of these.
% Using repmat and full assignment
edges = repmat(struct('weight', 1.0), [1 1000]);
% Using indexing
% NOTE: Only correct if variable is uninitialized!!!
edges(1:1000) = struct('weight', 1.0); % QUESTIONABLE
Note the 1:1000 instead of just 1000 when indexing in to the uninitialized edges array.
There's a problem with the edges(1:1000) form: if edges is already initialized, this syntax will just update the values of selected elements. If edges has more than 1000 elements, the others will be left unchanged, and your code will be buggy. Or if edges is a different type, you could get an error or weird behavior depending on its existing datatype. To be safe, you need to do clear edges before initializing using the indexing syntax. So it's better to just do full assignment with the repmat form.
BUT: Regardless of how you initialize it, an array-of-structs like this is always going to be inherently slow to work with for larger data sets. You can't do real "vectorized" operations on it because your primitive arrays are all broken up in to separate mxArrays inside each struct element. That includes the field assignment in your question – it is not possible to vectorize that. Instead, you should switch a struct-of-arrays like Brian L's answer suggests.
You can use a reverse struct and then do all operations without any errors
like this
x.E(1)=1;
x.E(2)=3;
x.E(2)=8;
x.E(3)=5;
and then the operation like the following
x.E
ans =
3 8 5
or like this
x.E(1:2)=2
x =
E: [2 2 5]
or maybe this
x.E(1:3)=[2,3,4]*5
x =
E: [10 15 20]
It is really faster than for_loop and you do not need other big functions to slow your program.
Here's the stumper:
Start with three arrays A, B and C with a total of 2n+1 entries.
Write an algorithm to sort all of the entries from all of the arrays
using only the following two methods:
X = sort(X) replaces the array X with the sorted version.
(X , Y) = doubleUp(X , Y) does nothing if X has more elements
than Y, otherwise it removes the first length(X) entries from Y
and appends them to the end of X.
Here's what I've tried so far. If two of the arrays are empty, then just use sort on the nonempty array.
If one of the arrays is empty, then I think I can use doubleUp to get one array to have just one thing and the other array to have everything else, and if that singleton array has the smallest (or largest) element, then that works. So I can use sort after I use doubleUp each time to make sure this happens. I coded this up in Maple and it worked for all the cases I checked.
I have no idea how to do it with 3 arrays though. Anyone have any ideas?
Sounds like nonsense. The total number of entries is odd. The only way to increase the length of an array is to make it the smaller first argument of doubleUp, in which case it ends up with an even number of elements. So unless all the elements are in one array to begin with there's no way to make one array contain all the elements, sorted or otherwise.
So, the desired final result is not a single array containing all the elements in order. Or if it is, then the answer to the question is "it cannot be done".