Reordering array dimensions in matlab - arrays

First, some background:
As part of a much larger code I'm reading in data from a netCDF input file. I produce this input file beforehand. The code has been written to expect a term F which is an array shaped like t-by-x-by-y-by-z where time t usually has around 20 values, and x and y dimensions are usually of the order 1000 entries each and z has usually about 5.
In summary, F is a 20x1000x1000x5 array.
This format is incredibly slow to read. It is many times faster to read it if it's written in the format x-by-y-by-z-by-t.
So what instead I am now producing an input netCDF file containing Fnew, which is a 1000x1000x5x20 array.
Now my question: I want to make as few changes to the larger code as possible, so after Fnew is read in, I immediately want to rearrange it to match F.
There must be an easy solution to this?

As Cris Luengo commented, the permute function is what you need. This is how you would use it in your context:
function test()
%% instead of the current (using 10 instead of 1000 just for demo purposes):
txyz = rand(20,10,10,5);
largerCodeOld(txyz);
%% you can now use:
xyzt = rand(10,10,5,20);
largerCodeNew( xyzt );
end
function largerCodeOld(txyz)
% do stuff with txyz
end
function largerCodeNew(xyzt)
txyz = permute(xyzt,[ 4, 1:3 ]);
% either do stuff with txyz
% or call largerCodeOld( txyz )
end

Related

How do I split results into separate variables in matlab?

