bool FastFourierTransform::computeFFT(double *data){
    
    if( !initialized || data == NULL ){
        return false;
    }
    
    //Window the input data
    if( !windowData(data) ){
        return false;
    }
    
    //Perform the FFT
    realFFT(data, fftReal, fftImag);
	
    averagePower = 0;
    
    for(unsigned int i = 0; i<windowSize/2; i++){
        
        if( computeMagnitude ){
            power[i] = fftReal[i]*fftReal[i] + fftImag[i]*fftImag[i];
            averagePower += power[i];
            magnitude[i] = 2.0*sqrt( power[i] );
        }
        
        if( computePhase ){
            phase[i] = atan2(fftImag[i],fftReal[i]);
        }
    }

    //Compute the average power
    averagePower = averagePower / (double)(windowSize/2);
    
    return true;
}
Example #2
0
void track_through_ztransverse(double **part, long np, ZTRANSVERSE *ztransverse, double Po,
                               RUN *run, long i_pass, CHARGE *charge
                               )
{
  static double *posItime[2] = {NULL, NULL};     /* array for particle density times x, y*/
  static double *posIfreq;                       /* array for FFT of particle density times x or y*/
  static double *Vtime = NULL;           /* array for voltage acting on each bin */
  static long max_n_bins = 0;
  static long *pbin = NULL;              /* array to record which bin each particle is in */
  static double *time = NULL;            /* array to record arrival time of each particle */
  static double *pz = NULL;
  static long max_np = 0;
  double *Vfreq, *iZ;
#if USE_MPI
  long i;
#endif
  long ib, nb, n_binned, nfreq, iReal, iImag, plane, first;
  double factor, tmin, tmax, tmean, dt, userFactor[2], rampFactor=1;
  static long not_first_call = -1;
  long ip, ip1, ip2, bunches, bunch, npb, i_pass0;
  long bucketEnd[MAX_BUCKETS];
#if USE_MPI
  float *buffer_send, *buffer_recv;
#endif
#if defined(DEBUG)
  FILE *fp;
#endif
  i_pass0 = i_pass;
  if ((i_pass -= ztransverse->startOnPass)<0)
    return;
  
  if (i_pass>=(ztransverse->rampPasses-1))
    rampFactor = 1;
  else
    rampFactor = (i_pass+1.0)/ztransverse->rampPasses;
  
  not_first_call += 1;

#if (!USE_MPI)
  if (np>max_np) {
    pbin = trealloc(pbin, sizeof(*pbin)*(max_np=np));
    time = trealloc(time, sizeof(*time)*max_np);
    pz = trealloc(pz, sizeof(*pz)*max_np);
  }
#else
    if (USE_MPI) {
      long np_total;
      if (isSlave) {
	MPI_Allreduce(&np, &np_total, 1, MPI_LONG, MPI_SUM, workers);
	if (np_total>max_np) { 
	  /* if the total number of particles is increased, we do reallocation for every CPU */
	  pbin = trealloc(pbin, sizeof(*pbin)*(max_np=np));
	  time = trealloc(time, sizeof(*time)*max_np);
	  pz = trealloc(pz, sizeof(*pz)*max_np);
	  max_np = np_total; /* max_np should be the sum across all the processors */
	}
      }
    } 
#endif
  
  if ((part[0][6]-floor(part[0][6]))!=0) {
    /* This is a kludgey way to determine that particles have been assigned to buckets */
    printf("Bunched beam detected\n"); fflush(stdout);
#if USE_MPI
    if (n_processors!=1) {
      printf("Error (ZTRANSVERSE): must have bunch_frequency=0 for parallel mode.\n");
      MPI_Barrier(MPI_COMM_WORLD); /* Make sure the information can be printed before aborting */
      MPI_Abort(MPI_COMM_WORLD, 2);
    }
#endif
    /* Start by sorting in bucket order */
    qsort(part[0], np, COORDINATES_PER_PARTICLE*sizeof(double), comp_BucketNumbers);
    /* Find the end of the buckets in the particle list */
    bunches = 0;
    for (ip=1; ip<np; ip++) {
      if ((part[ip-1][6]-floor(part[ip-1][6]))!=(part[ip][6]-floor(part[ip][6]))) {
        /* printf("Bucket %ld ends with ip=%ld\n", bunches, ip-1); fflush(stdout); */
        bucketEnd[bunches++] = ip-1;
        if (bunches>=MAX_BUCKETS) {
            bombElegant("Error (wake): maximum number of buckets was exceeded", NULL);
          }
      }
    }
    bucketEnd[bunches++] = np-1;
  } else {
    bunches = 1;
    bucketEnd[0] = np-1;
  }
  /* printf("Bucket %ld ends with ip=%ld\n", bunches, bucketEnd[bunches-1]); fflush(stdout); */

  ip2 = -1;
  for (bunch=0; bunch<bunches; bunch++) {
    ip1 = ip2+1;
    ip2 = bucketEnd[bunch];
    npb = ip2-ip1+1;
    /* printf("Processing bunch %ld with %ld particles\n", bunch, npb); fflush(stdout); */
    /* Compute time coordinate of each particle */
    tmean = computeTimeCoordinates(time+ip1, Po, part+ip1, npb);
    find_min_max(&tmin, &tmax, time+ip1, npb);
#if USE_MPI
    find_global_min_max(&tmin, &tmax, np, workers);      
#endif
    if (bunch==0) {
      /* use np here since we need to compute the macroparticle charge */
      set_up_ztransverse(ztransverse, run, i_pass, np, charge, tmax-tmin);
    }
    nb = ztransverse->n_bins;
    dt = ztransverse->bin_size;
    tmin -= dt;
    tmax -= dt;
    if ((tmax-tmin)*2>nb*dt) {
      TRACKING_CONTEXT tcontext;
      getTrackingContext(&tcontext);
      fprintf(stderr, "%s %s: Time span of bunch (%le s) is more than half the total time span (%le s).\n",
              entity_name[tcontext.elementType],
              tcontext.elementName,
              tmax-tmin, nb*dt);
      fprintf(stderr, "If using broad-band impedance, you should increase the number of bins and rerun.\n");
      fprintf(stderr, "If using file-based impedance, you should increase the number of data points or decrease the frequency resolution.\n");
      exitElegant(1);
    }

    if (nb>max_n_bins) {
      posItime[0] = trealloc(posItime[0], 2*sizeof(**posItime)*(max_n_bins=nb));
      posItime[1] = trealloc(posItime[1], 2*sizeof(**posItime)*(max_n_bins=nb));
      posIfreq = trealloc(posIfreq, 2*sizeof(*posIfreq)*(max_n_bins=nb));
      Vtime = trealloc(Vtime, 2*sizeof(*Vtime)*(max_n_bins+1));
    }

    for (ib=0; ib<nb; ib++)
      posItime[0][2*ib] = posItime[0][2*ib+1] = 
        posItime[1][2*ib] = posItime[1][2*ib+1] = 0;

    /* make arrays of I(t)*x and I(t)*y */
    n_binned = binTransverseTimeDistribution(posItime, pz, pbin, tmin, dt, nb, 
                                             time+ip1, part+ip1, Po, npb,
                                             ztransverse->dx, ztransverse->dy,
                                             ztransverse->xDriveExponent, ztransverse->yDriveExponent);
#if (!USE_MPI)
    if (n_binned!=npb) {
      fprintf(stdout, "Warning: only %ld of %ld particles were binned (ZTRANSVERSE)!\n", n_binned, npb);
      if (!not_first_call) {
        fprintf(stdout, "*** This may produce unphysical results.  Your wake needs smaller frequency\n");
        fprintf(stdout, "    spacing to cover a longer time span.\n");
      }
      fflush(stdout);
    }  
#else
    if (USE_MPI) {
      int all_binned, result = 1;
      if (isSlave)
        result = ((n_binned==np) ? 1 : 0);
      
      MPI_Allreduce(&result, &all_binned, 1, MPI_INT, MPI_LAND, workers);
      if (!all_binned) {
	if (myid==1) {  
	  /* This warning will be given only if the flag MPI_DEBUG is defined for the Pelegant */ 
	  fprintf(stdout, "warning: Not all of %ld particles were binned (WAKE)\n", np);
	  fprintf(stdout, "consider setting n_bins=0 in WAKE definition to invoke autoscaling\n");
	  fflush(stdout); 
	}
      }
    }
#endif

    userFactor[0] = ztransverse->factor*ztransverse->xfactor*rampFactor;
    userFactor[1] = ztransverse->factor*ztransverse->yfactor*rampFactor;

    first = 1;
    for (plane=0; plane<2; plane++) {
#if USE_MPI
      /* This could be good for some advanced network structures */
      /*
        if (isSlave) {
        double buffer[nb];
        MPI_Allreduce(posItime[plane], buffer, nb, MPI_DOUBLE, MPI_SUM, workers);
        memcpy(posItime[plane], buffer, sizeof(double)*nb);
        }
        */
      if (isSlave) {
        buffer_send = malloc(sizeof(float) * nb);
        buffer_recv = malloc(sizeof(float) * nb);
        for (i=0; i<nb; i++)
          buffer_send[i] = posItime[plane][i];
        MPI_Reduce(buffer_send, buffer_recv, nb, MPI_FLOAT, MPI_SUM, 1, workers);
        MPI_Bcast(buffer_recv, nb, MPI_FLOAT, 1, workers);
        for (i=0; i<nb; i++)
          posItime[plane][i] = buffer_recv[i];
        free(buffer_send);
        free(buffer_recv);
      }

#endif
      if (userFactor[plane]==0) {
        for (ib=0; ib<nb; ib++)
          Vtime[ib] = 0;
      } else {
        if (ztransverse->smoothing)
          SavitzyGolaySmooth(posItime[plane], nb, ztransverse->SGOrder,
                             ztransverse->SGHalfWidth, ztransverse->SGHalfWidth, 0);
        
        /* Take the FFT of (x*I)(t) to get (x*I)(f) */
        memcpy(posIfreq, posItime[plane], 2*nb*sizeof(*posIfreq));
        realFFT(posIfreq, nb, 0);
        
        /* Compute V(f) = i*Z(f)*(x*I)(f), putting in a factor 
         * to normalize the current waveform
         */
        Vfreq = Vtime;
        factor = ztransverse->macroParticleCharge*particleRelSign/dt*userFactor[plane];
        iZ = ztransverse->iZ[plane];
        Vfreq[0] = posIfreq[0]*iZ[0]*factor;
        nfreq = nb/2 + 1;
        if (nb%2==0)
          /* Nyquist term */
          Vfreq[nb-1] = posIfreq[nb-1]*iZ[nb-1]*factor;
        for (ib=1; ib<nfreq-1; ib++) {
          iImag = (iReal = 2*ib-1)+1;
          /* The signs are chosen here to get agreement with TRFMODE.
             In particular, test particles following closely behind the 
             drive particle get defocused.
             */
          Vfreq[iReal] =  (posIfreq[iReal]*iZ[iImag] + posIfreq[iImag]*iZ[iReal])*factor; 
          Vfreq[iImag] = -(posIfreq[iReal]*iZ[iReal] - posIfreq[iImag]*iZ[iImag])*factor;
        }
        
        /* Compute inverse FFT of V(f) to get V(t) */
        realFFT(Vfreq, nb, INVERSE_FFT);
        Vtime = Vfreq;
        
        /* change particle transverse momenta to reflect voltage in relevant bin */
        applyTransverseWakeKicks(part+ip1, time+ip1, pz, pbin, npb, 
                                 Po, plane, 
                                 Vtime, nb, tmin, dt, ztransverse->interpolate,
                                 plane==0?ztransverse->xProbeExponent:ztransverse->yProbeExponent);
      }

      if (ztransverse->SDDS_wake_initialized && ztransverse->wakes) {
        /* wake potential output */
        factor = ztransverse->macroParticleCharge*particleRelSign/dt;
        if ((ztransverse->wake_interval<=0 || ((i_pass0-ztransverse->wake_start)%ztransverse->wake_interval)==0) &&
            i_pass0>=ztransverse->wake_start && i_pass0<=ztransverse->wake_end) {
          if (first && !SDDS_StartTable(&ztransverse->SDDS_wake, nb)) {
            SDDS_SetError("Problem starting SDDS table for wake output (track_through_ztransverse)");
            SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors|SDDS_EXIT_PrintErrors);
          }
          for (ib=0; ib<nb; ib++) {
            if (!SDDS_SetRowValues(&ztransverse->SDDS_wake, SDDS_SET_BY_INDEX|SDDS_PASS_BY_VALUE, ib,
                                   0, ib*dt, 
                                   1+plane*2, posItime[plane][ib]*factor,  
                                   2+plane*2, Vtime[ib], -1)) {
              SDDS_SetError("Problem setting rows of SDDS table for wake output (track_through_ztransverse)");
              SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors|SDDS_EXIT_PrintErrors);
            }
          }
          if (!SDDS_SetParameters(&ztransverse->SDDS_wake, SDDS_SET_BY_NAME|SDDS_PASS_BY_VALUE,
                                  "Pass", i_pass0, "q", ztransverse->macroParticleCharge*particleRelSign*np, NULL)) {
            SDDS_SetError("Problem setting parameters of SDDS table for wake output (track_through_ztransverse)");
            SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors|SDDS_EXIT_PrintErrors);
          }
          if (ztransverse->broad_band) {
            if (!SDDS_SetParameters(&ztransverse->SDDS_wake, SDDS_SET_BY_NAME|SDDS_PASS_BY_VALUE,
                                    "Rs", ztransverse->Rs, "fo", ztransverse->freq, 
                                    "Deltaf", ztransverse->bin_size, NULL)) {
              SDDS_SetError("Problem setting parameters of SDDS table for wake output (track_through_ztransverse)");
              SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors|SDDS_EXIT_PrintErrors);
            }
          }
          if (!first) {
            if (!SDDS_WriteTable(&ztransverse->SDDS_wake)) {
              SDDS_SetError("Problem writing SDDS table for wake output (track_through_ztransverse)");
              SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors|SDDS_EXIT_PrintErrors);
            }
            if (!inhibitFileSync)
              SDDS_DoFSync(&ztransverse->SDDS_wake);
          }
        }
      }
      first = 0;
    }
  }
  
#if defined(MIMIMIZE_MEMORY)
  free(posItime[0]);
  free(posItime[1]);
  free(posIfreq);
  free(Vtime);
  free(pbin);
  free(time);
  free(pz);
  posItime[0] = posItime[1] = Vtime = time = pz = posIfreq = NULL;
  pbin = NULL;
  max_n_bins = max_np = 0 ;
#endif

}