Skip to content

Commit 5f2bb98

Browse files
authored
Merge pull request #323 from tashtonkey/ion-viscosity-neoclassical
Ion viscosity neoclassical
2 parents 0a6a635 + 7569ac8 commit 5f2bb98

File tree

2 files changed

+77
-8
lines changed

2 files changed

+77
-8
lines changed

include/ion_viscosity.hxx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,19 @@ private:
5454
BoutReal eta_limit_alpha; ///< Flux limit coefficient
5555
bool perpendicular; ///< Include perpendicular flow? (Requires phi)
5656
Vector2D Curlb_B; ///< Curvature vector Curl(b/B)
57-
57+
bool bounce_frequency; ///< Modify the collision time with the bounce frequency?
58+
BoutReal bounce_frequency_q95; ///< Input q95 for when including bounce frequency change
59+
BoutReal bounce_frequency_epsilon; ///< Input inverse aspect ratio for including bounce frequency change
60+
BoutReal bounce_frequency_R; ///< Input major radius
5861
bool diagnose; ///< Output additional diagnostics?
59-
62+
6063
/// Per-species diagnostics
6164
struct Diagnostics {
6265
Field3D Pi_ciperp; ///< Perpendicular part of Pi scalar
6366
Field3D Pi_cipar; ///< Parallel part of Pi scalar
6467
Field3D DivJ; ///< Divergence of current in vorticity equation
68+
Field3D bounce_factor;
69+
Field3D nu_star;
6570
};
6671

6772
/// Store diagnostics for each species

src/ion_viscosity.cxx