I'm pretty new to matlab, so I'm guessing there is some shortcut way to do this but I cant seem to find it
results = eqs\soltns;
A = results(1);
B = results(2);
C = results(3);
D = results(4);
E = results(5);
F = results(6);
soltns is a 6x1 vector and eqs is a 6x6 matrix, and I want the results of the operation in their own separate variables. It didn't let me save it like
[A, B, C, D, E, F] = eqs\soltns;
Which I feel like would make sense, but it doesn't work.
Up to now, I have never come across a MATLAB function doing this directly (but maybe I'm missing something?). So, my solution would be to write a function distribute on my own.
E.g. as follows:
result = [ 1 2 3 4 5 6 ];
[A,B,C,D,E,F] = distribute( result );
function varargout = distribute( vals )
assert( nargout <= numel( vals ), 'To many output arguments' )
varargout = arrayfun( #(X) {X}, vals(:) );
end
Explanation:
nargout is special variable in MATLAB function calls. Its value is equal to the number of output parameters that distribute is called with. So, the check nargout <= numel( vals ) evaluates if enough elements are given in vals to distribute them to the output variables and raises an assertion otherwise.
arrayfun( #(X) {X}, vals(:) ) converts vals to a cell array. The conversion is necessary as varargout is also a special variable in MATLAB's function calls, which must be a cell array.
The special thing about varargout is that MATLAB assigns the individual cells of varargout to the individual output parameters, i.e. in the above call to [A,B,C,D,E,F] as desired.
Note:
In general, I think such expanding of variables is seldom useful. MATLAB is optimized for processing of arrays, separating them to individual variables often only complicates things.
Note 2:
If result is a cell array, i.e. result = {1,2,3,4,5,6}, MATLAB actually allows to split its cells by [A,B,C,D,E,F] = result{:};
One way as long as you know the size of results in advance:
results = num2cell(eqs\soltns);
[A,B,C,D,E,F] = results{:};
This has to be done in two steps because MATLAB does not allow for indexing directly the results of a function call.
But note that this method is hard to generalize for arbitrary sizes. If the size of results is unknown in advance, it would probably be best to leave results as a vector in your downstream code.

Reading a specific line in Julia

Since I'm new in Julia I have sometimes obvious for you problems.
This time I do not know how to read the certain piece of data from the file i.e.:
...
stencil: half/bin/3d/newton
bin: intel
Per MPI rank memory allocation (min/avg/max) = 12.41 | 12.5 | 12.6 Mbytes
Step TotEng PotEng Temp Press Pxx Pyy Pzz Density Lx Ly Lz c_Tr
200000 261360.25 261349.16 413.63193 2032.9855 -8486.073 4108.1669
200010 261360.45 261349.36 413.53903 22.925126 -29.762605 132.03134
200020 261360.25 261349.17 413.46495 20.373081 -30.088775 129.6742
Loop
What I want is to read this file from third row after "Step" (the one which starts at 200010 which can be a different number - I have many files which stars at the same place but from different integer) until the program will reach the "Loop". Could you help me please? I'm stacked - I don't know how to combine the different options of julia to do it...
Here is one solution. It uses eachline to iterate over the lines. The loop skips the header, and any empty lines, and breaks when the Loop line is found. The lines to keep are returned in a vector. You might have to modify the detection of the header and/or the end token depending on the exact file format you have.
julia> function f(file)
result = String[]
for line in eachline(file)
if startswith(line, "Step") || isempty(line)
continue # skip the header and any empty lines
elseif startswith(line, "Loop")
break # stop reading completely
end
push!(result, line)
end
return result
end
f (generic function with 2 methods)
julia> f("file.txt")
3-element Array{String,1}:
"200000 261360.25 261349.16 413.63193 2032.9855 -8486.073 4108.1669"
"200010 261360.45 261349.36 413.53903 22.925126 -29.762605 132.03134"
"200020 261360.25 261349.17 413.46495 20.373081 -30.088775 129.6742"

Empty find matlab

I am trying to find what's the number on the array for the 1000 value. This is my code:
size = linspace(420, 2200, 100000);
size1000 = find(size==1000);
It returns an empty variable for size 1000. If I actually change 1000 with 420 it actually returns 1 like it should. Why is this not working?
The result of find is empty because 1000 is not in the array and isn't expected to be. Using the inputs to linspace, your expected step size is going to be 0.0178
(2200 - 420) / 100000
% 0.0178
With this step size and a starting value of 420, you're never going to hit the value 1000 exactly. The closest values in the array are 1000.001 and 999.983. If you want to identify values that are close to 1000, you can do something like the following instead.
inds = find(abs(size - 1000) < 0.01);
As a side-note, do not use size as the name of a variable since that is the name of a built-in MATLAB function and using it as a variable name can result in unexpected behavior.
You can also use logical indexing to simply remove all of the values below 1000, and then you know that the first component of what is left will be your answer....
a = size(size>1000);
a(1)
For what it is worth, please PLEASE do not use size as a variable name. size is an important MATLAB function to get the size of a matrix. For example,
>> size(randn(2,3))
ans =
2 3
However, when you declare a variable named size, like you do in your code, you will hide this function. So now, at some point later in your code, if you called size(randn(2,3)), you will get the cryptic error
Subscript indices must either be real positive integers or
logicals.
These are extremely tricky to track down, so please avoid it.

MATLAB append two arrays(one string cell and one numeric vector) into a .csv

I have two arrays, X and Y
X has numeric data like this:
12342
1355
2324
...
Y has strings like this:
APPLE
METRO
BLANKET
...
I want to append these arrays into a pre-existing .csv in this format:
X(1,1), Y{1,1}
X(2,1), Y{2,1}
X(3,1), Y{2,1}
...
How should I do so?
unfortunately writing cell arrays to csvs can be tricky. One way or another you need to loop through so you can access the data within each cell. The reason for cells not writing automatically is that a cell can contain anything - like a whole matrix of data.
The most versatile way that will allow for any types of cell/matrix combos is to use fprintf - you just need to specify a format.
http://au.mathworks.com/help/matlab/ref/fprintf.html
nrows = size(x,1);
fid = fopen('newfile.csv','w');
for aa = 1 : nrows
fprintf(fid,'%f,%s\r\n', x(aa,1), y{aa,1});
end
you can use %d instead of %f if you are only chasing decimal numbers instead of floating point precision.
I have found fprintf to be faster than any of the alternatives for this sort of situation. It is a little more low-level but allows you to write anything you like to file.

Distributing a function over a single dimension of an array in MATLAB?

I often find myself wanting to collapse an n-dimensional matrix across one dimension using a custom function, and can't figure out if there is a concise incantation I can use to do this.
For example, when parsing an image, I often want to do something like this. (Note! Illustrative example only. I know about rgb2gray for this specific case.)
img = imread('whatever.jpg');
s = size(img);
for i=1:s(1)
for j=1:s(2)
bw_img(i,j) = mean(img(i,j,:));
end
end
I would love to express this as something like:
bw = on(color, 3, #mean);
or
bw(:,:,1) = mean(color);
Is there a short way to do this?
EDIT: Apparently mean already does this; I want to be able to do this for any function I've written. E.g.,
...
filtered_img(i,j) = reddish_tint(img(i,j,:));
...
where
function out = reddish_tint(in)
out = in(1) * 0.5 + in(2) * 0.25 + in(3) * 0.25;
end
Many basic MATLAB functions, like MEAN, MAX, MIN, SUM, etc., are designed to operate across a specific dimension:
bw = mean(img,3); %# Mean across dimension 3
You can also take advantage of the fact that MATLAB arithmetic operators are designed to operate in an element-wise fashion on matrices. For example, the operation in your function reddish_tint can be applied to all pixels of your image with this single line:
filtered_img = 0.5.*img(:,:,1)+0.25.*img(:,:,2)+0.25.*img(:,:,3);
To handle a more general case where you want to apply a function to an arbitrary dimension of an N-dimensional matrix, you will probably want to write your function such that it accepts an additional input argument for which dimension to operate over (like the above-mentioned MATLAB functions do) and then uses some simple logic (i.e. if-else statements) and element-wise matrix operations to apply its computations to the proper dimension of the matrix.
Although I would not suggest using it, there is a quick-and-dirty solution, but it's rather ugly and computationally more expensive. You can use the function NUM2CELL to collect values along a dimension of your array into cells of a cell array, then apply your function to each cell using the function CELLFUN:
cellArray = num2cell(img,3); %# Collect values in dimension 3 into cells
filtered_img = cellfun(#reddish_tint,cellArray); %# Apply function to each cell
I wrote a helper function called 'vecfun' that might be useful for this, if it's what you're trying to achieve?
link
You could use BSXFUN for at least some of your tasks. It performs an element-wise operation among two arrays by expanding the size 1 - dimensions to match the size in the other array. The 'reddish tint' function would become
reddish_image = bsxfun(#times,img,cat(3,0.5,0.25,0.25));
filtered_img = sum(reddish_image,3);
All the above statement requires in order to work is that the third dimension of img has size 1 or 3. Number and size of the other dimensions can be chosen freely.
If you are consistently trying to apply a function to a vector comprised by the 3 dimension in a block of images, I recommend using a pair reshapes, for instance:
Img = rand(480,640,3);
sz = size(Img);
output = reshape(myFavoriteFunction(reshape(Img,[prod(sz(1:2)),sz(3)])'),sz);
This way you can swap in any function that operates on matrices along their first dimension.
edit.
The above code will crash if you input an image which has only one layer: The function below can fix it.
function o = nLayerImage2MatrixOfPixels(i)
%function o = nLayerImage2MatrixOfPixels(i)
s = size(i);
if(length(s) == 2)
s3 = 1;
else
s3 = s(3);
end
o = reshape(i,[s(1)*s(2),s(3)])';
Well, if you are only concerned with multiplying vectors together you could just use the dot product, like this:
bw(:,:,1)*[0.3;0.2;0.5]
taking care that the shapes of your vectors conform.

Resources