public static List <List <Complex[, ]> > Split(GriddingConstants c, List <List <Subgrid> > metadata, Complex[,] grid) { var phasorPrecomputed = new Complex[c.SubgridSize, c.SubgridSize]; Parallel.For(0, phasorPrecomputed.GetLength(0), (y) => { for (int x = 0; x < phasorPrecomputed.GetLength(1); x++) { double phase = -Math.PI * (x + y - c.SubgridSize) / c.SubgridSize; phasorPrecomputed[y, x] = new Complex(Math.Cos(phase), Math.Sin(phase)); } }); var subgrids = new List <List <Complex[, ]> >(metadata.Count); for (int baseline = 0; baseline < metadata.Count; baseline++) { var blMeta = metadata[baseline]; var blSubgridsData = new List <Complex[, ]>(blMeta.Count); subgrids.Add(blSubgridsData); for (int subgrid = 0; subgrid < blMeta.Count; subgrid++) { var meta = blMeta[subgrid]; var subgridData = new Complex[c.SubgridSize, c.SubgridSize]; blSubgridsData.Add(subgridData); int subgridX = meta.UPixel; int subgridY = meta.VPixel; int subgridW = meta.WLambda; bool negativeW = subgridW < 0; int wLayer = negativeW ? -subgridW - 1 : subgridW; for (int y = 0; y < c.SubgridSize; y++) { for (int x = 0; x < c.SubgridSize; x++) { int xDst = (x + (c.SubgridSize / 2)) % c.SubgridSize; int yDst = (y + (c.SubgridSize / 2)) % c.SubgridSize; int xSrc = negativeW ? c.GridSize - subgridX - x : subgridX + x; int ySrc = negativeW ? c.GridSize - subgridY - y : subgridY + y; if (subgridX >= 1 && subgridX < c.GridSize - c.SubgridSize && subgridY >= 1 && subgridY < c.GridSize - c.SubgridSize) { var phasor = phasorPrecomputed[y, x]; var value = grid[ySrc, xSrc]; value = negativeW ? Complex.Conjugate(value) : value; subgridData[yDst, xDst] = phasor * value; } } } } } return(subgrids); }
public static Complex[,,] DeGridW(GriddingConstants c, List <List <Subgrid> > metadata, Complex[,] grid, double[,,] uvw, double[] frequencies) { FFT.Shift(grid); var ftGridded = AdderWStack.Split(c, metadata, grid); var gridded = SubgridFFT.Backward(c, ftGridded); var visibilities = Gridder.Backwards(c, metadata, gridded, uvw, frequencies, c.SubgridSpheroidal); return(visibilities); }
public static List <Complex[, ]> GridW(GriddingConstants c, List <List <Subgrid> > metadata, Complex[,,] visibilities, double[,,] uvw, double[] frequencies) { var gridded = Gridder.Forward(c, metadata, uvw, visibilities, frequencies, c.SubgridSpheroidal); var ftgridded = SubgridFFT.Forward(c, gridded); var grid = AdderWStack.Add(c, metadata, ftgridded); FFT.Shift(grid); return(grid); }
public static List <List <Complex[, ]> > Forward(GriddingConstants c, List <List <Complex[, ]> > subgrids) { var output = new List <List <Complex[, ]> >(subgrids.Count); for (int baseline = 0; baseline < subgrids.Count; baseline++) { var blSubgrids = subgrids[baseline]; var blOutput = new List <Complex[, ]>(blSubgrids.Count); for (int subgrid = 0; subgrid < blSubgrids.Count; subgrid++) { var sub = blSubgrids[subgrid]; var outFourier = new Complex[c.SubgridSize, c.SubgridSize]; using (var imageSpace = new AlignedArrayComplex(16, c.SubgridSize, c.SubgridSize)) using (var fourierSpace = new AlignedArrayComplex(16, imageSpace.GetSize())) { //copy for (int i = 0; i < c.SubgridSize; i++) { for (int j = 0; j < c.SubgridSize; j++) { imageSpace[i, j] = sub[i, j]; } } /* * This is not a bug * The original IDG implementation uses the inverse Fourier transform here, even though the * Subgrids are already in image space. */ DFT.IFFT(imageSpace, fourierSpace); var norm = 1.0 / (c.SubgridSize * c.SubgridSize); for (int i = 0; i < c.SubgridSize; i++) { for (int j = 0; j < c.SubgridSize; j++) { outFourier[i, j] = fourierSpace[i, j] * norm; } } } blOutput.Add(outFourier); } output.Add(blOutput); } return(output); }
public static double[,] ToImage(GriddingConstants c, List <List <Subgrid> > metadata, Complex[,,] visibilities, double[,,] uvw, double[] frequencies) { var gridded = Gridder.Forward(c, metadata, uvw, visibilities, frequencies, c.SubgridSpheroidal); var ftgridded = SubgridFFT.Forward(c, gridded); var grid = Adder.Add(c, metadata, ftgridded); FFT.Shift(grid); var img = FFT.Backward(grid, c.VisibilitiesCount); FFT.Shift(img); //remove spheroidal from grid /*for (int y = 0; y < img.GetLength(0); y++) * for (int x = 0; x < img.GetLength(1); x++) * img[y, x] = img[y, x] / c.GridSpheroidal[y, x];*/ return(img); }
public static List <List <Complex[, ]> > Backward(GriddingConstants c, List <List <Complex[, ]> > subgrids) { var output = new List <List <Complex[, ]> >(subgrids.Count); for (int baseline = 0; baseline < subgrids.Count; baseline++) { var blSubgrids = subgrids[baseline]; var blOutput = new List <Complex[, ]>(blSubgrids.Count); for (int subgrid = 0; subgrid < blSubgrids.Count; subgrid++) { var sub = blSubgrids[subgrid]; var outFourier = new Complex[c.SubgridSize, c.SubgridSize]; using (var imageSpace = new AlignedArrayComplex(16, c.SubgridSize, c.SubgridSize)) using (var fourierSpace = new AlignedArrayComplex(16, imageSpace.GetSize())) { //copy for (int i = 0; i < c.SubgridSize; i++) { for (int j = 0; j < c.SubgridSize; j++) { imageSpace[i, j] = sub[i, j]; } } DFT.FFT(imageSpace, fourierSpace); //normalization is done in the Gridder for (int i = 0; i < c.SubgridSize; i++) { for (int j = 0; j < c.SubgridSize; j++) { outFourier[i, j] = fourierSpace[i, j]; } } } blOutput.Add(outFourier); } output.Add(blOutput); } return(output); }
public static Complex[,] Add(GriddingConstants c, List <List <Subgrid> > metadata, List <List <Complex[, ]> > subgrids) { var grid = new Complex[c.GridSize, c.GridSize]; for (int baseline = 0; baseline < subgrids.Count; baseline++) { var blMeta = metadata[baseline]; var blSubgridsData = subgrids[baseline]; for (int subgrid = 0; subgrid < blSubgridsData.Count; subgrid++) { var meta = blMeta[subgrid]; var subgridData = blSubgridsData[subgrid]; int gridX = meta.UPixel; int gridY = meta.VPixel; //TODO: gridX >= 0, even though in plan we check that it is >= 1. if (gridX >= 0 && gridX < c.GridSize - c.SubgridSize && gridY >= 0 && gridY < c.GridSize - c.SubgridSize) { for (int y = 0; y < c.SubgridSize; y++) { for (int x = 0; x < c.SubgridSize; x++) { int xSrc = (x + (c.SubgridSize / 2)) % c.SubgridSize; int ySrc = (y + (c.SubgridSize / 2)) % c.SubgridSize; double phase = PI * (x + y - c.SubgridSize) / c.SubgridSize; Complex phasor = new Complex(Cos(phase), Sin(phase)); grid[gridY + y, gridX + x] += subgridData[ySrc, xSrc] * phasor; } } } else { throw new Exception("invalid grid"); } } } return(grid); }
public static double[,] CalculatePSF(GriddingConstants c, List <List <Subgrid> > metadata, double[,,] uvw, bool[,,] flags, double[] frequencies) { var visibilities = new Complex[uvw.GetLength(0), uvw.GetLength(1), frequencies.Length]; for (int i = 0; i < visibilities.GetLength(0); i++) { for (int j = 0; j < visibilities.GetLength(1); j++) { for (int k = 0; k < visibilities.GetLength(2); k++) { if (!flags[i, j, k]) { visibilities[i, j, k] = new Complex(1.0, 0); } else { visibilities[i, j, k] = new Complex(0, 0); } } } } var gridded = Gridder.Forward(c, metadata, uvw, visibilities, frequencies, c.SubgridSpheroidal); var ftgridded = SubgridFFT.Forward(c, gridded); var grid = Adder.Add(c, metadata, ftgridded); FFT.Shift(grid); var psf = FFT.Backward(grid, c.VisibilitiesCount); FFT.Shift(psf); //remove spheroidal from grid /*for (int y = 0; y < psf.GetLength(0); y++) * for (int x = 0; x < psf.GetLength(1); x++) * psf[y, x] = psf[y, x] / c.GridSpheroidal[y, x];*/ return(psf); }
public static List <List <Complex[, ]> > Split(GriddingConstants c, List <List <Subgrid> > metadata, Complex[,] grid) { var subgrids = new List <List <Complex[, ]> >(metadata.Count); for (int baseline = 0; baseline < metadata.Count; baseline++) { var blMeta = metadata[baseline]; var blSubgridsData = new List <Complex[, ]>(blMeta.Count); subgrids.Add(blSubgridsData); for (int subgrid = 0; subgrid < blMeta.Count; subgrid++) { var meta = blMeta[subgrid]; var subgridData = new Complex[c.SubgridSize, c.SubgridSize]; blSubgridsData.Add(subgridData); int gridX = meta.UPixel; int gridY = meta.VPixel; if (gridX >= 0 && gridX < c.GridSize - c.SubgridSize && gridY >= 0 && gridY < c.GridSize - c.SubgridSize) { for (int y = 0; y < c.SubgridSize; y++) { for (int x = 0; x < c.SubgridSize; x++) { int xDst = (x + (c.SubgridSize / 2)) % c.SubgridSize; int yDst = (y + (c.SubgridSize / 2)) % c.SubgridSize; double phase = -PI * (x + y - c.SubgridSize) / c.SubgridSize; var phasor = new Complex(Cos(phase), Sin(phase)); subgridData[yDst, xDst] = grid[gridY + y, gridX + x] * phasor; } } } } } return(subgrids); }
public static Complex[,] GridPSF(GriddingConstants c, List <List <Subgrid> > metadata, double[,,] uvw, bool[,,] flags, double[] frequencies) { var visibilities = new Complex[uvw.GetLength(0), uvw.GetLength(1), frequencies.Length]; for (int i = 0; i < visibilities.GetLength(0); i++) { for (int j = 0; j < visibilities.GetLength(1); j++) { for (int k = 0; k < visibilities.GetLength(2); k++) { if (!flags[i, j, k]) { visibilities[i, j, k] = new Complex(1.0, 0); } else { visibilities[i, j, k] = new Complex(0, 0); } } } } return(Grid(c, metadata, visibilities, uvw, frequencies)); }
public static List <Complex[, ]> Add(GriddingConstants c, List <List <Subgrid> > metadata, List <List <Complex[, ]> > subgrids) { var grid = new List <Complex[, ]>(c.WLayerCount); for (int i = 0; i < c.WLayerCount; i++) { grid.Add(new Complex[c.GridSize, c.GridSize]); } var phasorPrecomputed = new Complex[c.SubgridSize, c.SubgridSize]; Parallel.For(0, phasorPrecomputed.GetLength(0), (y) => { for (int x = 0; x < phasorPrecomputed.GetLength(1); x++) { double phase = Math.PI * (x + y - c.SubgridSize) / c.SubgridSize; phasorPrecomputed[y, x] = new Complex(Math.Cos(phase), Math.Sin(phase)); } }); for (int baseline = 0; baseline < subgrids.Count; baseline++) { var blMeta = metadata[baseline]; var blSubgridsData = subgrids[baseline]; for (int subgrid = 0; subgrid < blSubgridsData.Count; subgrid++) { var meta = blMeta[subgrid]; var data = blSubgridsData[subgrid]; int subgridX = meta.UPixel; int subgridY = meta.VPixel; int subgridW = meta.WLambda; // Mirror subgrid coordinates for negative w-values bool negativeW = subgridW < 0; if (negativeW) { subgridX = c.GridSize - subgridX - c.SubgridSize + 1; subgridY = c.GridSize - subgridY - c.SubgridSize + 1; subgridW = -subgridW - 1; } // Check whether subgrid fits in grid if (!(subgridX >= 1 && subgridX < c.GridSize - c.SubgridSize && subgridY >= 1 && subgridY < c.GridSize - c.SubgridSize)) { continue; } for (int y = 0; y < c.SubgridSize; y++) { int y_mirrored = c.SubgridSize - 1 - y; int y_ = negativeW ? y_mirrored : y; for (int x = 0; x < c.SubgridSize; x++) { int x_mirrored = c.SubgridSize - 1 - x; int x_ = negativeW ? x_mirrored : x; int xSrc = (x_ + (c.SubgridSize / 2)) % c.SubgridSize; int ySrc = (y_ + (c.SubgridSize / 2)) % c.SubgridSize; int xDst = subgridX + x; int yDst = subgridY + y; var phasor = phasorPrecomputed[y_, x_]; var value = phasor * data[ySrc, xSrc]; value = negativeW ? Complex.Conjugate(value) : value; grid[subgridW][yDst, xDst] += value; } } } } return(grid); }
public static Complex[,,] Backwards(GriddingConstants c, List <List <Subgrid> > metadata, List <List <Complex[, ]> > subgridData, double[,,] uvw, double[] frequencies, float[,] spheroidal) { var wavenumbers = MathFunctions.FrequencyToWavenumber(frequencies); var imagesize = c.ScaleArcSec * c.GridSize; var outputVis = new Complex[uvw.GetLength(0), uvw.GetLength(1), wavenumbers.Length]; Parallel.For(0, metadata.Count, baseline => { var blMeta = metadata[baseline]; var blSubgrids = subgridData[baseline]; for (int subgrid = 0; subgrid < blMeta.Count; subgrid++) { //de-apply a-term correction var meta = blMeta[subgrid]; var data = blSubgrids[subgrid]; var pixels_copy = new Complex[c.SubgridSize, c.SubgridSize]; for (int y = 0; y < c.SubgridSize; y++) { for (int x = 0; x < c.SubgridSize; x++) { var sph = spheroidal[y, x]; int xSrc = (x + (c.SubgridSize / 2)) % c.SubgridSize; int ySrc = (y + (c.SubgridSize / 2)) % c.SubgridSize; pixels_copy[y, x] = sph * data[ySrc, xSrc]; } } var uOffset = (meta.UPixel + c.SubgridSize / 2 - c.GridSize / 2) * (2 * PI / imagesize); var vOffset = (meta.VPixel + c.SubgridSize / 2 - c.GridSize / 2) * (2 * PI / imagesize); var tmpW_lambda = c.WStepLambda * (meta.WLambda + 0.5); var wOffset = 2 * PI * tmpW_lambda; int sampleEnd = meta.timeSampleStart + meta.timeSampleCount; for (int time = meta.timeSampleStart; time < sampleEnd; time++) { var u = uvw[baseline, time, 0]; var v = uvw[baseline, time, 1]; var w = uvw[baseline, time, 2]; for (int channel = 0; channel < wavenumbers.Length; channel++) { var visibility = new Complex(); for (int y = 0; y < c.SubgridSize; y++) { for (int x = 0; x < c.SubgridSize; x++) { //calculate directional cosines. exp(2*PI*j * (u*l + v*m + w*n)) var l = ComputeL(x, c.SubgridSize, imagesize); var m = ComputeL(y, c.SubgridSize, imagesize); var n = ComputeN(l, m); double phaseIndex = u * l + v * m + w * n; double phaseOffset = uOffset * l + vOffset * m + wOffset * n; double phase = (phaseIndex * wavenumbers[channel]) - phaseOffset; var phasor = new Complex(Cos(phase), Sin(phase)); visibility += pixels_copy[y, x] * phasor; } } double scale = 1.0f / (c.SubgridSize * c.SubgridSize); outputVis[baseline, time, channel] = visibility * scale; } } } }); return(outputVis); }
public static List <List <Complex[, ]> > Forward(GriddingConstants c, List <List <Subgrid> > metadata, double[,,] uvw, Complex[,,] visibilities, double[] frequencies, float[,] spheroidal) { var wavenumbers = MathFunctions.FrequencyToWavenumber(frequencies); var imagesize = c.ScaleArcSec * c.GridSize; var output = new List <List <Complex[, ]> >(metadata.Count); for (int baseline = 0; baseline < metadata.Count; baseline++) { var blMeta = metadata[baseline]; var blSubgrids = new List <Complex[, ]>(blMeta.Count); output.Add(blSubgrids); } Parallel.For(0, metadata.Count, baseline => { var blMeta = metadata[baseline]; var blSubgrids = output[baseline]; for (int subgrid = 0; subgrid < blMeta.Count; subgrid++) { var meta = blMeta[subgrid]; var subgridOutput = new Complex[c.SubgridSize, c.SubgridSize]; // [+ p.SubgridSize / 2 - p.GridSize / 2] undoes shift from Planner var uOffset = (meta.UPixel + c.SubgridSize / 2 - c.GridSize / 2) * (2 * PI / imagesize); var vOffset = (meta.VPixel + c.SubgridSize / 2 - c.GridSize / 2) * (2 * PI / imagesize); var tmpW_lambda = c.WStepLambda * (meta.WLambda + 0.5); var wOffset = 2 * PI * tmpW_lambda; //discrete w-correction, similar to w-stacking for (int y = 0; y < c.SubgridSize; y++) { for (int x = 0; x < c.SubgridSize; x++) { //real and imaginary part of the pixel. We ignore polarization here var pixel = new Complex(); //calculate directional cosines. exp(2*PI*j * (u*l + v*m + w*n)) var l = ComputeL(x, c.SubgridSize, imagesize); var m = ComputeL(y, c.SubgridSize, imagesize); var n = ComputeN(l, m); int sampleEnd = meta.timeSampleStart + meta.timeSampleCount; for (int time = meta.timeSampleStart; time < sampleEnd; time++) { var u = uvw[baseline, time, 0]; var v = uvw[baseline, time, 1]; var w = uvw[baseline, time, 2]; double phaseIndex = u * l + v * m + w * n; double phaseOffset = uOffset * l + vOffset * m + wOffset * n; for (int channel = 0; channel < wavenumbers.Length; channel++) { double phase = phaseOffset - (phaseIndex * wavenumbers[channel]); var phasor = new Complex(Cos(phase), Sin(phase)); var vis = visibilities[baseline, time, channel]; pixel += vis * phasor; } } //idg A-correction goes here var sph = spheroidal[y, x]; int xDest = (x + (c.SubgridSize / 2)) % c.SubgridSize; int yDest = (y + (c.SubgridSize / 2)) % c.SubgridSize; subgridOutput[yDest, xDest] = pixel * sph; } } blSubgrids.Add(subgridOutput); } }); return(output); }
/// <summary> /// Partitions the Visibility data into subgrids. /// /// In the original implementation, this is called "Plan" /// </summary> /// <param name="c"></param> /// <param name="uvw"></param> /// <param name="frequencies"></param> /// <returns></returns> public static List <List <ImageDomainGridder.Subgrid> > CreatePartition(GriddingConstants c, double[,,] uvw, double[] frequencies) { var imagesize = c.ScaleArcSec * c.GridSize; List <List <ImageDomainGridder.Subgrid> > outputGrids = new List <List <ImageDomainGridder.Subgrid> >(uvw.GetLength(0)); for (int baseline = 0; baseline < uvw.GetLength(0); baseline++) { var baselineOutput = new List <ImageDomainGridder.Subgrid>(uvw.GetLength(1)); outputGrids.Add(baselineOutput); //idg checks a-terms bins we ignore the a-term correction here, so we can simplify and only iterate over Datapoint[,] datapoints = new Datapoint[uvw.GetLength(1), frequencies.Length]; //timeSamplesCount channelsCount int time = 0; for (time = 0; time < uvw.GetLength(1); time++) { //convert visibilities for (int channel = 0; channel < frequencies.Length; channel++) { var dp = new Datapoint { timestep = time, channel = channel, uPixel = MetersToPixels(uvw[baseline, time, 0], imagesize, frequencies[channel]), vPixel = MetersToPixels(uvw[baseline, time, 1], imagesize, frequencies[channel]), wLambda = MetersToLambda(uvw[baseline, time, 2], frequencies[channel]) }; datapoints[time, channel] = dp; } } time = 0; Subgrid subgrid = new Subgrid(c); while (time < uvw.GetLength(1)) { subgrid.Reset(); int timeSamplePerSubgrid = 0; //this is taken from the original IDG implementation. Here may be room for simplification for (; time < uvw.GetLength(1); time++) { var dpChannel0 = datapoints[time, 0]; var dpChannelMax = datapoints[time, frequencies.Length - 1]; var hack = dpChannelMax.Copy(); hack.wLambda = dpChannel0.wLambda; // hack taken over from IDG reference implementation if (subgrid.AddVisibility(dpChannel0) && subgrid.AddVisibility(hack)) { timeSamplePerSubgrid++; if (timeSamplePerSubgrid == c.MaxTimestepsPerSubgrid) { time++; break; } } else { break; } } //Handle empty subgrids if (timeSamplePerSubgrid == 0) { var dp = datapoints[time, 0]; if (Double.IsInfinity(dp.uPixel) && Double.IsInfinity(dp.vPixel)) { throw new Exception("could not place (all) visibilities on subgrid (too many channnels, kernel size too large)"); } else if (Double.IsInfinity(dp.uPixel) || Double.IsInfinity(dp.vPixel)) { //added by me throw new Exception("could not place (all) visibilities on subgrid (too many channnels, kernel size too large)"); } else { // Advance to next timeslot when visibilities for current timeslot had infinite coordinates time++; continue; } } subgrid.Finish(); if (subgrid.InRange()) { //TODO: Fix hack and hand over data properly var data = new ImageDomainGridder.Subgrid(); data.timeSampleCount = timeSamplePerSubgrid; data.timeSampleStart = time - timeSamplePerSubgrid; data.baselineIdx = baseline; data.UPixel = subgrid.UPixel; data.VPixel = subgrid.VPixel; data.WLambda = subgrid.WIndex; baselineOutput.Add(data); } else { subgrid.InRange(); throw new Exception("subgrid falls not within grid"); } } }//baseline return(outputGrids); }
public Subgrid(GriddingConstants c) { this.c = c; this.Reset(); }