home *** CD-ROM | disk | FTP | other *** search
- /*--------------------------------------------------------------------
- * The GMT-system: @(#)grdfft.c 2.24 3/13/95
- *
- * Copyright (c) 1991-1995 by P. Wessel and W. H. F. Smith
- * See README file for copying and redistribution conditions.
- *--------------------------------------------------------------------*/
- /*
- * grdfft.c
- *
- * A program to do various operations
- * on grdfiles in the frequency domain.
- *
- * W.H.F. Smith, 7 March 1990.
- *
- * Version 2.0.2 has option to do power spectral estimates.
- * added by WHFSmith, 4 Feb 1992.
- *
- */
-
- #include "gmt.h"
-
- #ifndef FSIGNIF
- #define FSIGNIF 24
- #endif
- #define UP_DOWN_CONTINUE 0
- #define AZIMUTHAL_DERIVATIVE 1
- #define DIFFERENTIATE 2
- #define INTEGRATE 3
- #define ISOSTASY 4
- #define FILTER 5
- #define SPECTRUM 6
-
- /* Macro definition ij_data(i,j) finds the array index to an element
- containing the real data(i,j) in the padded complex array: */
-
- #define ij_data(i,j) (2*(nx2*((j)+j_data_start)+(i)+i_data_start))
-
-
- int narray[2];
- int ndim = 2, ksign, iform = 1, i, j, k, n, nx2 = 0, ny2 = 0, ndatac, i_data_start, j_data_start;
- int pad[4];
-
- BOOLEAN map_units = FALSE, force_narray = FALSE, suggest_narray = FALSE, leave_trend_alone = FALSE, n_user_set = FALSE;
-
- double data_var, data2_var, delta_kx, delta_ky;
- double a[3]; /* Plane fitting coefficients */
- double mGal_at_45 = 980619.9203; /* Moritz's 1980 IGF value for gravity in mGal at 45 degrees latitude */
-
- char *infile = NULL, *outfile = NULL;
-
- struct GRD_HEADER h;
- struct F_INFO {
- double lc[3]; /* Low-cut frequency for r, x, and y */
- double lp[3]; /* Low-pass frequency for r, x, and y */
- double hp[3]; /* High-pass frequency for r, x, and y */
- double hc[3]; /* High-cut frequency for r, x, and y */
- double ltaper[3]; /* Low taper width for r, x, and y */
- double htaper[3]; /* High taper width for r, x, and y */
- int do_this[3]; /* T/F this filter wanted for r, x, and y */
- int set_already;
- } f_info;
-
- struct FFT_SUGGESTION {
- int nx;
- int ny;
- int worksize; /* # single-complex elements needed in work array */
- int totalbytes; /* (8*(nx*ny + worksize)) */
- double run_time;
- double rms_rel_err;
- } fft_sug[3]; /* [0] holds fastest, [1] most accurate, [2] least storage */
-
-
- float *datac, *workc;
- double scale_out = 1.0;
-
- main (argc, argv)
- int argc;
- char **argv;
- {
-
- int op_count = 0, n_op_count = 0, par_count = 0, n_par = 0, *operation = NULL;
- BOOLEAN error = FALSE, stop, chose_spectrum = FALSE, give_wavelength;
- double *par = NULL;
-
- for (i = 0; i < 3; i++) {
- f_info.lc[i] = f_info.lp[i] = -1.0; /* Set negative, below valid freqency range */
- f_info.hp[i] = f_info.hc[i] = MAXDOUBLE; /* Set huge positive, above valid freqency range */
- f_info.ltaper[i] = f_info.htaper[i] = 0.0; /* 1/width of taper, zero when not used */
- f_info.do_this[i] = FALSE;
- }
- f_info.set_already = FALSE;
-
- argc = gmt_begin (argc, argv);
-
- for (i = 1; i < argc; i++) {
- if (argv[i][0] == '-') {
- switch (argv[i][1]) {
-
- /* Common parameters */
-
- case 'V':
- case '\0':
- error += get_common_args (argv[i], 0, 0, 0, 0);
- break;
-
- /* Supplemental parameters */
-
- case 'A':
- n_op_count++;
- operation = (int *) memory((char *)operation, n_op_count, sizeof(int), "grdfft");
- operation[op_count] = AZIMUTHAL_DERIVATIVE;
- op_count++;
- n_par++;
- par = (double *) memory((char *)par, n_par, sizeof(double), "grdfft");
- if ((sscanf(&argv[i][2], "%lf", &par[par_count])) != 1) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -A option: Cannot read azimuth\n", gmt_program);
- error++;
- }
- par_count++;
- break;
- case 'C':
- n_op_count++;
- operation = (int *) memory((char *)operation, n_op_count, sizeof(int), "grdfft");
- operation[op_count] = UP_DOWN_CONTINUE;
- op_count++;
- n_par++;
- par = (double *) memory((char *)par, n_par, sizeof(double), "grdfft");
- if ((sscanf(&argv[i][2], "%lf", &par[par_count])) != 1) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -C option: Cannot read zlevel\n", gmt_program);
- error++;
- }
- par_count++;
- break;
- case 'D':
- n_op_count++;
- operation = (int *) memory((char *)operation, n_op_count, sizeof(int), "grdfft");
- operation[op_count] = DIFFERENTIATE;
- op_count++;
- n_par++;
- par = (double *) memory((char *)par, n_par, sizeof(double), "grdfft");
- if (argv[i][2]) {
- par[par_count] = (argv[i][2] == 'g' || argv[i][2] == 'G') ? mGal_at_45 : atof (&argv[i][2]);
- if (par[par_count] == 0.0) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -D option: scale must be nonzero\n", gmt_program);
- error++;
- }
- }
- par_count++;
- break;
- case 'E':
- n_op_count++;
- operation = (int *) memory((char *)operation, n_op_count, sizeof(int), "grdfft");
- operation[op_count] = SPECTRUM;
- op_count++;
- n_par++;
- par = (double *) memory((char *)par, n_par, sizeof(double), "grdfft");
- par[par_count] = 0.0;
- give_wavelength = FALSE;
- j = 2;
- while(argv[i][j]) {
- if (argv[i][2] == 'x' || argv[i][2] == 'X')
- par[par_count] = 1.0;
- else if (argv[i][2] == 'y' || argv[i][2] == 'Y')
- par[par_count] = -1.0;
- else if (argv[i][j] == 'w' || argv[i][j] == 'W')
- give_wavelength = TRUE;
- j++;
- }
- par_count++;
- chose_spectrum = TRUE;
- break;
- case 'F':
- if (!(f_info.set_already)) {
- n_op_count++;
- operation = (int *) memory((char *)operation, n_op_count, sizeof(int), "grdfft");
- operation[op_count] = FILTER;
- op_count++;
- f_info.set_already = TRUE;
- }
- if (parse_f_string(&argv[i][2])) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -F option: ", gmt_program);
- error++;
- }
- break;
- case 'G':
- outfile = &argv[i][2];
- break;
- case 'I':
- n_op_count++;
- operation = (int *) memory((char *)operation, n_op_count, sizeof(int), "grdfft");
- operation[op_count] = INTEGRATE;
- op_count++;
- n_par++;
- par = (double *) memory((char *)par, n_par, sizeof(double), "grdfft");
- if (argv[i][2]) {
- par[par_count] = (argv[i][2] == 'g' || argv[i][2] == 'G') ? mGal_at_45 : atof (&argv[i][2]);
- if (par[par_count] == 0.0) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -I option: scale must be nonzero\n", gmt_program);
- error++;
- }
- }
- par_count++;
- break;
- case 'L':
- leave_trend_alone = TRUE;
- break;
- case 'M':
- map_units = TRUE;
- break;
- case 'N':
- if (argv[i][2] == 'f' || argv[i][2] == 'F')
- force_narray = TRUE;
- else if (argv[i][2] == 'q' || argv[i][2] == 'Q')
- suggest_narray = TRUE;
- else {
- sscanf(&argv[i][2], "%d/%d", &nx2, &ny2);
- n_user_set = TRUE;
- }
- break;
- case 'S':
- scale_out = (argv[i][2] == 'd' || argv[i][2] == 'D') ? 1.0e6: atof (&argv[i][2]);
- break;
- case 'T':
- n_op_count++;
- operation = (int *) memory((char *)operation, n_op_count, sizeof(int), "grdfft");
- operation[op_count] = ISOSTASY;
- op_count++;
- n_par += 5;
- par = (double *) memory((char *)par, n_par, sizeof(double), "grdfft");
- n = sscanf (&argv[i][2], "%lf/%lf/%lf/%lf/%lf", &par[par_count],
- &par[par_count+1], &par[par_count+2], &par[par_count+3], &par[par_count+4]);
- for (j = 1, k = 0; j < 5; j++) if (par[par_count+j] < 0.0) k++;
- if (n != 5 || k > 0) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -T option. Correct syntax:\n", gmt_program);
- fprintf (stderr, "\t-T<te>/<rhol>/<rhom>/<rhow>/<rhoi>, all densities >= 0\n");
- error++;
- }
- par_count += 5;
- leave_trend_alone = TRUE;
- break;
- default:
- error = TRUE;
- gmt_default_error (argv[i][1]);
- break;
- }
- }
- else
- infile = argv[i];
- }
-
- if (argc == 1 || gmt_quick) {
- fprintf (stderr, "grdfft %s - Perform mathematical operations on grdfiles in the frequency domain\n\n", GMT_VERSION);
- fprintf (stderr,"usage: grdfft <in_grdfile> [-G<out_grdfile>] [-A<azimuth>] [-C<zlevel>]\n");
- fprintf (stderr,"\t[-D[<scale>]] [-E[x_or_y][w]] [-F[x_or_y]<lc>/<lp>/<hp>/<hc>] [-I[<scale>]] [-L] [-M]\n");
- fprintf (stderr,"\t[-N<stuff>] [-S<scale>] [-T<te/rl/rm/rw/ri>] [-V]\n\n");
-
- if (gmt_quick) exit (-1);
-
- fprintf (stderr,"\tin_grdfile is the input netCDF grdfile\n");
- fprintf (stderr, "\tOPTIONS:\n");
- fprintf (stderr,"\t-G filename for output netCDF grdfile\n");
- fprintf (stderr,"\t-A<azimuth> Take azimuthal derivative along line <azimuth> degrees CW from North.\n");
- fprintf (stderr,"\t-C<zlevel> Continue field upward (+) or downward (-) to zlevel (meters).\n");
- fprintf (stderr,"\t-D Differentiate, i.e., multiply by kr [ * scale] [Default scale gives mGal from m]\n");
- fprintf (stderr,"\t-E Estimate spEctrum of r [x] [y]. Write f, power[f], 1 std dev(power[f]) to stdout.\n");
- fprintf (stderr,"\t\tAppend w to write wavelength instead of frequency.\n");
- fprintf (stderr,"\t-F Filter r [x] [y] freq according to four wavelengths <lc>/<lp>/<hp>/<hc>.\n");
- fprintf (stderr,"\t freq outside <lc>/<hc> are cut; inside <lp>/<hp> are passed, rest are tapered.\n");
- fprintf (stderr,"\t replace wavelength by - to skip, e.g. -F-/-/500/100 is a low-pass filter.\n");
- fprintf (stderr,"\t-I Integrate, i.e., devide by kr [ * scale] [Default scale gives m from mGal]\n");
- fprintf (stderr,"\t-L Leave trend alone. Do not remove least squares plane from data. [Default removes plane].\n");
- fprintf (stderr,"\t-M Map units used. Convert grid dimensions from degrees to meters.\n");
- fprintf (stderr,"\t-N<stuff> Choose or inquire about suitable grid dimensions for FFT.\n");
- fprintf (stderr,"\t\t-Nf will force the FFT to use the dimensions of the data.\n");
- fprintf (stderr,"\t\t-Nq will inQuire about more suitable dimensions.\n");
- fprintf (stderr,"\t\t-N<nx>/<ny> will do FFT on array size <nx>/<ny> (Must be >= grdfile size).\n");
- fprintf (stderr,"\t\tDefault chooses dimensions >= data which optimize speed, accuracy of FFT.\n");
- fprintf (stderr,"\t\tIf FFT dimensions > grdfile dimensions, data are extended and tapered to zero.\n");
- fprintf (stderr,"\t-S multiply field by scale after inverse FFT [1.0]\n");
- fprintf (stderr,"\t Give -Sd to convert deflection of vertical to micro-radians\n");
- fprintf (stderr,"\t-T Compute isostatic response. Input file is topo load. Append elastic thickness,\n");
- fprintf (stderr,"\t and densities of load, mantle, water, and infill, all in SI units\n");
- fprintf (stderr,"\t It also implicitly sets -L\n");
- fprintf (stderr,"\tList operations in the order desired for execution.\n");
- exit (-1);
- }
-
- if (!(n_op_count)) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR: Must specify at least one operation\n", gmt_program);
- error++;
- }
- if (n_user_set && (nx2 <= 0 || ny2 <= 0)) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -N option: nx2 and/or ny2 <= 0\n", gmt_program);
- error++;
- }
- if (scale_out == 0.0) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -S option: scale must be nonzero\n", gmt_program);
- error++;
- }
- if (!infile) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR: Must specify input file\n", gmt_program);
- error++;
- }
- if (chose_spectrum && outfile) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -E option: -G ignored (stdout used for ASCII output)\n", gmt_program);
- error++;
- }
- if (!chose_spectrum && !outfile) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -G option: Must specify output file\n", gmt_program);
- error++;
- }
- if (error) exit (-1);
-
- if (read_data(argc, argv) ) {
- fprintf (stderr,"grdfft: Fatal memory error. Exiting.\n");
- exit (-1);
- }
-
- /* Check that no NaNs are present */
-
- stop = FALSE;
- for (j = 0; !stop && j < h.ny; j++) for (i = 0; !stop && i < h.nx; i++) stop = bad_float ((double)datac[ij_data(i,j)]);
- if (stop) {
- fprintf (stderr, "grdfft: Input grid cannot have NaNs!\n");
- exit (-1);
- }
-
- if (gmtdefs.verbose) fprintf (stderr, "grdfft: Forward FFT\n");
-
- ksign = -1;
-
- fourt_(datac, narray, &ndim, &ksign, &iform, workc);
-
- for (op_count=0, par_count = 0; op_count < n_op_count; op_count++) {
- switch(operation[op_count]) {
- case UP_DOWN_CONTINUE:
- if (gmtdefs.verbose) ((par[par_count] < 0.0) ? fprintf (stderr, "grdfft: Downward continuation\n") : fprintf (stderr, "grdfft: Upward continuation\n"));
- do_continuation (&par[par_count]);
- par_count++;
- break;
- case AZIMUTHAL_DERIVATIVE:
- if (gmtdefs.verbose) fprintf (stderr, "grdfft: azimuthal derivative\n");
- do_azimuthal_derivative (&par[par_count]);
- par_count++;
- break;
- case DIFFERENTIATE:
- if (gmtdefs.verbose) fprintf (stderr, "grdfft: differentiate\n");
- do_differentiate (&par[par_count]);
- par_count++;
- break;
- case INTEGRATE:
- if (gmtdefs.verbose) fprintf (stderr, "grdfft: integrate\n");
- do_integrate (&par[par_count]);
- par_count++;
- break;
- case ISOSTASY:
- if (gmtdefs.verbose) fprintf (stderr, "grdfft: isostasy\n");
- do_isostasy (&par[par_count]);
- par_count += 5;
- break;
- case FILTER:
- if (gmtdefs.verbose) fprintf (stderr, "grdfft: filter\n");
- do_filter ();
- break;
- case SPECTRUM:
- if (gmtdefs.verbose) fprintf (stderr, "grdfft: spectrum\n");
- do_spectrum (&par[par_count], give_wavelength);
- par_count += 2;
- break;
- }
- }
-
- if (outfile) {
-
- if (gmtdefs.verbose) fprintf (stderr, "grdfft: Inverse FFT\n");
-
- ksign = 1;
- fourt_(datac, narray, &ndim, &ksign, &iform, workc);
-
- scale_out *= (2.0 / ndatac);
- for (i = 0; i < ndatac; i+= 2) datac[i] *= scale_out;
-
- /* The data are in the middle of the padded array: */
-
- if (write_grd (outfile, &h, datac, h.x_min, h.x_max, h.y_min, h.y_max, pad, TRUE)) {
- fprintf (stderr, "grdfft: Error writing file %s\n", outfile);
- exit (-1);
- }
- }
-
- free((char *)workc);
- free((char *)datac);
-
- if (gmtdefs.verbose) fprintf (stderr, "grdfft: Done\n");
-
- gmt_end (argc, argv);
-
- exit(0);
- }
-
- read_data(argc, argv)
- int argc;
- char **argv;
- {
- int worksize, factors[32];
- double tdummy, edummy;
- void suggest_fft();
- void fourt_stats();
-
- if (read_grd_info (infile, &h)) {
- fprintf (stderr, "grdfft: Error opening file %s\n", infile);
- return (-1);
- }
-
- grd_init (&h, argc, argv, TRUE);
-
- /* Get dimensions as may be appropriate: */
- if (n_user_set) {
- if (nx2 < h.nx || ny2 < h.ny) {
- fprintf(stderr,"grdfft: Error: You specified -Nnx/ny smaller than input grdfile. Ignored.\n");
- n_user_set = FALSE;
- }
- }
- if (!(n_user_set) ) {
- if (force_narray) {
- nx2 = h.nx;
- ny2 = h.ny;
- }
- else {
- suggest_fft(h.nx, h.ny, fft_sug, (gmtdefs.verbose || suggest_narray));
- if (fft_sug[1].totalbytes < fft_sug[0].totalbytes) {
- /* The most accurate solution needs same or less storage
- * as the fastest solution; use the most accurate's dimensions: */
- nx2 = fft_sug[1].nx;
- ny2 = fft_sug[1].ny;
- }
- else {
- /* Use the sizes of the fastest solution */
- nx2 = fft_sug[0].nx;
- ny2 = fft_sug[0].ny;
- }
- }
- }
-
- /* Get here when nx2 and ny2 are set to the vals we will use. */
- narray[0] = nx2;
- narray[1] = ny2;
- fourt_stats(nx2, ny2, factors, &edummy, &worksize, &tdummy);
- if (gmtdefs.verbose) fprintf(stderr,"grdfft: Data dimension %d %d\tFFT dimension %d %d\n",
- h.nx, h.ny, nx2, ny2);
-
- /* Make an array of floats 2 * nx2 * ny2 for complex data: */
- ndatac = 2 * nx2 * ny2;
- datac = (float *) memory (CNULL, ndatac, sizeof(float), "grdfft");
- memset ((char *)datac, 0, ndatac*sizeof(float));
- if (worksize) {
- if (worksize < nx2) worksize = nx2;
- if (worksize < ny2) worksize = ny2;
- worksize *= 2;
- workc = (float *) memory (CNULL, worksize, sizeof(float), "grdfft");
- memset ((char *)workc, 0, worksize*sizeof(float));
- }
- else {
- workc = (float *) memory (CNULL, 4, sizeof(float), "grdfft");
- memset ((char *)workc, 0, 4*sizeof(float));
- }
-
- /* Put the data in the middle of the padded array: */
-
- i_data_start = pad[0] = (nx2 - h.nx)/2; /* zero if nx2 < h.nx+1 */
- j_data_start = pad[3] = (ny2 - h.ny)/2;
- pad[1] = nx2 - h.nx - pad[0];
- pad[2] = ny2 - h.ny - pad[3];
-
- if (read_grd (infile, &h, datac, h.x_min, h.x_max, h.y_min, h.y_max, pad, TRUE)) {
- fprintf (stderr, "grdfft: Error reading file %s\n", infile);
- return (-1);
- }
-
- if (!(leave_trend_alone) )remove_plane();
- if (!(force_narray) )taper_edges();
-
- delta_kx = 2 * M_PI / (nx2 * h.x_inc);
- delta_ky = 2 * M_PI / (ny2 * h.y_inc);
- if (map_units) {
- /* Give delta_kx, delta_ky units of 2pi/meters */
- double tmp;
- tmp = 2.0 * M_PI * gmtdefs.ellipse[N_ELLIPSOIDS-1].eq_radius / 360.0; /* GRS-80 sphere m/degree */
- delta_kx /= (tmp * cos(0.5 * (h.y_min + h.y_max) * D2R) );
- delta_ky /= tmp;
- }
-
- return(0);
- }
-
- int remove_plane()
- {
- /* Remove the best-fitting plane by least squares.
-
- Let plane be z = a0 + a1 * x + a2 * y. Choose the
- center of x,y coordinate system at the center of
- the array. This will make the Normal equations
- matrix G'G diagonal, so solution is trivial. Also,
- spend some multiplications on normalizing the
- range of x,y into [-1,1], to avoid roundoff error. */
-
- int one_or_zero;
- double x_half_length, one_on_xhl, y_half_length, one_on_yhl;
- double sumx2, sumy2, x, y, z;
-
- one_or_zero = (h.node_offset) ? 0 : 1;
- x_half_length = 0.5 * (h.nx - one_or_zero);
- one_on_xhl = 1.0 / x_half_length;
- y_half_length = 0.5 * (h.ny - one_or_zero);
- one_on_yhl = 1.0 / y_half_length;
-
- sumx2 = sumy2 = data_var = 0.0;
- a[2] = a[1] = a[0] = 0.0;
-
- for (j = 0; j < h.ny; j++) {
- y = one_on_yhl * (j - y_half_length);
- for (i = 0; i < h.nx; i++) {
- x = one_on_xhl * (i - x_half_length);
- z = datac[ij_data(i,j)];
- a[0] += z;
- a[1] += z*x;
- a[2] += z*y;
- sumx2 += x*x;
- sumy2 += y*y;
- }
- }
- a[0] /= (h.nx*h.ny);
- a[1] /= sumx2;
- a[2] /= sumy2;
- for (j = 0; j < h.ny; j++) {
- y = one_on_yhl * (j - y_half_length);
- for (i = 0; i < h.nx; i++) {
- x = one_on_xhl * (i - x_half_length);
- datac[ij_data(i,j)] -= (a[0] + a[1]*x + a[2]*y);
- data_var += (datac[ij_data(i,j)] * datac[ij_data(i,j)]);
- }
- }
- data_var = sqrt(data_var / (h.nx*h.ny - 1));
- /* Rescale a1,a2 into user's units, in case useful later: */
- a[1] *= (2.0/(h.x_max - h.x_min));
- a[2] *= (2.0/(h.y_max - h.y_min));
- if(gmtdefs.verbose)fprintf (stderr,"grdfft: Plane removed. Mean, S.D., Dx, Dy: %.8lg\t%.8lg\t%.8lg\t%.8lg\n", a[0],data_var,a[1],a[2]);
- }
-
- int taper_edges ()
- {
- int im, jm, il1, ir1, il2, ir2, jb1, jb2, jt1, jt2;
- double scale, cos_wt;
-
- /* Note that if nx2 = h.nx+1 and ny2 = h.ny + 1, then this routine
- will do nothing; thus a single row/column of zeros may be
- added to the bottom/right of the input array and it cannot
- be tapered. But when (nx2 - h.nx)%2 == 1 or ditto for y,
- this is zero anyway. */
-
-
- /* First reflect about xmin and xmax, point symmetric about edge point: */
-
- for (im = 1; im <= i_data_start; im++) {
- il1 = -im; /* Outside xmin; left of edge 1 */
- ir1 = im; /* Inside xmin; right of edge 1 */
- il2 = il1 + h.nx - 1; /* Inside xmax; left of edge 2 */
- ir2 = ir1 + h.nx - 1; /* Outside xmax; right of edge 2 */
- for (j = 0; j < h.ny; j++) {
- datac[ij_data(il1,j)] = 2.0*datac[ij_data(0,j)] - datac[ij_data(ir1,j)];
- datac[ij_data(ir2,j)] = 2.0*datac[ij_data((h.nx-1),j)] - datac[ij_data(il2,j)];
- }
- }
-
- /* Next, reflect about ymin and ymax.
- At the same time, since x has been reflected,
- we can use these vals and taper on y edges: */
-
- scale = M_PI / (j_data_start + 1);
-
- for (jm = 1; jm <= j_data_start; jm++) {
- jb1 = -jm; /* Outside ymin; bottom side of edge 1 */
- jt1 = jm; /* Inside ymin; top side of edge 1 */
- jb2 = jb1 + h.ny - 1; /* Inside ymax; bottom side of edge 2 */
- jt2 = jt1 + h.ny - 1; /* Outside ymax; bottom side of edge 2 */
- cos_wt = 0.5 * (1.0 + cos(jm * scale) );
- for (i = -i_data_start; i < nx2 - i_data_start; i++) {
- datac[ij_data(i,jb1)] = cos_wt * (2.0*datac[ij_data(i,0)] - datac[ij_data(i,jt1)]);
- datac[ij_data(i,jt2)] = cos_wt * (2.0*datac[ij_data(i,(h.ny-1))] - datac[ij_data(i,jb2)]);
- }
- }
-
- /* Now, cos taper the x edges: */
-
- scale = M_PI / (i_data_start + 1);
- for (im = 1; im <= i_data_start; im++) {
- il1 = -im;
- ir1 = im;
- il2 = il1 + h.nx - 1;
- ir2 = ir1 + h.nx - 1;
- cos_wt = 0.5 * (1.0 + cos(im * scale) );
- for (j = -j_data_start; j < ny2 - j_data_start; j++) {
- datac[ij_data(il1,j)] *= cos_wt;
- datac[ij_data(ir2,j)] *= cos_wt;
- }
- }
-
- /* Now, renormalize the variance: COMMENTED OUT--STUPID IDEA
-
- data2_var = 0.0;
- for (i = 0; i < ndatac; i+= 2) data2_var += (datac[i] * datac[i]);
-
- data2_var = sqrt(data2_var / (ndatac/2 - 1));
- scale = data_var / data2_var;
- for (i = 0; i < ndatac; i+= 2) datac[i] *= scale;
-
- if (gmtdefs.verbose) fprintf (stderr, "grdfft: Cosine tapering rescaled data by %.8lg\n", scale); */
- return(0);
- }
-
- double kx(k)
- int k;
- {
- /* Return the value of kx given k,
- where kx = 2 pi / lambda x,
- and k refers to the position
- in the datac array, datac[k]. */
-
- int ii;
-
- ii = ((int)(k/2))%nx2;
- if (ii > nx2/2) ii -= nx2;
- return(ii * delta_kx);
- }
-
- double ky(k)
- int k;
- {
- /* Return the value of ky given k,
- where ky = 2 pi / lambda y,
- and k refers to the position
- in the datac array, datac[k]. */
-
- int jj;
-
- jj = ((int)(k/2))/nx2;
- if (jj > ny2/2) jj -= ny2;
- return(jj * delta_ky);
- }
-
- double modk(k)
- int k;
- {
- /* Return the value of sqrt(kx*kx + ky*ky),
- given k, where k is array position. */
-
- return (hypot (kx(k), ky(k)));
- }
-
- int do_differentiate (par)
- double *par;
- {
- int k;
- double scale, fact;
-
- /* Differentiate in frequency domain by multiplying by kr [scale optional] */
-
- scale = (*par != 0.0) ? *par : 1.0;
- datac[0] = datac[1] = 0.0;
- for (k = 2; k < ndatac; k+= 2) {
- fact = scale * modk(k);
- datac[k] *= fact;
- datac[k+1] *= fact;
- }
- }
-
- int do_integrate (par)
- double *par;
- {
- /* Integrate in frequency domain by deviding by kr [scale optional] */
- int k;
- double fact, scale;
-
- scale = (*par != 0.0) ? *par : 1.0;
- datac[0] = datac[1] = 0.0;
- for (k = 2; k < ndatac; k+= 2) {
- fact = 1.0 / (scale * modk(k) );
- datac[k] *= fact;
- datac[k+1] *= fact;
- }
- }
-
- int do_continuation (zlevel)
- double *zlevel;
- {
- int k;
- double tmp;
-
- /* If z is positive, the field will be upward continued using exp[- k z]. */
-
- for (k = 2; k < ndatac; k+= 2) {
- tmp = exp (-(*zlevel) * modk(k) );
- datac[k] *= tmp;
- datac[k+1] *= tmp;
- }
- }
-
- int do_azimuthal_derivative (azim)
- double *azim;
- {
- int k;
- float tempr, tempi, fact;
- double cos_azim, sin_azim;
-
- cos_azim = cos ((*azim) * D2R);
- sin_azim = sin ((*azim) * D2R);
-
- datac[0] = datac[1] = 0.0;
- for (k = 2; k < ndatac; k+= 2) {
- fact = sin_azim * kx(k) + cos_azim * ky(k);
- tempr = -(datac[k+1] * fact);
- tempi = (datac[k] * fact);
- datac[k] = tempr;
- datac[k+1] = tempi;
- }
- }
-
- int do_isostasy (par)
- double *par;
- {
-
- /* Do the isostatic response function convolution in the Freq domain.
- All units assumed to be in SI (that is kx, ky, modk wavenumbers in m**-1,
- densities in kg/m**3, Te in m, etc.
- rw, the water density, is used to set the Airy ratio and the restoring
- force on the plate (rm - ri)*gravity if ri = rw; so use zero for topo in air. */
- int k;
- double airy_ratio, rigidity_d, d_over_restoring_force, mk, k2, k4, transfer_fn;
-
- double te; /* Elastic thickness, SI units (m) */
- double rl; /* Load density, SI units */
- double rm; /* Mantle density, SI units */
- double rw; /* Water density, SI units */
- double ri; /* Infill density, SI units */
-
- /* Kernighan and Ritchie 2nd edition ANSI C says these should be const double, but
- my lint won't recognise that type: */
-
- double youngs_modulus = 1.0e11; /* Pascal = Nt/m**2 */
- double normal_gravity = 9.80619203; /* m/s**2 */
- double poissons_ratio = 0.25;
-
- te = par[0]; rl = par[1]; rm = par[2]; rw = par[3]; ri = par[4];
- rigidity_d = (youngs_modulus * te * te * te) / (12.0 * (1.0 - poissons_ratio * poissons_ratio));
- d_over_restoring_force = rigidity_d / ( (rm - ri) * normal_gravity);
- airy_ratio = -(rl - rw)/(rm - ri);
-
- if (te == 0.0) { /* Airy isostasy; scale global variable scale_out and return */
- scale_out *= airy_ratio;
- return;
- }
-
- for (k = 0; k < ndatac; k+= 2) {
- mk = modk(k);
- k2 = mk * mk;
- k4 = k2 * k2;
- transfer_fn = airy_ratio / ( (d_over_restoring_force * k4) + 1.0);
- datac[k] *= transfer_fn;
- datac[k+1] *= transfer_fn;
- }
- }
-
- int do_filter()
- {
- int k;
- double weight, f_wt();
- for (k = 0; k < ndatac; k += 2) {
- weight = f_wt(k);
- datac[k] *= weight;
- datac[k+1] *= weight;
- }
- }
-
- double f_wt(k)
- int k;
- {
- double freq, return_value = 1.0;
- int j;
-
- /* Always return immediately when zero weight encountered. */
-
- for (j = 0; j < 3; j++) {
- if (!(f_info.do_this[j])) continue;
- switch (j) {
- case 0:
- freq = modk(k);
- break;
- case 1:
- freq = kx(k);
- break;
- case 2:
- freq = ky(k);
- break;
- }
- if (freq <= f_info.lc[j] || freq >= f_info.hc[j])
- /* In fully cut range. Weight is zero. */
- return(0.0);
- else if (freq > f_info.lc[j] && freq < f_info.lp[j])
- return_value *= 0.5 * (1.0 + cos (M_PI * (freq - f_info.lp[j]) * f_info.ltaper[j]));
- else if (freq > f_info.hp[j] && freq < f_info.hc[j])
- return_value *= 0.5 * (1.0 + cos (M_PI * (freq - f_info.hp[j]) * f_info.htaper[j]));
- /* Else freq is in the fully passed range, so weight is multiplied by 1.0 */
- }
-
- /* Get here when all weights have been multiplied on return_value: */
-
- return(return_value);
- }
-
- int parse_f_string(c)
- char *c;
- {
- int i, j, n_tokens, descending;
- double fourvals[4];
- char line[80], *p;
-
- strcpy(line, c);
- i = j = 0; /* j is Filter type: r=0, x=1, y=2 */
-
- if (line[i] == 'x') {
- j = 1;
- i++;
- }
- else if (line[i] == 'y') {
- j = 2;
- i++;
- }
-
- f_info.do_this[j] = TRUE;
-
- n_tokens = 0;
- p = strtok(&line[i],"/");
- while (p) {
- if (n_tokens > 3) {
- fprintf(stderr,"Too many slashes.\n");
- return(TRUE);
- }
- if(p[0] == '-') {
- fourvals[n_tokens] = -1.0;
- }
- else {
- if ((sscanf(p, "%lf", &fourvals[n_tokens])) != 1) {
- fprintf(stderr,"grdfft: Cannot read token %d.\n", n_tokens);
- return(TRUE);
- }
- }
- n_tokens++;
- p = strtok(CNULL, "/");
- }
-
- if (n_tokens != 4) {
- fprintf(stderr,"Cannot find 4 tokens separated by slashes.\n");
- return(TRUE);
- }
-
- descending = TRUE;
- for (i = 1; i < 4; i++) {
- if (fourvals[i] == -1.0 || fourvals[i-1] == -1.0) continue;
- if (fourvals[i] > fourvals[i-1]) descending = FALSE;
- }
- if (!(descending)) {
- fprintf(stderr,"Wavelengths are not in descending order.\n");
- return(TRUE);
- }
- if ( (fourvals[0] * fourvals[1]) < 0.0 || (fourvals[2] * fourvals[3]) < 0.0) {
- fprintf(stderr,"Pass/Cut specification error.\n");
- return(TRUE);
- }
-
- /* Now everything is OK */
-
- if (fourvals[0] >= 0.0 || fourvals[1] >= 0.0) { /* Lower end values are set */
- f_info.lc[j] = (2.0 * M_PI)/fourvals[0];
- f_info.lp[j] = (2.0 * M_PI)/fourvals[1];
- if (fourvals[0] != fourvals[1]) f_info.ltaper[j] = 1.0/(f_info.lc[j] - f_info.lp[j]);
- }
-
- if (fourvals[2] >= 0.0 || fourvals[3] >= 0.0) { /* Higher end values are set */
- f_info.hp[j] = (2.0 * M_PI)/fourvals[2];
- f_info.hc[j] = (2.0 * M_PI)/fourvals[3];
- if (fourvals[2] != fourvals[3]) f_info.htaper[j] = 1.0/(f_info.hc[j] - f_info.hp[j]);
- }
-
- return(FALSE);
- }
-
- int do_spectrum(par, give_wavelength)
- double *par;
- int give_wavelength;
- {
- /* This is modeled on the 1-D case, using the following ideas:
- * In 1-D, we ensemble average over samples of length L =
- * n * dt. This gives n/2 power spectral estimates, at
- * frequencies i/L, where i = 1, n/2. If we have a total
- * data set of ndata, we can make nest=ndata/n independent
- * estimates of the power. Our standard error is then
- * 1/sqrt(nest).
- * In making 1-D estimates from 2-D data, we may choose
- * n and L from nx2 or ny2 and delta_kx, delta_ky as
- * appropriate. In this routine, we are giving the sum over
- * all frequencies in the other dimension; that is, an
- * approximation of the integral.
- */
-
- int k, nk, nused, ifreq;
- double delta_k, r_delta_k, freq, *power, eps_pow;
- PFD get_k;
- char format[64];
-
- if (*par > 0.0) {
- /* X spectrum desired */
- delta_k = delta_kx;
- nk = nx2/2;
- get_k = (PFD)kx;
- }
- else if (*par < 0.0) {
- /* Y spectrum desired */
- delta_k = delta_ky;
- nk = ny2/2;
- get_k = (PFD)ky;
- }
- else {
- /* R spectrum desired */
- if (delta_kx < delta_ky) {
- delta_k = delta_kx;
- nk = nx2/2;
- }
- else {
- delta_k = delta_ky;
- nk = ny2/2;
- }
- get_k = (PFD)modk;
- }
-
- /* Get an array for summing stuff: */
- power = (double *) memory(CNULL, nk, sizeof(double), "grdfft");
- for (k = 0; k < nk; k++) power[k] = 0.0;
-
- /* Loop over it all, summing and storing, checking range for r: */
-
- r_delta_k = 1.0 / delta_k;
-
- for (nused = 0, k = 2; k < ndatac; k+= 2) {
- freq = (*get_k)(k);
- ifreq = irint(fabs(freq)*r_delta_k) - 1;
- if (ifreq < 0) ifreq = 0; /* Might happen when doing r spectrum */
- if (ifreq >= nk) continue; /* Might happen when doing r spectrum */
- power[ifreq] += (datac[k]*datac[k] + datac[k+1]*datac[k+1]);
- nused++;
- }
-
- /* Now get here when array is summed. */
- eps_pow = 1.0/sqrt((double)nused/(double)nk);
- delta_k /= (2.0*M_PI); /* Write out frequency, not wavenumber */
- sprintf (format, "%s\t%s\t%s\n\0", gmtdefs.d_format, gmtdefs.d_format, gmtdefs.d_format);
- for (k = 0; k < nk; k++) {
- freq = (k + 1) * delta_k;
- if (give_wavelength) freq = 1.0/freq;
- printf(format, freq, power[k], eps_pow * power[k]);
- }
- return;
- }
-
- void fourt_stats(nx, ny, f, r, s, t)
- int nx, ny, f[], *s;
- double *r, *t;
- {
- /* Find the proportional run time, t, and rms relative error, r,
- * of a Fourier transform of size nx,ny. Also gives s, the size
- * of the workspace that will be needed by the transform.
- * To use this routine for a 1-D transform, set ny = 1.
- *
- * This is all based on the comments in Norman Brenner's code
- * FOURT, from which our C codes are translated.
- * Brenner says:
- * r = 3 * pow(2, -FSIGNIF) * sum{ pow(prime_factors, 1.5) }
- * where FSIGNIF is the smallest bit in the floating point fraction.
- *
- * Let m = largest prime factor in the list of factors.
- * Let p = product of all primes which appear an odd number of
- * times in the list of prime factors. Then the worksize needed
- * s = max(m,p). However, we know that if n is radix 2, then no
- * work is required; yet this formula would say we need a worksize
- * of at least 2. So I will return s = 0 when max(m,p) = 2.
- *
- * I have two different versions of the comments in FOURT, with
- * different formulae for t. The simple formula says
- * t = n * (sum of prime factors of n).
- * The more complicated formula gives coefficients in microsecs
- * on a cdc3300 (ancient history, but perhaps proportional):
- * t = 3000 + n*(500 + 43*s2 + 68*sf + 320*nf),
- * where s2 is the sum of all factors of 2, sf is the sum of all
- * factors greater than 2, and nf is the number of factors != 2.
- * We know that factors of 2 are very good to have, and indeed,
- * Brenner's code calls different routines depending on whether
- * the transform is of size 2 or not, so I think that the second
- * formula is more correct, using proportions of 43:68 for 2 and
- * non-2 factors. So I will use the more complicated formula.
- * However, I realize that the actual numbers are wrong for today's
- * architectures, and the relative proportions may be wrong as well.
- *
- * W. H. F. Smith, 26 February 1992.
- * */
-
- int n_factors, i, ntotal, sum2, sumnot2, nnot2;
- int nonsymx, nonsymy, nonsym, storage;
- double err_scale, sig_bits = FSIGNIF;
-
-
- /* Find workspace needed. First find non_symmetric factors in nx, ny */
- n_factors = get_prime_factors(nx, f);
- nonsymx = get_non_symmetric_f(f, n_factors);
- n_factors = get_prime_factors(ny, f);
- nonsymy = get_non_symmetric_f(f, n_factors);
- nonsym = MAX(nonsymx, nonsymy);
-
- /* Now get factors of ntotal */
- ntotal = nx * ny;
- n_factors = get_prime_factors(ntotal, f);
- storage = MAX(nonsym, f[n_factors - 1]);
- if (storage == 2)
- *s = 0;
- else
- *s = storage;
-
- /* Now find time and error estimates: */
-
- err_scale = 0.0;
- sum2 = 0;
- sumnot2 = 0;
- nnot2 = 0;
- for(i = 0; i < n_factors; i++) {
- if (f[i] == 2)
- sum2 += f[i];
- else {
- sumnot2 += f[i];
- nnot2++;
- }
- err_scale += pow((double)f[i], 1.5);
- }
- *t = 1.0e-06*(3000.0 + ntotal * (500.0 + 43.0*sum2 + 68.0*sumnot2 + 320.0*nnot2));
- *r = err_scale * 3.0 * pow(2.0, -sig_bits);
- return;
- }
-
- int get_non_symmetric_f(f, n)
- int f[], n;
- {
- /* Return the product of the non-symmetric factors in f[] */
- int i = 0, j = 1, retval = 1;
-
- if (n == 1) return(f[0]);
-
- while(i < n) {
- while(j < n && f[j] == f[i]) j++;
- if ((j-i)%2) retval *= f[i];
- i = j;
- j = i + 1;
- }
- if (retval == 1) retval = 0; /* There are no non-sym factors */
- return(retval);
- }
-
- void suggest_fft(nx, ny, fft_sug, do_print)
- int nx, ny, do_print;
- struct FFT_SUGGESTION fft_sug[];
- {
- int f[64], xstop, ystop;
- int nx_best_t, ny_best_t;
- int nx_best_e, ny_best_e;
- int nx_best_s, ny_best_s;
- int nxg, nyg; /* Guessed by this routine */
- int nx2, ny2, nx3, ny3, nx5, ny5; /* For powers */
- double current_time, best_time, given_time, s_time, e_time;
- int current_space, best_space, given_space, e_space, t_space;
- double current_err, best_err, given_err, s_err, t_err;
- void fourt_stats();
-
-
- fourt_stats(nx, ny, f, &given_err, &given_space, &given_time);
- given_space += nx*ny;
- given_space *= 8;
- if (do_print) fprintf(stderr,"grdfft: Data dimension\t%d %d\ttime factor %.8lg\trms error %.8le\tbytes %d\n",
- nx, ny, given_time, given_err, given_space);
-
- best_err = s_err = t_err = given_err;
- best_time = s_time = e_time = given_time;
- best_space = t_space = e_space = given_space;
- nx_best_e = nx_best_t = nx_best_s = nx;
- ny_best_e = ny_best_t = ny_best_s = ny;
-
- xstop = 2 * nx;
- ystop = 2 * ny;
-
- for (nx2 = 2; nx2 <= xstop; nx2 *= 2) {
- for (nx3 = 1; nx3 <= xstop; nx3 *= 3) {
- for (nx5 = 1; nx5 <= xstop; nx5 *= 5) {
- nxg = nx2 * nx3 * nx5;
- if (nxg < nx || nxg > xstop) continue;
-
- for (ny2 = 2; ny2 <= ystop; ny2 *= 2) {
- for (ny3 = 1; ny3 <= ystop; ny3 *= 3) {
- for (ny5 = 1; ny5 <= ystop; ny5 *= 5) {
- nyg = ny2 * ny3 * ny5;
- if (nyg < ny || nyg > ystop) continue;
-
- fourt_stats(nxg, nyg, f, ¤t_err, ¤t_space, ¤t_time);
- current_space += nxg*nyg;
- current_space *= 8;
- if (current_err < best_err) {
- best_err = current_err;
- nx_best_e = nxg;
- ny_best_e = nyg;
- e_time = current_time;
- e_space = current_space;
- }
- if (current_time < best_time) {
- best_time = current_time;
- nx_best_t = nxg;
- ny_best_t = nyg;
- t_err = current_err;
- t_space = current_space;
- }
- if (current_space < best_space) {
- best_space = current_space;
- nx_best_s = nxg;
- ny_best_s = nyg;
- s_time = current_time;
- s_err = current_err;
- }
-
- }
- }
- }
-
- }
- }
- }
-
- if (do_print) {
- fprintf(stderr,"grdfft: Highest speed\t%d %d\ttime factor %.8lg\trms error %.8le\tbytes %d\n",
- nx_best_t, ny_best_t, best_time, t_err, t_space);
- fprintf(stderr,"grdfft: Most accurate\t%d %d\ttime factor %.8lg\trms error %.8le\tbytes %d\n",
- nx_best_e, ny_best_e, e_time, best_err, e_space);
- fprintf(stderr,"grdfft: Least storage\t%d %d\ttime factor %.8lg\trms error %.8le\tbytes %d\n",
- nx_best_s, ny_best_s, s_time, s_err, best_space);
- }
- /* Fastest solution: */
- fft_sug[0].nx = nx_best_t;
- fft_sug[0].ny = ny_best_t;
- fft_sug[0].worksize = (t_space/8) - (nx_best_t * ny_best_t);
- fft_sug[0].totalbytes = t_space;
- fft_sug[0].run_time = best_time;
- fft_sug[0].rms_rel_err = t_err;
- /* Most accurate solution: */
- fft_sug[1].nx = nx_best_e;
- fft_sug[1].ny = ny_best_e;
- fft_sug[1].worksize = (e_space/8) - (nx_best_e * ny_best_e);
- fft_sug[1].totalbytes = e_space;
- fft_sug[1].run_time = e_time;
- fft_sug[1].rms_rel_err = best_err;
- /* Least storage solution: */
- fft_sug[2].nx = nx_best_s;
- fft_sug[2].ny = ny_best_s;
- fft_sug[2].worksize = (best_space/8) - (nx_best_s * ny_best_s);
- fft_sug[2].totalbytes = best_space;
- fft_sug[2].run_time = s_time;
- fft_sug[2].rms_rel_err = s_err;
-
- return;
- }
-
- int get_prime_factors(n, f)
- int n, f[];
- {
- /* Fills the integer array f with the prime factors of n.
- * Returns the number of locations filled in f, which is
- * one if n is prime.
- *
- * f[] should have been malloc'ed to enough space before
- * calling prime_factors(). We can be certain that f[32]
- * is enough space, for if n fits in a long, then n < 2**32,
- * and so it must have fewer than 32 prime factors. I think
- * that in general, ceil(log2((double)n)) is enough storage
- * space for f[].
- *
- * Tries 2,3,5 explicitly; then alternately adds 2 or 4
- * to the previously tried factor to obtain the next trial
- * factor. This is done with the variable two_four_toggle.
- * With this method we try 7,11,13,17,19,23,25,29,31,35,...
- * up to a maximum of sqrt(n). This shortened list results
- * in 1/3 fewer divisions than if we simply tried all integers
- * between 5 and sqrt(n). We can reduce the size of the list
- * of trials by an additional 20% by removing the multiples
- * of 5, which are equal to 30m +/- 5, where m >= 1. Starting
- * from 25, these are found by alternately adding 10 or 20.
- * To do this, we use the variable ten_twenty_toggle.
- *
- * W. H. F. Smith, 26 Feb 1992, after D.E. Knuth, vol. II */
-
- int current_factor; /* The factor currently being tried */
- int max_factor; /* Don't try any factors bigger than this */
- int n_factors = 0; /* Returned; one if n is prime */
- int two_four_toggle = 0; /* Used to add 2 or 4 to get next trial factor */
- int ten_twenty_toggle = 0; /* Used to add 10 or 20 to skip_five */
- int skip_five = 25; /* Used to skip multiples of 5 in the list */
- int m; /* Used to keep a working copy of n */
-
-
- /* Initialize m and max_factor */
- m = abs(n);
- if (m < 2) return(0);
- max_factor = floor(sqrt((double)m));
-
- /* First find the 2s */
- current_factor = 2;
- while(!(m%current_factor)) {
- m /= current_factor;
- f[n_factors] = current_factor;
- n_factors++;
- }
- if (m == 1) return(n_factors);
-
- /* Next find the 3s */
- current_factor = 3;
- while(!(m%current_factor)) {
- m /= current_factor;
- f[n_factors] = current_factor;
- n_factors++;
- }
- if (m == 1) return(n_factors);
-
- /* Next find the 5s */
- current_factor = 5;
- while(!(m%current_factor)) {
- m /= current_factor;
- f[n_factors] = current_factor;
- n_factors++;
- }
- if (m == 1) return(n_factors);
-
- /* Now try all the rest */
-
- while (m > 1 && current_factor <= max_factor) {
-
- /* Current factor is either 2 or 4 more than previous value */
-
- if (two_four_toggle) {
- current_factor += 4;
- two_four_toggle = 0;
- }
- else {
- current_factor += 2;
- two_four_toggle = 1;
- }
-
- /* If current factor is a multiple of 5, skip it. But first,
- set next value of skip_five according to 10/20 toggle: */
-
- if (current_factor == skip_five) {
- if (ten_twenty_toggle) {
- skip_five += 20;
- ten_twenty_toggle = 0;
- }
- else {
- skip_five += 10;
- ten_twenty_toggle = 1;
- }
- continue;
- }
-
- /* Get here when current_factor is not a multiple of 2,3 or 5: */
-
- while(!(m%current_factor)) {
- m /= current_factor;
- f[n_factors] = current_factor;
- n_factors++;
- }
- }
-
- /* Get here when all factors up to floor(sqrt(n)) have been tried. */
-
- if (m > 1) {
- /* m is an additional prime factor of n */
- f[n_factors] = m;
- n_factors++;
- }
- return (n_factors);
- }
-
-