/*
This file is part of the Snoopy code.
Snoopy code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Snoopy code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Snoopy code. If not, see .
*/
#include
#include
#include "common.h"
#include "gfft.h"
#include "debug.h"
#include "forcing.h"
#include "particles.h"
#include "ltide.h"
#ifndef COMPRESSIBLE
/***************************************************************/
/**
Compute the right hand side of the INCOMPRESSIBLE dynamical equation
@param dfldo: (output) right hand side of the dynamical equation
@param fldi: (input) current status of the flow
@param t: current time of the simulation
@param tremap: current remap time (only when shear is on)
@param dt: current timestep size
*/
/***************************************************************/
void timestep( struct Field dfldo,
struct Field fldi,
const double t,
const double tremap,
const double dt) {
int i;
double complex q0,q1;
double qr0;
double S;
// This is the timesteping algorithm, solving the physics.
// Find the shear at time t
#ifdef WITH_SHEAR
#ifdef TIME_DEPENDANT_SHEAR
S = param.shear * cos(param.omega_shear * t); // This is the real shear: -dvy/dx
#else
S = param.shear;
#endif
#endif
#ifdef ELSASSER_FORMULATION
/******************************************
** ELSASSER variable formulation **********
** To be used
*******************************************/
// Solve the MHD equations using Elsasser fields
#ifdef _OPENMP
#pragma omp parallel for private(i) schedule(static)
#endif
for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
w1[i] = fldi.vx[i]+fldi.bx[i];
w2[i] = fldi.vy[i]+fldi.by[i];
w3[i] = fldi.vz[i]+fldi.bz[i];
w4[i] = fldi.vx[i]-fldi.bx[i];
w5[i] = fldi.vy[i]-fldi.by[i];
w6[i] = fldi.vz[i]-fldi.bz[i];
}
// These fields should have no divergence.
// When shear is on, however, divergence is conserved up to the timeintegrator precision.
// Let's clean it.
projector(w1,w2,w3);
projector(w4,w5,w6);
gfft_c2r_t(w1);
gfft_c2r_t(w2);
gfft_c2r_t(w3);
gfft_c2r_t(w4);
gfft_c2r_t(w5);
gfft_c2r_t(w6);
// Compute the Elsasser tensor
#ifdef _OPENMP
#pragma omp parallel for private(i) schedule(static)
#endif
for( i = 0 ; i < 2*NTOTAL_COMPLEX ; i++) {
wr7[i] = wr1[i] * wr4[i] / ((double) NTOTAL*NTOTAL);
wr8[i] = wr1[i] * wr5[i] / ((double) NTOTAL*NTOTAL);
wr9[i] = wr1[i] * wr6[i] / ((double) NTOTAL*NTOTAL);
wr10[i] = wr2[i] * wr4[i] / ((double) NTOTAL*NTOTAL);
wr11[i] = wr2[i] * wr5[i] / ((double) NTOTAL*NTOTAL);
wr12[i] = wr2[i] * wr6[i] / ((double) NTOTAL*NTOTAL);
wr13[i] = wr3[i] * wr4[i] / ((double) NTOTAL*NTOTAL);
wr14[i] = wr3[i] * wr5[i] / ((double) NTOTAL*NTOTAL);
wr15[i] = wr3[i] * wr6[i] / ((double) NTOTAL*NTOTAL);
}
gfft_r2c_t(wr7);
gfft_r2c_t(wr8);
gfft_r2c_t(wr9);
gfft_r2c_t(wr10);
gfft_r2c_t(wr11);
gfft_r2c_t(wr12);
gfft_r2c_t(wr13);
gfft_r2c_t(wr14);
gfft_r2c_t(wr15);
// Compute the volution of the Elssaser fields (u= ik.
#ifdef _OPENMP
#pragma omp parallel for private(i) schedule(static)
#endif
for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
dfldo.vx[i] = - I * 0.5 * mask[i] * (
kxt[i] * ( 2.0 * w7[i] ) + ky[i] * ( w8[i] + w10[i]) + kz[i] * (w9[i] + w13[i]) );
dfldo.vy[i] = - I * 0.5 * mask[i] * (
kxt[i] * (w10[i] + w8[i]) + ky[i] * ( 2.0 * w11[i]) + kz[i] * (w12[i] + w14[i]) );
dfldo.vz[i] = - I * 0.5 * mask[i] * (
kxt[i] * (w13[i] + w9[i]) + ky[i] * (w14[i] + w12[i]) + kz[i] * ( 2.0 * w15[i] ) );
dfldo.bx[i] = - I * 0.5 * mask[i] * (
ky[i] * ( w8[i] - w10[i]) + kz[i] * (w9[i] - w13[i]) );
dfldo.by[i] = - I * 0.5 * mask[i] * (
kxt[i] * (w10[i] - w8[i]) + kz[i] * (w12[i] - w14[i]) );
dfldo.bz[i] = - I * 0.5 * mask[i] * (
kxt[i] * (w13[i] - w9[i]) + ky[i] * (w14[i] - w12[i]) );
}
// Compute real(U) in case it is used later.
for( i = 0 ; i < 2*NTOTAL_COMPLEX ; i++) {
wr1[i] = 0.5 * (wr1[i] + wr4[i]);
wr2[i] = 0.5 * (wr2[i] + wr5[i]);
wr3[i] = 0.5 * (wr3[i] + wr6[i]);
}
#else
/******************************************
** Velocity Self Advection ****************
*******************************************/
/* Compute the convolution */
#ifdef _OPENMP
#pragma omp parallel for private(i) schedule(static)
#endif
for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
w1[i] = fldi.vx[i];
w2[i] = fldi.vy[i];
w3[i] = fldi.vz[i];
}
// These fields should have no divergence.
// When shear is on, however, divergence is conserved up to the timeintegrator precision.
// Let's clean it.
projector(w1,w2,w3);
gfft_c2r_t(w1);
gfft_c2r_t(w2);
gfft_c2r_t(w3);
/* Compute the convolution for the advection process */
#ifdef _OPENMP
#pragma omp parallel for private(i) schedule(static)
#endif
for( i = 0 ; i < 2*NTOTAL_COMPLEX ; i++) {
wr4[i] = wr1[i] * wr1[i] / ((double) NTOTAL*NTOTAL);
wr5[i] = wr2[i] * wr2[i] / ((double) NTOTAL*NTOTAL);
#ifndef WITH_2D
wr6[i] = wr3[i] * wr3[i] / ((double) NTOTAL*NTOTAL);
#endif
wr7[i] = wr1[i] * wr2[i] / ((double) NTOTAL*NTOTAL);
wr8[i] = wr1[i] * wr3[i] / ((double) NTOTAL*NTOTAL);
wr9[i] = wr2[i] * wr3[i] / ((double) NTOTAL*NTOTAL);
}
gfft_r2c_t(wr4);
gfft_r2c_t(wr5);
#ifndef WITH_2D
gfft_r2c_t(wr6);
#endif
gfft_r2c_t(wr7);
gfft_r2c_t(wr8);
gfft_r2c_t(wr9);
#ifdef _OPENMP
#pragma omp parallel for private(i) schedule(static)
#endif
for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
dfldo.vx[i] = - I * mask[i] * (
kxt[i] * w4[i] + ky[i] * w7[i] + kz[i] * w8[i] );
dfldo.vy[i] = - I * mask[i] * (
kxt[i] * w7[i] + ky[i] * w5[i] + kz[i] * w9[i] );
dfldo.vz[i] = - I * mask[i] * (
kxt[i] * w8[i] + ky[i] * w9[i] + kz[i] * w6[i] ); // since kz=0 in 2D, kz*w6 gives 0, even if w6 is some random array
}
#endif
/**********************************************
** Particles (if needed) **********************
***********************************************/
#ifdef WITH_PARTICLES
particle_step(dfldo, fldi, wr1, wr2, wr3, t, tremap, dt);
#endif
/**********************************************
** BOUSSINESQ TERMS (if needed) ***************
***********************************************/
#ifdef BOUSSINESQ
#ifdef _OPENMP
#pragma omp parallel for private(i) schedule(static)
#endif
for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
w4[i] = fldi.th[i];
}
gfft_c2r_t(w4);
#ifdef _OPENMP
#pragma omp parallel for private(i) schedule(static)
#endif
for( i = 0 ; i < 2*NTOTAL_COMPLEX ; i++) {
wr5[i] = wr1[i] * wr4[i] / ((double) NTOTAL*NTOTAL);
wr6[i] = wr2[i] * wr4[i] / ((double) NTOTAL*NTOTAL);
#ifndef WITH_2D
wr7[i] = wr3[i] * wr4[i] / ((double) NTOTAL*NTOTAL);
#endif
#ifdef N2PROFILE
wr8[i] = N2_profile[i] * wr4[i] / ((double) NTOTAL);
#endif
}
gfft_r2c_t(wr5);
gfft_r2c_t(wr6);
#ifndef WITH_2D
gfft_r2c_t(wr7);
#endif
#ifdef N2PROFILE
gfft_r2c_t(wr8);
#endif
#ifdef _OPENMP
#pragma omp parallel for private(i) schedule(static)
#endif
for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
#ifdef VERTSTRAT
#ifdef N2PROFILE
dfldo.vz[i] -= w8[i] * mask[i];
#else
dfldo.vz[i] -= param.N2 * fldi.th[i];
#endif
dfldo.th[i] = - I * mask[i] * (
kxt[i] * w5[i] + ky[i] * w6[i] + kz[i] * w7[i])
+ fldi.vz[i];
#else
#ifdef N2PROFILE
dfldo.vx[i] -= w8[i] * mask[i];
#else
dfldo.vx[i] -= param.N2 * fldi.th[i];
#endif
dfldo.th[i] = - I * mask[i] * (
kxt[i] * w5[i] + ky[i] * w6[i] + kz[i] * w7[i])
+ fldi.vx[i];
#endif
}
#endif
/*********************************************
**** MHD Terms (if needed) *****************
*********************************************/
#ifdef MHD
#ifndef ELSASSER_FORMULATION // If Elssaser is on, MHD are already computed...
// Start with the induction equation
#ifdef _OPENMP
#pragma omp parallel for private(i) schedule(static)
#endif
for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
w4[i] = fldi.bx[i];
w5[i] = fldi.by[i];
w6[i] = fldi.bz[i];
}
// These fields should have no divergence.
// When shear is on, however, divergence is conserved up to the timeintegrator precision.
// Let's clean it.
projector(w4,w5,w6);
gfft_c2r_t(w4);
gfft_c2r_t(w5);
gfft_c2r_t(w6);
// (vx,vy,vz) is in w1-w3 and (bx,by,bz) is in (w4-w6). It is now time to compute the emfs in w7-w9...
#ifdef _OPENMP
#pragma omp parallel for private(i) schedule(static)
#endif
for( i = 0 ; i < 2*NTOTAL_COMPLEX ; i++) {
wr7[i] = (wr2[i] * wr6[i] - wr3[i] * wr5[i]) / ((double) NTOTAL*NTOTAL);
wr8[i] = (wr3[i] * wr4[i] - wr1[i] * wr6[i]) / ((double) NTOTAL*NTOTAL);
wr9[i] = (wr1[i] * wr5[i] - wr2[i] * wr4[i]) / ((double) NTOTAL*NTOTAL);
}
// Compute the curl of the emf to add in the induction equation.
gfft_r2c_t(wr7);
gfft_r2c_t(wr8);
gfft_r2c_t(wr9);
#ifdef _OPENMP
#pragma omp parallel for private(i) schedule(static)
#endif
for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
dfldo.bx[i] = I * mask[i] * (ky[i] * w9[i] - kz[i] * w8[i]);
dfldo.by[i] = I * mask[i] * (kz[i] * w7[i] - kxt[i]* w9[i]);
dfldo.bz[i] = I * mask[i] * (kxt[i]* w8[i] - ky[i] * w7[i]);
}
// Let's do the Lorentz Force
// We already have (bx,by,bz) in w4-w6. No need to compute them again...
#ifdef _OPENMP
#pragma omp parallel for private(i) schedule(static)
#endif
for( i = 0 ; i < 2*NTOTAL_COMPLEX ; i++) {
wr1[i] = wr4[i] * wr4[i] / ((double) NTOTAL*NTOTAL);
wr2[i] = wr5[i] * wr5[i] / ((double) NTOTAL*NTOTAL);
wr3[i] = wr6[i] * wr6[i] / ((double) NTOTAL*NTOTAL);
wr7[i] = wr4[i] * wr5[i] / ((double) NTOTAL*NTOTAL);
wr8[i] = wr4[i] * wr6[i] / ((double) NTOTAL*NTOTAL);
wr9[i] = wr5[i] * wr6[i] / ((double) NTOTAL*NTOTAL);
}
gfft_r2c_t(wr1);
gfft_r2c_t(wr2);
gfft_r2c_t(wr3);
gfft_r2c_t(wr7);
gfft_r2c_t(wr8);
gfft_r2c_t(wr9);
#ifdef _OPENMP
#pragma omp parallel for private(i) schedule(static)
#endif
for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
dfldo.vx[i] += I * mask[i] * (kxt[i] * w1[i] + ky[i] * w7[i] + kz[i] * w8[i]);
dfldo.vy[i] += I * mask[i] * (kxt[i] * w7[i] + ky[i] * w2[i] + kz[i] * w9[i]);
dfldo.vz[i] += I * mask[i] * (kxt[i] * w8[i] + ky[i] * w9[i] + kz[i] * w3[i]);
}
#endif
/*************************************************
/** Braginskii viscosity. ***********
/*************************************************/
// Only to be used without the ELSASSER formulation (otherwise we have
// to calculate the maxwell stress twice
// Compute the b_i b_j tensor
#ifdef WITH_BRAGINSKII
#ifdef _OPENMP
#pragma omp parallel for private(i,qr0) schedule(static)
#endif
for( i = 0 ; i < 2*NTOTAL_COMPLEX ; i++) {
qr0 = wr4[i] * wr4[i] + wr5[i] * wr5[i] + wr6[i] * wr6[i]; // norm(B)^2
wr10[i] = wr4[i] * wr4[i] / qr0;
wr11[i] = wr5[i] * wr5[i] / qr0;
wr12[i] = wr6[i] * wr6[i] / qr0;
wr13[i] = wr4[i] * wr5[i] / qr0;
wr14[i] = wr4[i] * wr6[i] / qr0;
wr15[i] = wr5[i] * wr6[i] / qr0;
}
// Compute the stress tensor
#ifdef _OPENMP
#pragma omp parallel for private(i) schedule(static)
#endif
for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
w1[i] = I * kxt[i] * fldi.vx[i];
w2[i] = I * ky[i] * fldi.vy[i];
w3[i] = I * kz[i] * fldi.vz[i];
w4[i] = I * ( kxt[i] * fldi.vy[i] + ky[i] * fldi.vx[i] );
w5[i] = I * ( kxt[i] * fldi.vz[i] + kz[i] * fldi.vx[i] );
w6[i] = I * ( ky[i] * fldi.vz[i] + kz[i] * fldi.vy[i] );
}
gfft_c2r_t(w1);
gfft_c2r_t(w2);
gfft_c2r_t(w3);
gfft_c2r_t(w4);
gfft_c2r_t(w5);
gfft_c2r_t(w6);
// Compute the pressure anisotropy
#ifdef _OPENMP
#pragma omp parallel for private(i) schedule(static)
#endif
for( i = 0 ; i < 2*NTOTAL_COMPLEX ; i++) {
wr7[i] = (wr10[i] * wr1[i]
+ wr11[i] * wr2[i]
+ wr12[i] * wr3[i]
+ wr13[i] * (wr4[i] - param.shear*((double) NTOTAL)) // Take into account the background shear in the stress tensor
+ wr14[i] * wr5[i]
+ wr15[i] * wr6[i]
) / ((double) NTOTAL);
}
// Compute the viscous stress tensor
#ifdef _OPENMP
#pragma omp parallel for private(i) schedule(static)
#endif
for( i = 0 ; i < 2*NTOTAL_COMPLEX ; i++) {
wr10[i] = wr10[i] * wr7[i];
wr11[i] = wr11[i] * wr7[i];
wr12[i] = wr12[i] * wr7[i];
wr13[i] = wr13[i] * wr7[i];
wr14[i] = wr14[i] * wr7[i];
wr15[i] = wr15[i] * wr7[i];
}
gfft_r2c_t(wr10);
gfft_r2c_t(wr11);
gfft_r2c_t(wr12);
gfft_r2c_t(wr13);
gfft_r2c_t(wr14);
gfft_r2c_t(wr15);
#ifdef _OPENMP
#pragma omp parallel for private(i) schedule(static)
#endif
for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
dfldo.vx[i] += 3.0 * mask[i] * I / param.reynolds_B * ( kxt[i] * w10[i] + ky[i] * w13[i] + kz[i] * w14[i] );
dfldo.vy[i] += 3.0 * mask[i] * I / param.reynolds_B * ( kxt[i] * w13[i] + ky[i] * w11[i] + kz[i] * w15[i] );
dfldo.vz[i] += 3.0 * mask[i] * I / param.reynolds_B * ( kxt[i] * w14[i] + ky[i] * w15[i] + kz[i] * w12[i] );
}
#endif
#endif
/*************************************************/
/** HALL EFFECT **********************************/
/*************************************************/
#ifdef WITH_HALL
#ifdef _OPENMP
#pragma omp parallel for private(i) schedule(static)
#endif
for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
w1[i] = I * (ky[i] * fldi.bz[i] - kz[i] * fldi.by[i]);
w2[i] = I * (kz[i] * fldi.bx[i] - kxt[i] * fldi.bz[i]);
w3[i] = I * (kxt[i] * fldi.by[i] - ky[i] * fldi.bx[i]);
w4[i] = fldi.bx[i];
w5[i] = fldi.by[i];
w6[i] = fldi.bz[i];
}
// These fields should have no divergence.
// When shear is on, however, divergence is conserved up to the timeintegrator precision.
// Let's clean it.
projector(w4,w5,w6);
gfft_c2r_t(w1);
gfft_c2r_t(w2);
gfft_c2r_t(w3);
gfft_c2r_t(w4);
gfft_c2r_t(w5);
gfft_c2r_t(w6);
// J is in w1-w3, B is in w4-w6
// q0 is the Hall parameter
q0 = 1.0 / param.x_hall;
#ifdef _OPENMP
#pragma omp parallel for private(i) schedule(static)
#endif
for( i = 0 ; i < 2*NTOTAL_COMPLEX ; i++) {
wr7[i] = -q0*(wr2[i] * wr6[i] - wr3[i] * wr5[i]) / ((double) NTOTAL*NTOTAL);
wr8[i] = -q0*(wr3[i] * wr4[i] - wr1[i] * wr6[i]) / ((double) NTOTAL*NTOTAL);
wr9[i] = -q0*(wr1[i] * wr5[i] - wr2[i] * wr4[i]) / ((double) NTOTAL*NTOTAL);
}
// Compute the curl of the emf to add in the induction equation.
gfft_r2c_t(wr7);
gfft_r2c_t(wr8);
gfft_r2c_t(wr9);
#ifdef _OPENMP
#pragma omp parallel for private(i) schedule(static)
#endif
for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
dfldo.bx[i] += I * mask[i] * (ky[i] * w9[i] - kz[i] * w8[i]);
dfldo.by[i] += I * mask[i] * (kz[i] * w7[i] - kxt[i]* w9[i]);
dfldo.bz[i] += I * mask[i] * (kxt[i]* w8[i] - ky[i] * w7[i]);
}
#endif //WITH_HALL
/************************************
** SOURCE TERMS ********************
************************************/
#ifdef _OPENMP
#pragma omp parallel for private(i) schedule(static)
#endif
for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
#ifdef WITH_ROTATION
dfldo.vx[i] += 2.0 * param.omega * fldi.vy[i];
dfldo.vy[i] -= 2.0 * param.omega * fldi.vx[i];
#endif
#ifdef WITH_SHEAR
dfldo.vy[i] += S * fldi.vx[i];
#ifdef MHD
dfldo.by[i] -= S * fldi.bx[i];
#endif
#endif
}
/************************************
** EXPLICIT LINEAR DISSIPATION ******
*************************************/
#ifdef WITH_EXPLICIT_DISSIPATION
#ifdef _OPENMP
#pragma omp parallel for private(i) schedule(static)
#endif
for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
dfldo.vx[i] += - nu * k2t[i] * fldi.vx[i];
dfldo.vy[i] += - nu * k2t[i] * fldi.vy[i];
dfldo.vz[i] += - nu * k2t[i] * fldi.vz[i];
#ifdef MHD
dfldo.bx[i] += - eta * k2t[i] * fldi.bx[i];
dfldo.by[i] += - eta * k2t[i] * fldi.by[i];
dfldo.bz[i] += - eta * k2t[i] * fldi.bz[i];
#endif // MHD
#ifdef BOUSSiNESQ
dfldo.th[i] += - nu_th * k2t[i] * fldi.th[i];
#endif // BOUSSINESQ
}
#endif // WITH_EXPLICIT_DISSIPATION
/************************************
** PRESSURE TERMS *******************
************************************/
#ifdef _OPENMP
#pragma omp parallel for private(i,q0,q1) schedule(static)
#endif
for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
#ifdef WITH_SHEAR
q0= S * ky[i] * fldi.vx[i] + kxt[i] * dfldo.vx[i] + ky[i] * dfldo.vy[i] + kz[i] * dfldo.vz[i];
#else
q0= kxt[i] * dfldo.vx[i] + ky[i] * dfldo.vy[i] + kz[i] * dfldo.vz[i];
#endif
/* po would contain the pressure field
if(po != NULL) {
po[i] = - I * ik2t[i] * q0; // Save the pressure field (if needed)
}
*/
dfldo.vx[i] += -kxt[i]* q0 * ik2t[i];
dfldo.vy[i] += -ky[i] * q0 * ik2t[i];
dfldo.vz[i] += -kz[i] * q0 * ik2t[i];
}
#ifdef WITH_LINEAR_TIDE
ltide_timestep(dfldo, fldi, t, dt);
#endif
return;
}
#ifdef SGS
/***************************************************************/
/**
Subgridscale model
This is the Chollet-Lesieur Model (1981)
We have nu(k)=nu_i(k)*(E(kc)/kc)^(1/2)
nu_i(k)=0.267+9.21*exp(-3.03 kc/k)
NB: this subgridscale model is applied only to the velocity field,
even when MHD is active!
This is an implicit model: fldi is modified by this routine
@param fldi: (input and output) current status of the flow
@param t: current time of the simulation
@param dt: current timestep size
*/
/***************************************************************/
void sgs_dissipation(struct Field fldi,
const double t,
const double dt) {
// Subgrid model
// Compute E(kc)
double kc, dk;
double q0, q1;
int i,j,k;
kc = 0.5*kmax;
dk = 2.5;
q0 = 0.0;
for( i = 0; i < NX_COMPLEX/NPROC; i++) {
for( j = 0; j < NY_COMPLEX; j++) {
for( k = 0; k < NZ_COMPLEX; k++) {
if( (k2t[ IDX3D ] < (kc+dk) * (kc+dk)) & (k2t[ IDX3D ] > (kc-dk) * (kc-dk) )) {
#ifdef WITH_2D
if( j == 0)
#else
if( k == 0)
#endif
q0 = q0 + creal( fldi.vx[ IDX3D ] * conj( fldi.vx[ IDX3D ] ) +
fldi.vy[ IDX3D ] * conj( fldi.vy[ IDX3D ] ) +
fldi.vz[ IDX3D ] * conj( fldi.vz[ IDX3D ] ) ) / ((double) NTOTAL*NTOTAL);
else
// k>0, only half of the complex plane is represented.
q0 = q0 + 2.0 * creal( fldi.vx[ IDX3D ] * conj( fldi.vx[ IDX3D ] ) +
fldi.vy[ IDX3D ] * conj( fldi.vy[ IDX3D ] ) +
fldi.vz[ IDX3D ] * conj( fldi.vz[ IDX3D ] ) ) / ((double) NTOTAL*NTOTAL);
}
}
}
}
#ifdef MPI_SUPPORT
reduce(&q0, 1);
#endif
q0 = q0 / (2.0*dk);
// q0 is E(kc)
q0 = pow(q0/kc, 0.5);
#ifdef _OPENMP
#pragma omp parallel for private(i) schedule(static)
#endif
for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
w1[i] = (double complex) q0 * ( 0.267 + 9.21 * exp(-3.03 * kc * pow(ik2t[i],0.5) ) ); // Original Chollet-Lesieur
// w1[i] = 0.1 * (1.0 + 5.0*pow(k2t[i]/(kc*kc), 4.0)) * q0; // Ponty el al 2003
}
// Apply SGS viscosity to the flow.
for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
q0 = exp( - w1[i] * dt* k2t[i] );
fldi.vx[i] = fldi.vx[i] * q0;
fldi.vy[i] = fldi.vy[i] * q0;
fldi.vz[i] = fldi.vz[i] * q0;
}
}
#endif // This is for SGS
/***************************************************************/
/**
Implicit steps of the integrator (essentially linear diffusion terms)
This is an implicit model: fldi is modified by this routine
@param fldi: (input and output) current status of the flow
@param t: current time of the simulation
@param dt: current timestep size
*/
/***************************************************************/
void implicitstep(
struct Field fldi,
const double t,
const double dt ) {
double q0;
int i;
#ifdef SGS
sgs_dissipation( fldi, t, dt);
#endif
#ifndef WITH_EXPLICIT_DISSIPATION
#ifdef _OPENMP
#pragma omp parallel for private(i,q0) schedule(static)
#endif
for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
#ifndef SGS
q0 = exp( - nu * dt* k2t[i] );
fldi.vx[i] = fldi.vx[i] * q0;
fldi.vy[i] = fldi.vy[i] * q0;
fldi.vz[i] = fldi.vz[i] * q0;
#endif // SGS
#ifdef BOUSSINESQ
q0 = exp( - nu_th * dt* k2t[i] );
fldi.th[i] = fldi.th[i] * q0;
#endif
#ifdef MHD
q0 = exp( - eta * dt* k2t[i] );
fldi.bx[i] = fldi.bx[i] * q0;
fldi.by[i] = fldi.by[i] * q0;
fldi.bz[i] = fldi.bz[i] * q0;
#endif
}
#endif // WITH_EXPLICIT_DISSIPATION
#ifdef FORCING
forcing(fldi, dt);
#endif
#ifdef WITH_PARTICLES
particle_implicit_step( fldi, t, dt);
#endif
#ifdef WITH_LINEAR_TIDE
ltide_implicitstep( fldi, t, dt);
#endif
return;
}
#endif // This is for COMPRESSIBLE