public static Image GetAnisotropicFSC(Image volume1, Image volume2, Image mask, float pixelsize, float threshold, int healpixOrder, float scaleToGlobalShell) { float MaskFraction = mask.GetHostContinuousCopy().Sum() / mask.ElementsReal; Image Masked1 = volume1.GetCopyGPU(); volume1.FreeDevice(); Masked1.Multiply(mask); Image Volume1FT = Masked1.AsFFT(true); Masked1.Dispose(); Image Masked2 = volume2.GetCopyGPU(); Masked2.Multiply(mask); volume2.FreeDevice(); Image Volume2FT = Masked2.AsFFT(true); Masked2.Dispose(); mask.FreeDevice(); float2[] Angles = Helper.GetHealpixRotTilt(healpixOrder, "C1", 91f); float3[] Directions = Angles.Select(a => Matrix3.Euler(a.X * Helper.ToRad, a.Y * Helper.ToRad, 0).Transposed() * float3.UnitZ).ToArray(); float AngleSpacing = (float)(60.0 / Math.Pow(2, Math.Min(2, healpixOrder))); float[] ConeShells = new float[Directions.Length]; CPU.ConicalFSC(Volume1FT.GetHostContinuousCopy(), Volume2FT.GetHostContinuousCopy(), volume1.Dims, Helper.ToInterleaved(Directions), Directions.Length, AngleSpacing, 10, threshold, MaskFraction, ConeShells); Volume1FT.Dispose(); Volume2FT.Dispose(); float MeanShell = MathHelper.MeanWeighted(ConeShells, MathHelper.Mult(ConeShells, ConeShells)); ConeShells = ConeShells.Select(v => v / MeanShell * scaleToGlobalShell).ToArray(); int NRot = (int)Math.Ceiling(360f / AngleSpacing * 2); float StepRot = 360f / NRot; int NTilt = (int)Math.Ceiling(90f / AngleSpacing * 2); float StepTilt = 90f / NTilt; float[] PolarValues = new float[NRot * NTilt]; for (int t = 0; t < NTilt; t++) { float Tilt = t * StepTilt; for (int r = 0; r < NRot; r++) { float Rot = r * StepRot; float3 Direction = Matrix3.Euler(Rot * Helper.ToRad, Tilt * Helper.ToRad, 0).Transposed() * float3.UnitZ; float WeightedShell = 0; float Weights = 0; for (int d = 0; d < Directions.Length; d++) { float AngleDiff = (float)Math.Acos(Math.Min(1, Math.Abs(float3.Dot(Directions[d], Direction)))) * Helper.ToDeg; float Weight = 1 - Math.Min(1, AngleDiff / AngleSpacing); WeightedShell += ConeShells[d] * Weight; Weights += Weight; } PolarValues[t * NRot + r] = volume1.Dims.X * pixelsize / (WeightedShell / Weights); } } return(new Image(PolarValues, new int3(NRot, NTilt, 1))); }