Lines changed: 70 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,23 @@ IonViscosity::IonViscosity(std::string name, Options& alloptions, Solver*) {
2525
perpendicular = options["perpendicular"]
2626
.doc("Include perpendicular flow? (Requires phi)")
2727
.withDefault<bool>(false);
28-
28+
29+
bounce_frequency = options["bounce_frequency"]
30+
.doc("Include neoclassical modification of the collision time?")
31+
.withDefault<bool>(false);
32+
33+
bounce_frequency_q95 = options["bounce_frequency_q95"]
34+
.doc("Include input for q95 when using bounce frequency modification to viscosity")
35+
.withDefault(4.0);
36+
37+
bounce_frequency_epsilon = options["bounce_frequency_epsilon"]
38+
.doc("Include input for inverse aspect ratio epsilon when using bounce frequency modification to viscosity")
39+
.withDefault(0.3);
40+
41+
bounce_frequency_R = options["bounce_frequency_R"]
42+
.doc("Include input for major radius R when using bounce frequency modification to viscosity")
43+
.withDefault(2.0);
44+
2945
if (perpendicular) {
3046
// Read curvature vector
3147
try {
@@ -53,12 +69,21 @@ IonViscosity::IonViscosity(std::string name, Options& alloptions, Solver*) {
5369

5470
auto coord = mesh->getCoordinates();
5571

72+
73+
5674
Curlb_B.x /= Bnorm;
5775
Curlb_B.y *= SQ(Lnorm);
5876
Curlb_B.z *= SQ(Lnorm);
5977

6078
Curlb_B *= 2. / coord->Bxy;
6179
}
80+
if (bounce_frequency) {
81+
const Options& units = alloptions["units"];
82+
const BoutReal Lnorm = units["meters"];
83+
bounce_frequency_R /= Lnorm;
84+
}
85+
86+
6287
}
6388

6489
void IonViscosity::transform(Options &state) {
@@ -98,7 +123,27 @@ void IonViscosity::transform(Options &state) {
98123

99124
// Parallel ion viscosity (4/3 * 0.96 coefficient)
100125
Field3D eta = 1.28 * P * tau;
126+
127+
Field2D bounce_factor = 1.0; // if bounce_frequency = false, this factor does nothing to anything
128+
Field2D nu_star = 1.0;
129+
130+
if (bounce_frequency) {
131+
// Need to collect the DC density and temperature, ion collision time and thermal velocity to calculate the bounce frequency, with the equation taken as in Rozhansky 2009.
132+
133+
const Field2D N_av = DC(get<Field3D>(species["density"]));
134+
const Field2D T_av = DC(get<Field3D>(species["temperature"]));
135+
const Field2D tau_av = DC(tau);
136+
137+
// calculating ion thermal velocity
138+
BoutReal mass = get<BoutReal>(species["AA"]);
139+
const Field2D v_thermal = sqrt(2.0 * T_av / mass);
101140

141+
nu_star *= (bounce_frequency_R * bounce_frequency_q95) / ( tau_av * pow(bounce_frequency_epsilon, 1.5) * v_thermal);
142+
143+
bounce_factor *= (1 / (1 + (1./nu_star))) * (1 / (1 + (1. / pow(bounce_frequency_epsilon, 1.5)) * (1./nu_star)));
144+
eta *= bounce_factor;
145+
}
146+
102147
if (eta_limit_alpha > 0.) {
103148
// SOLPS-style flux limiter
104149
// Values of alpha ~ 0.5 typically
@@ -126,21 +171,22 @@ void IonViscosity::transform(Options &state) {
126171
const Field2D V_av = DC(V);
127172

128173
// Parallel ion stress tensor component, calculated here because before it was only div_Pi_cipar
129-
Field2D Pi_cipar = -0.96 * P_av * tau_av *
174+
Field2D Pi_cipar = -0.96 * P_av * tau_av * bounce_factor *
130175
(2. * Grad_par(V_av) + V_av * Grad_par_logB);
131176
Field2D Pi_ciperp = 0 * Pi_cipar; // Perpendicular components and divergence of current J equal to 0 for only parallel viscosity case
132177
Field2D DivJ = 0 * Pi_cipar;
133178
// Find the diagnostics struct for this species
134179
auto search = diagnostics.find(species_name);
135180
if (search == diagnostics.end()) {
136181
// First time, create diagnostic
137-
diagnostics.emplace(species_name, Diagnostics {Pi_ciperp, Pi_cipar, DivJ});
182+
diagnostics.emplace(species_name, Diagnostics {Pi_ciperp, Pi_cipar, DivJ, bounce_factor});
138183
} else {
139184
// Update diagnostic values
140185
auto& d = search->second;
141186
d.Pi_ciperp = Pi_ciperp;
142187
d.Pi_cipar = Pi_cipar;
143188
d.DivJ = DivJ;
189+
d.bounce_factor = bounce_factor;
144190
}
145191
}
146192
continue; // Skip perpendicular flow parts below
@@ -159,15 +205,15 @@ void IonViscosity::transform(Options &state) {
159205
const Field2D V_av = DC(V);
160206

161207
// Parallel ion stress tensor component
162-
Field2D Pi_cipar = -0.96 * P_av * tau_av *
208+
Field2D Pi_cipar = -0.96 * P_av * tau_av * bounce_factor *
163209
(2. * Grad_par(V_av) + V_av * Grad_par_logB);
164210
// Could also be written as:
165211
// Pi_cipar = -0.96*Pi*tau*2.*Grad_par(sqrt(Bxy)*Vi)/sqrt(Bxy);
166212

167213
// Perpendicular ion stress tensor
168214
// 0.96 P tau kappa * (V_E + V_di + 1.61 b x Grad(T)/B )
169215
// Note: Heat flux terms are neglected for now
170-
Field2D Pi_ciperp = -0.5 * 0.96 * P_av * tau_av *
216+
Field2D Pi_ciperp = -0.5 * 0.96 * P_av * tau_av * bounce_factor *
171217
(Curlb_B * Grad(phi_av + 1.61 * T_av) - Curlb_B * Grad(P_av) / N_av);
172218

173219
// Limit size of stress tensor components
@@ -238,13 +284,15 @@ void IonViscosity::transform(Options &state) {
238284
auto search = diagnostics.find(species_name);
239285
if (search == diagnostics.end()) {
240286
// First time, create diagnostic
241-
diagnostics.emplace(species_name, Diagnostics {Pi_ciperp, Pi_cipar, DivJ});
287+
diagnostics.emplace(species_name, Diagnostics {Pi_ciperp, Pi_cipar, DivJ, bounce_factor, nu_star});
242288
} else {
243289
// Update diagnostic values
244290
auto& d = search->second;
245291
d.Pi_ciperp = Pi_ciperp;
246292
d.Pi_cipar = Pi_cipar;
247293
d.DivJ = DivJ;
294+
d.bounce_factor = bounce_factor;
295+
d.nu_star = nu_star;
248296
}
249297
}
250298
}
@@ -289,6 +337,22 @@ void IonViscosity::outputVars(Options &state) {
289337
{"long_name", std::string("Divergence of viscous current due to species") + species_name},
290338
{"species", species_name},
291339
{"source", "ion_viscosity"}});
340+
341+
set_with_attrs(state[std::string("bounce_factor_") + species_name], d.bounce_factor,
342+
{{"time_dimension", "t"},
343+
{"units", "none"},
344+
{"conversion", 1},
345+
{"long_name", std::string("Bounce factor for viscosity calculation") + species_name},
346+
{"species", species_name},
347+
{"source", "ion_viscosity"}});
348+
349+
set_with_attrs(state[std::string("nu_star_") + species_name], d.nu_star,
350+
{{"time_dimension", "t"},
351+
{"units", "none"},
352+
{"conversion", 1},
353+
{"long_name", std::string("nu star") + species_name},
354+
{"species", species_name},
355+
{"source", "ion_viscosity"}});
292356
}
293357
}
294358
}

0 commit comments

Comments
 (0)