cannam@167: /* cannam@167: * Copyright (c) 2003, 2007-14 Matteo Frigo cannam@167: * Copyright (c) 2003, 2007-14 Massachusetts Institute of Technology cannam@167: * cannam@167: * This program is free software; you can redistribute it and/or modify cannam@167: * it under the terms of the GNU General Public License as published by cannam@167: * the Free Software Foundation; either version 2 of the License, or cannam@167: * (at your option) any later version. cannam@167: * cannam@167: * This program is distributed in the hope that it will be useful, cannam@167: * but WITHOUT ANY WARRANTY; without even the implied warranty of cannam@167: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the cannam@167: * GNU General Public License for more details. cannam@167: * cannam@167: * You should have received a copy of the GNU General Public License cannam@167: * along with this program; if not, write to the Free Software cannam@167: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA cannam@167: * cannam@167: */ cannam@167: cannam@167: #include "ifftw-mpi.h" cannam@167: cannam@167: /* Return the radix r for a 1d MPI transform of a distributed dimension d, cannam@167: with the given flags and transform size. That is, decomposes d.n cannam@167: as r * m, Cooley-Tukey style. Also computes the block sizes rblock cannam@167: and mblock. Returns 0 if such a decomposition is not feasible. cannam@167: This is unfortunately somewhat complicated. cannam@167: cannam@167: A distributed Cooley-Tukey algorithm works as follows (see dft-rank1.c): cannam@167: cannam@167: d.n is initially distributed as an m x r array with block size mblock[IB]. cannam@167: Then it is internally transposed to an r x m array with block size cannam@167: rblock[IB]. Then it is internally transposed to m x r again with block cannam@167: size mblock[OB]. Finally, it is transposed to r x m with block size cannam@167: rblock[IB]. cannam@167: cannam@167: If flags & SCRAMBLED_IN, then the first transpose is skipped (the array cannam@167: starts out as r x m). If flags & SCRAMBLED_OUT, then the last transpose cannam@167: is skipped (the array ends up as m x r). To make sure the forward cannam@167: and backward transforms use the same "scrambling" format, we swap r cannam@167: and m when sign != FFT_SIGN. cannam@167: cannam@167: There are some downsides to this, especially in the case where cannam@167: either m or r is not divisible by n_pes. For one thing, it means cannam@167: that in general we can't use the same block size for the input and cannam@167: output. For another thing, it means that we can't in general honor cannam@167: a user's "requested" block sizes in d.b[]. Therefore, for simplicity, cannam@167: we simply ignore d.b[] for now. cannam@167: */ cannam@167: INT XM(choose_radix)(ddim d, int n_pes, unsigned flags, int sign, cannam@167: INT rblock[2], INT mblock[2]) cannam@167: { cannam@167: INT r, m; cannam@167: cannam@167: UNUSED(flags); /* we would need this if we paid attention to d.b[*] */ cannam@167: cannam@167: /* If n_pes is a factor of d.n, then choose r to be d.n / n_pes. cannam@167: This not only ensures that the input (the m dimension) is cannam@167: equally distributed if possible, and at the r dimension is cannam@167: maximally equally distributed (if d.n/n_pes >= n_pes), it also cannam@167: makes one of the local transpositions in the algorithm cannam@167: trivial. */ cannam@167: if (d.n % n_pes == 0 /* it's good if n_pes divides d.n ...*/ cannam@167: && d.n / n_pes >= n_pes /* .. unless we can't use n_pes processes */) cannam@167: r = d.n / n_pes; cannam@167: else { /* n_pes does not divide d.n, pick a factor close to sqrt(d.n) */ cannam@167: for (r = X(isqrt)(d.n); d.n % r != 0; ++r) cannam@167: ; cannam@167: } cannam@167: if (r == 1 || r == d.n) return 0; /* punt if we can't reduce size */ cannam@167: cannam@167: if (sign != FFT_SIGN) { /* swap {m,r} so that scrambling is reversible */ cannam@167: m = r; cannam@167: r = d.n / m; cannam@167: } cannam@167: else cannam@167: m = d.n / r; cannam@167: cannam@167: rblock[IB] = rblock[OB] = XM(default_block)(r, n_pes); cannam@167: mblock[IB] = mblock[OB] = XM(default_block)(m, n_pes); cannam@167: cannam@167: return r; cannam@167: }