Beispiel #1
0
ConstantDamping::ConstantDamping(const Inputs& sp, MPIdata& mpi, fftwPlans& fft) :
dampFac(0.5),
equations_name("ConstantDamping"),
numMF_(1), numLin_(4),
f_noise_(sp.f_noise), nu_(sp.nu), eta_(sp.eta),
q_(sp.q),
dont_drive_ky0_modes_(0),// If true, no driving ky=0 modes
Model(sp.NZ, sp.NXY , sp.L), // Dimensions - stored in base
mpi_(mpi), // MPI data
fft_(fft) // FFT data
{
    // Setup MPI
    mpi_.Split_NXY_Grid( Dimxy_full() ); // Work out MPI splitting
    // Assign K data
    K = new Kdata(this, &mpi_); // Stores all the K data
    // Fourier transform plans
    fft_.calculatePlans( N(2),NZ() );
    
    // Random generator
    mt_ = boost::random::mt19937(1.0 + mpi_.my_n_v());  // Seed is 1.0, could change
    ndist_ = boost::random::normal_distribution<double>(0,f_noise_/sqrt(2)); // Normal distribution, standard deviation f_noise_ (factor 2 is since it's complex)
    noise_buff_ = dcmplxVec(num_Lin()*(NZ()-1));// NZ-1 since ky=kz=0 mode is not driven
    
    // Sizes of various arrays used for normalizing things
    totalN2_ = N(0)*N(1)*N(2); // Total number of grid points
    totalN2_ = totalN2_*totalN2_; // Squared
    mult_noise_fac_ = 1.0/(16*32*32); // Defined so that consistent with (16, 32, 32) results
    mult_noise_fac_ = mult_noise_fac_*mult_noise_fac_;
    // NZ^2 for normalizing  mean field energy
    nz2_ = N(2)*N(2);
    
    // Temps for evaulation of main equations
    uy_ = dcmplxVec( NZ() );
    by_ = dcmplxVec( NZ() );
    
    ////////////////////////////////////////////////////
    //               TEMPORARY ARRAYS                 //
    //  These are used during evaluation of the various parts of the model
    // There should never be any need to keep their value over more than 1 time-step
    //////////////////////////////////////////////////
    // These arrays are used for all sets of equations
    lapFtmp_ = doubVec( NZ() ); //For (time-dependent) k^2
    ilapFtmp_ = doubVec( NZ() ); // Inverse
    lap2tmp_ = doubVec( NZ() ); // For ky^2+kz^2 - could be pre-assigned
    ilap2tmp_ = doubVec( NZ() ); // Inverse


}
Beispiel #2
0
Kdata::Kdata(Model *mod){
    //////////////////////////////////////////
    // Define kx and ky arrays - length is Nx*Ny
    // Leave out the (zero,zero) frequncy
    kx = new dcmplx[ mod->Dimxy_full() ];
    ky = new dcmplx[ mod->Dimxy_full() ];
    ky_index = new int[ mod->Dimxy_full() ];
    // Include only positive ky values!
    int ny=mod->N(1)/2, nx=mod->N(0)/2; // Nx and Ny over 2!
    for (int i=0; i<nx; ++i) {
        for (int j=0; j<ny; ++j) {
            kx[j+ny*i]=dcmplx(0,i*2*PI/( mod->L(0) ));
            ky[j+ny*i]=dcmplx(0,j*2*PI/( mod->L(1) ));
            ky_index[j+ny*i]=j;
        }
    }
    // Leave out the Nyquist frequncy in kx
    for (int i=nx+1; i<2*nx; ++i) {
        for (int j=0; j<ny; ++j) {
            kx[j+ny*(i-1)]=dcmplx(0,(-2*nx+i)*2*PI/( mod->L(0) ));
            ky[j+ny*(i-1)]=dcmplx(0,j*2*PI/( mod->L(2) ));
            ky_index[j+ny*(i-1)]=j;
        }
    }
    ////////////////////////////////////////////////
    
    ///////////////////////////////////////////
    // kz and kz^2 arrays
    // kz is length NZ eigen array
    kz = dcmplxVec( mod->N(2) );
    kz2 = doubVec( mod->N(2) );
    int nz=mod->N(2)/2;
    for (int i=0; i<nz; ++i)
        kz(i) = dcmplx(0,i*2*PI/(mod->L(2)) );
    for (int i=nz; i<2*nz; ++i)
        kz(i) = dcmplx(0,(-2*nz+i)*2*PI/(mod->L(2)) );
    
    kz2 = (kz*kz).real();

    
}
Beispiel #3
0
EulerCN::EulerCN(double t0, Inputs& SP, Model * mod) :
nxy_(mod->Dimxy()), nz_(mod->NZ()),
nMF_(mod->num_MFs()),nLin_(mod->num_Lin()),
model_(mod)
{
    if (SP.dt<0)
        std::cout << "Variable time-step not supported by EulerCN integrator!"<< std::endl;
    dt_ = fabs(SP.dt); // This integrator requires a time-step to be specified in inputs!!
    
    // Solution RHS (dt U = F(U) ) as returned by integrator
    sol_rhs_ = new solution(model_);
    
    
    /////////////////////////////////////////////////////////////
    // Linear operators - couldn't think of a good way to do this, just doubVec array
    
    linearOp_fluct_ = new doubVec*[nxy_];
    linearOp_fluct_old_ = new doubVec*[nxy_];
    for (int i=0; i<nxy_; ++i) {
        linearOp_fluct_[i] = new doubVec[nLin_];
        linearOp_fluct_old_[i] = new doubVec[nLin_];
        for (int j=0; j<nLin_; ++j) {
            linearOp_fluct_[i][j] = doubVec(nz_);
            linearOp_fluct_old_[i][j] = doubVec(nz_);
        }
    }
    denom = doubVec(nz_);
    
    doubVec* linearOp_MF_ = new doubVec[nMF_];
    linearOp_MF_NLCo_ = new doubVec[nMF_];
    linearOp_MF_LinCo_ = new doubVec[nMF_];
    for (int i=0; i<nMF_; ++i) {
        linearOp_MF_[i] = doubVec(nz_);
        linearOp_MF_NLCo_[i] = doubVec(nz_);
        linearOp_MF_LinCo_[i] = doubVec(nz_);
    }
    model_->linearOPs_Init(t0, linearOp_fluct_old_, linearOp_MF_);
    
    // Pre-assign the MF linear operators
    // ASSUMES MF OPERATOR CONSTANT IN TIME!
    for (int i=0; i<nMF_; ++i) {
        linearOp_MF_NLCo_[i] = dt_/(1.0-dt_/2*linearOp_MF_[i]);
        linearOp_MF_LinCo_[i] = (1.0+dt_/2*linearOp_MF_[i])/(1.0-dt_/2*linearOp_MF_[i]);
    }

    delete[] linearOp_MF_;
}
Beispiel #4
0
Kdata::Kdata(Model *mod, MPIdata *mpi){
    //   First form entire array, then take bit for each processor

    //////////////////////////////////////////
    // Define kx and ky arrays - length is Nx*Ny
    // Leave out the (zero,zero) frequncy
    dcmplx *kx_tmp, *ky_tmp; // kx and ky - each of length nxy
    ;
    kx_tmp = new dcmplx[ mod->Dimxy_full() ];
    ky_tmp = new dcmplx[ mod->Dimxy_full() ];
    ky_index_full = new int[ mod->Dimxy_full() ];
    kx_index_full = new int[ mod->Dimxy_full() ];

    kxLfac = 2*PI/( mod->L(0) );
    kyLfac = 2*PI/( mod->L(1) );
    kzLfac = 2*PI/( mod->L(2) );
    
    // Include only positive ky values!
    int ny=mod->N(1)/2, nx=mod->N(0)/2; // Nx and Ny over 2!
    for (int i=0; i<nx; ++i) {
        for (int j=0; j<ny; ++j) {
            kx_tmp[j+ny*i]=dcmplx(0,i*kxLfac);
            ky_tmp[j+ny*i]=dcmplx(0,j*kyLfac);
            kx_index_full[j+ny*i]=i;
            ky_index_full[j+ny*i]=j;
        }
    }
    // Leave out the Nyquist frequncy in kx
    for (int i=nx+1; i<2*nx; ++i) {
        for (int j=0; j<ny; ++j) {
            kx_tmp[j+ny*(i-1)]=dcmplx(0,(-2*nx+i)*kxLfac);
            ky_tmp[j+ny*(i-1)]=dcmplx(0,j*kyLfac);
            kx_index_full[j+ny*(i-1)]=-2*nx+i;
            ky_index_full[j+ny*(i-1)]=j;
        }
    }
    ////////////////////////////////////////////////
    // Take bit belonging to each processor
    int nxy = mod->Dimxy();
    kx = new dcmplx[ nxy ];
    ky = new dcmplx[nxy];
    ky_index = new int[ nxy ];
    kx_index = new int[ nxy ];
    for (int i=0; i<nxy ;  ++i){
        int k_i = i +  mpi->minxy_i(); // k index
        kx[i] = kx_tmp[k_i];
        ky[i] = ky_tmp[k_i];
        ky_index[i] = ky_index_full[k_i];
        kx_index[i] = kx_index_full[k_i];
    }


//    for (int i=0; i<nxy ;  ++i){
//        stringstream prnt;
//        prnt << "kx, ky: " <<kx_index[i] << ", " << ky_index[i] <<endl;
//        mpi->printAll(prnt.str());
//    }
//    
    ///////////////////////////////////////////
    // kz and kz^2 arrays
    // kz is length NZ eigen array
    kz = dcmplxVec( mod->NZ() );
    kz2 = doubVec( mod->NZ() );
    int nzl=(mod->NZ() - 1)/2; // Loop nz
    for (int i=0; i<nzl+1; ++i)
        kz(i) = dcmplx(0,i*kzLfac );
    for (int i=nzl+1; i<2*nzl+1; ++i)
        kz(i) = dcmplx(0,(-2*nzl+i-1)*kzLfac );
    
    kz2 = (kz*kz).real();



    
/////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////
    //   EXTRA BITS
    // lap2 arrays
    // Wasting memory a bit here, since all ky are stored on all processors. To improve, would be better to have a more general parallelization
    // Maximum ky index
    int number_of_ky = ny;
    // Quick error check
    if (mod->Dimxy_full()%number_of_ky!=0)
        std::cout << "Warning, something funny going on in Define_Lap2_Arrays_" << std::endl;
    // Assign data to arrays
    lap2 = new doubVec[ number_of_ky ];
    ilap2 = new doubVec[ number_of_ky ];
    
    
    for (int i=0; i<number_of_ky;  ++i){
        
        // Form Laplacian
        doubVec lap2tmp( mod->NZ() ),ilap2tmp( mod->NZ() );
        double kyr_tmp=ky_tmp[i].imag();
        lap2tmp = -kyr_tmp*kyr_tmp + kz2;
        ilap2tmp = 1/lap2tmp;
        
        // Fix up zero bits
        if (kyr_tmp==0 ) {
            lap2tmp(0)=0;
            // Avoid infinities
            ilap2tmp(0)=1;
        }
        
        // Assign to lap2 and ilap2
        lap2[i] = lap2tmp;
        ilap2[i] = ilap2tmp;
        
        
    }

/////////////////////////////////////////////////
    // Arrays for communications to create real noise
    int *ky0pkx = new int[nx-1]; // Locations of ky=0 in array, kx>0
    int *ky0nkx = new int[nx-1]; // Locations of ky=0 in array, kx<0
    for (int i=0; i<2*nx-2; ++i){
        if (i<nx-1)
            ky0pkx[i] = (i+1)*ny;
        if (i>=nx-1)
            ky0nkx[2*(nx-1)-i-1] = (i+1)*ny;
    }
    
    for (int i=0; i<nx-1; ++i) {
        if (ky0pkx[i]/nxy == mpi->my_n_v()) {
            // Add value to vector if it is in ky0 array
            match_kx_local.push_back(ky0pkx[i]%nxy);
            // Add where it receives this from
            match_kx_from_p.push_back(ky0nkx[i]/nxy);
            match_kx_from.push_back(ky0nkx[i]%nxy);  // Don't need this but use as a tag to make sure the comm matches up
        }
        if (ky0nkx[i]/nxy == mpi->my_n_v()){
            // Add value to _tosend vectors
            match_kx_tosend.push_back(ky0nkx[i]%nxy);
            match_kx_tosend_p.push_back(ky0pkx[i]/nxy);
        }
    }
    
    // SAMPLE CODE TO PERFORM NECESSARY SENDS AND RECEIVES
    
//    i_tosend = match_kx_tosend.begin();
//    i_loc = match_kx_local.begin();
//    i_from = match_kx_from.begin();
//    i_fp = match_kx_from_p.begin();
//    i_sp = match_kx_tosend_p.begin();
//    // Sending
//    while (i_sp < match_kx_tosend_p.end()) {
//        double tosend[2] = {kx[*i_tosend].imag(),ky[*i_tosend].imag()};
//        MPI_Send(&tosend, 2, MPI_DOUBLE, *i_sp, *i_tosend, MPI_COMM_WORLD);
//        ++ i_tosend;
//        ++ i_sp;
//    }
//    // Recieving
//    while (i_fp < match_kx_from_p.end()) {
//        double torec[2];
//        MPI_Recv(torec, 2, MPI_DOUBLE, *i_fp, *i_from, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
//        cout << torec[0] << " " << kx[*i_loc].imag() << ", " << torec[1] << " " << ky[*i_loc].imag() << endl;
//        
//        ++i_fp;
//        ++i_loc;
//        ++i_from;
//    }
    
    delete[] kx_tmp; // Could make these members if it ends up being required
    delete[] ky_tmp;
    delete[] ky0pkx;
    delete[] ky0nkx;
}