Making array matrix with minimal code in IDL - idl-programming-language

I am new to IDL. I want to minimize code. I am writing this
for x=0,(pixel-1) do begin
for y=0,(pixel-1) do begin
for z=0,(pixel-1) do begin
Bx[x,y,z]=-(n*3.14/pixel)*cos(n*3.14*x/pixel)*sin(m*3.14*y/pixel)*exp(-sqrt(n^2+m^2)*3.14*z/pixel)
endfor
endfor
endfor
And I want to reduce to something like
x=dindgen(pixel)
y=dindgen(pixel)
z=dindgen(pixel)
Bx[x,y,z]=-(n*3.14/pixel)*cos(n*3.14*x/pixel)*sin(m*3.14*y/pixel)*exp(-sqrt(n^2+m^2)*3.14*z/pixel)
How can I do it?

Depending on the size of pixel you may not be able to create these arrays:
x = rebin(reform(dindgen(pixel), pixel, 1, 1), pixel, pixel, pixel)
y = rebin(reform(dindgen(pixel), 1, pixel, 1), pixel, pixel, pixel)
z = rebin(reform(dindgen(pixel), 1, 1, pixel), pixel, pixel, pixel)
But if you can, you should be able to do:
Bx = -(n*3.14/pixel)*cos(n*3.14*x/pixel)*sin(m*3.14*y/pixel)*exp(-sqrt(n^2+m^2)*3.14*z/pixel)

Related

MPI cartesian grid : cumulate a scalar value through the procs of a given axis of the grid

