@@ -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
6489void 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