I have an MPI question about using a cartesian grid of processors which represents a spatial domain decomposition (a cubic geometrical domain split into several smaller cubes...).
I have many possible communicators to address the procs, as for example a comm along each of the 3 axes I,J,K, or along a plane IK,JK,IJ, etc..).
I need to cumulate a scalar value (SCAL) through the procs which belong to a given axis (let's say the K axis, defined by I=J=0).
The origin proc 0-0-0 has a given value for SCAL (say SCAL000)
I want to update the 'following' proc (0-0-1) by doing SCAL = SCAL + SCAL000, and I want to propagate this along the axis. At the end, the last proc of the axis should have the total sum of SCAL along the axis. Please, do you see a way to do this with MPI ? I have tried many things (with MPI_SENDRECV, but unsuccessfully...). Thank you in any case.
I give some precision on my question (and an answer):
I have a 3D domain which is split into a cartesian grid of subdomains with MPI. Each sub-domain knows its size (physical size in meters) but doesn't know it's absolute position relatively to a given absolute origin, and this is what I needed.
My solution (probably classical) consists in a cycling shift in the 3 directions (only X direction is shown hereafter) and make a MPI_SENDRECV.
In the following, I suppose I know:
- "NEIGHBORS": array which gives the process number of the 6 direct neighbors of the current process.
- ALRNK_I(): ARRAY which stores the processes which are in the same line (X direction) than the current process.
- I_PROCS: is the number or processes in this line (size of ALRNK_I)
- LENGTH(1): is the physical size (meters) of a current domain in X direction. Each process receives the Xmax of the left neighbor (that it stores in its Xmin buffer) and sends its Xmax value to it's right neighbor (which does the same thing). We just have to care with the limits and make a cycling condition...(in the code, the xmax value is XEND, the xmin value is XORI)
DO N=1,I_PROCS-1
DEST=NEIGHBORS(1 , 0, 0)
SOUR=NEIGHBORS(-1, 0, 0)
XEND=XORI+LENGTH(1) ! UPDATE ORIGIN
IF (DEST.EQ.MPI_PROC_NULL) DEST=ALRNK_I(1)
IF (SOUR.EQ.MPI_PROC_NULL) THEN
SOUR=ALRNK_I(I_PROCS)
CALL MPI_SENDRECV(XEND, 1, MPI_REAL8, DEST, TAG,
& DUMMY, 1, MPI_REAL8, SOUR, TAG,
& COMM_IKJ,STATUS, MPIERR)
ELSE
CALL MPI_SENDRECV(XEND, 1, MPI_REAL8, DEST, TAG,
& XORI, 1, MPI_REAL8, SOUR, TAG,
& COMM_IKJ,STATUS, MPIERR)
ENDIF
ENDDO

What is an inch? Setting the length for arrows

Somewhat inexplicably, the length parameter in arrows is specified in inches (from ?arrows):
length length of the edges of the arrow head (in inches).
R source even goes so far as to explicitly make note that this measurement is in inches in a comment, highlighting how peculiar this design is.
That means the relative size of the arrows depends on dev.size(). What's not clear is how to translate inches into axis units (which are infinitely more useful in the first place). Here's a simplified version:
h = c(1, 2, 3)
xs = barplot(h, space = 0, ylim = c(0, 4))
arrows(xs, h - .5, xs, h + .5,
length = .5*mean(diff(xs)))
How this displays will depend on the device. E.g. here is the output on this device:
png('test.png', width = 5, height = 5)
And here it is on another:
png('test.png', width = 8, height = 8)
It's a bit of an optical illusion to tell on sight, but the arrows are indeed the same width in the two plots. How can I control this so that both plots (which convey the same data) display identically? More specifically, how can I make sure that the arrows are exactly .5 plot units in width?
I spent far too much time in the rabbit hole on this, but here goes. I'll document a bit of my journey first to aid others who happen upon this in the types of nooks and crannies to search when trying to pull yourself up by your bootstraps.
I started looking in the source of arrows, but to no avail, since it quickly dives into internal code. So I searched the R source for "C_arrows" to find what's happening; luckily, it's not too esoteric, as far as R internal code goes. Poking around it seems the workhorse is actually GArrow, but this was a dead end, as it seems the length parameter isn't really transformed there (IIUC this means the conversion to inches is done for the other coordinates and length is untouched). But I happened to notice some GConvert calls that looked closer to what I want and hoped to find some user-facing function that appeals to these directly.
This led me to go back to R and to simply run through the gamut of functions in the same package as arrows looking for anything that could be useful:
ls(envir = as.environment('package:grDevices'))
ls(envir = as.environment('package:graphics'))
Finally I found three functions in graphics: xinch, yinch, and xyinch (all found on ?xinch) are used for the opposite of my goal here -- namely, they take inches and convert them into device units (in the x, y, and x&y directions, respectively). Luckily enough, these functions are all very simple, e.g. the work horse of xinch is the conversion factor:
diff(par("usr")[1:2])/par("pin")[1L]
Examining ?par (for the 1,000,000th time), indeed pin and usr are exactly the graphical parameter we need (pin is new to me, usr comes up here and there):
pin The current plot dimensions, (width, height), in inches.
usr A vector of the form c(x1, x2, y1, y2) giving the extremes of the user coordinates of the plotting region.
Hence, we can convert from plot units to inches by inverting this function:
xinch_inv = function(dev_unit) {
dev_unit * par("pin")[1L]/diff(par("usr")[1:2])
}
h = c(1, 2, 3)
xs = barplot(h, space = 0, ylim = c(0, 4))
arrows(xs, h - .5, xs, h + .5,
# just convert plot units to inches
length = xinch_inv(.5*mean(diff(xs))))
Resulting in (5x5):
And (8x8):
One further note, it appears length is the length of each side of the arrow head -- using length = xinch_inv(.5), code = 3, angle = 90 results in segments as wide as the bars (i.e., 1).
On the off chance you're interested, I've packaged these in my package as xdev2in, etc.; GitHub only for now.

Rendering 2d function plot

My task is to produce the plot of a 2-dimensional function in real time using nothing but linear algebra and color (imagine having to compute an image buffer in plain C++ from a function definition, for example f(x,y) = x^2 + y^2). The output should be something like this 3d plot.
So far I have tried 3 approaches:
1: Ray tracing:
Divide the (x,y) plane into triangles, find the z-values of each vertex, thus divide the plot into triangles. Intersect each ray with the triangles.
2: Sphere tracing:
a method for rendering implicit surfaces described here.
3: Rasterization:
The inverse of (1). Split the plot into triangles, project them onto the camera plane, loop over the pixels of the canvas and for each one choose the "closest" projected pixel.
All of these are way to slow. Part of my assignment is moving around the camera, so the plot has to be re-rendered in each frame. Please point me towards another source of information/another algorithm/any kind of help. Thank you.
EDIT
As pointed out, here is the pseudocode for my very basic rasterizer. I am aware that this code might not be flawless, but it should resemble the general idea. However, when splitting my plot into 200 triangles (which I do not expect to be enough) it already runs very slowly, even without rendering anything. I am not even using a depth buffer for visibility. I just wanted to test the speed by setting up a frame buffer as follows:
NOTE: In the JavaScript framework I am using, _ denotes array indexing and a..b composes a list from a to b.
/*
* Raster setup.
* The raster is a pxH x pxW array.
* Raster coordinates might be negative or larger than the array dimensions.
* When rendering (i.e. filling the array) positions outside the visible raster will not be filled (i.e. colored).
*/
pxW := Width of the screen in pixels.
pxH := Height of the screen in pixels.
T := Transformation matrix of homogeneous world points to raster space.
// Buffer setup.
colBuffer = apply(1..pxW, apply(1..pxH, 0)); // pxH x pxW array of black pixels.
// Positive/0 if the point is on the right side of the line (V1,V2)/exactly on the line.
// p2D := point to test.
// V1, V2 := two vertices of the triangle.
edgeFunction(p2D, V1, V2) := (
det([p2D-V1, V2-V1]);
);
fillBuffer(V0, V1, V2) := (
// Dehomogenize.
hV0 = V0/(V0_3);
hV1 = V1/(V1_3);
hV2 = V2/(V2_3);
// Find boundaries of the triangle in raster space.
xMin = min(hV0.x, hV1.x, hV2.x);
xMax = max(hV0.x, hV1.x, hV2.x);
yMin = min(hV0.y, hV1.y, hV2.y);
yMax = max(hV0.y, hV1.y, hV2.y);
xMin = floor(if(xMin >= 0, xMin, 0));
xMax = ceil(if(xMax < pxW, xMax, pxW));
yMin = floor(if(yMin >= 0, yMin, 0));
yMax = ceil(if(yMax < pxH, yMax, pxH));
// Check for all points "close to" the triangle in raster space whether they lie inside it.
forall(xMin..xMax, x, forall(yMin..yMax, y, (
p2D = (x,y);
i = edgeFunction(p2D, hV0.xy, hV1.xy) * edgeFunction(p2D, hV1.xy, hV2.xy) * edgeFunction(p2D, hV2.xy, hV0.xy);
if (i > 0, colBuffer_y_x = 1); // Fill all points inside the triangle with some placeholder.
)));
);
mapTrianglesToScreen() := (
tvRaster = homogVerts * T; // Triangle vertices in raster space.
forall(1..(length(tvRaster)/3), i, (
actualI = i / 3 + 1;
fillBuffer(tvRaster_actualI, tvRaster_(actualI + 1), tvRaster_(actualI + 2));
));
);
// After all this, render the colBuffer.
What is wrong about this approach? Why is it so slow?
Thank you.
I would go with #3 it is really not that complex so you should obtain > 20 fps on standard machine with pure SW rasterizer (without any libs) if coded properly. My bet is you are using some slow API like PutPixel or SetPixel or doing some crazy thing. Without seeing code or better description of how you do it is hard to elaborate. All the info you need to do this is in here:
Algorithm to fill triangle
HSV histogram
Understanding 4x4 homogenous transform matrices
Do look also in the sub-links in each ...

Weighted random coordinates

This may be more of a search for a term, but solutions are also welcome. I'm looking to create n amount of random x,y coordinates. The issue I am having is that I would like the coordinates to be "weighted" or have more of a chance of falling closer to a specific point. I've created something close by using this pseudo code:
x = rand(100) //random integer between 0 and 100
x = rand(x) //random number between 0 and the previous rand value
//randomize x to positive or negative
//repeat for y
This works to pull objects toward 0,0 - however if you create enough points, you can see a pattern of the x and y axis. This is because the even if x manages to get to 100, the chances are high that y will then be closer to.
I'm looking to avoid the formation of this x,y line. Bonus points if there is a way to throw in multiple "weighted coordinates" that the random coordinates would sort of gravitate to, instead of statically to 0,0.
This is easier in polar coordinates. All you have to do is to generate a uniform random angle and a power distributed distance. Here's an example in Python:
import math
from random import random
def randomPoint(aroundX, aroundY, scale, density):
angle = random()*2*math.pi
x = random()
if x == 0:
x = 0.0000001
distance = scale * (pow(x, -1.0/density) - 1)
return (aroundX + distance * math.sin(angle),
aroundY + distance * math.cos(angle))
Here's the distribution of randomPoint(0, 0, 1, 1):
We can shift it to center around another point like 1,2 with randomPoint(1, 2, 1, 1):
We can spread across a larger area by increasing the scale. Here's randomPoint(0, 0, 3, 1):
And we can change the shape, that is the tendency to flock together, by changing the density. randomPoint(0, 0, 1, 3):

rgl clear specific area of plot

I have been using rgl to plot a block model - using shade3d to render the blocks.
I'd like to replace certain blocks using an interactive process. The problem is the rendering is cumulative, so if I overlay a white cube with alpha 0.5 on a blue cube with alpha 1, I'll still see the blue cube. [see below]. I looked at clear3d, but seems to only work at a global level. Any ideas?
shade3d(translate3d(cube3d(),
1,
1,
1),
col="blue",
alpha = 1)
After some work:
shade3d(translate3d(cube3d(),
1,
1,
1),
col="white",
alpha = 0.5)
clear3d() removes all objects, as you've discovered. To remove a single object, you want rgl.pop().
As long as you know a given shape's object ID (i.e. its position on the stack of plotted objects), you can use rgl.pop() to remove it. The key bookkeeping detail, then, is that you must keep track of the object ID of any object you may later want to remove.
(Conveniently, most rgl functions whose side-effect is to draw an object to the rgl device return the object ID (or vector of IDs) as their return value. Alternatively, use rgl.ids() to access the object IDs of all objects plotted on the current device.)
A few more details from ?rgl.pop:
RGL holds two stacks. One is for shapes and the other is for
lights. 'clear3d' and 'rgl.clear' clear the specified stack, or
restore the defaults for the bounding box (not visible) or
viewpoint. By default with 'id=0' 'rgl.pop' removes the top-most
(last added) node on the shape stack. The 'id' argument may be
used to specify arbitrary item(s) to remove from the specified
stack.
So in your case you might do:
library(rgl)
ii <- shade3d(translate3d(cube3d(), 1, 1, 1), col="blue", alpha = 1)
shade3d(translate3d(cube3d(), 1, 1, 1), col="white", alpha = 0.5)
rgl.pop(id = ii)

Resources