-
Notifications
You must be signed in to change notification settings - Fork 306
/
braginskii.py
2266 lines (1891 loc) · 73.1 KB
/
braginskii.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
r"""
Functions to calculate classical transport coefficients.
.. nbgallery::
/notebooks/formulary/braginskii
.. attention::
|expect-api-changes|
Introduction
============
Classical transport theory is derived by using kinetic theory to close
the plasma two-fluid (electron and ion fluid) equations in the
collisional limit. The first complete model in this form was done by
:cite:t:`braginskii:1965`.
As described in the next section, this module uses fitting functions
from the literature
:cite:p:`braginskii:1965,spitzer:1953,spitzer:1962,epperlein:1986,ji:2013`
to calculate the transport coefficients, which are the resistivity,
thermoelectric conductivity, thermal conductivity, and viscosity.
Keep in mind the following assumptions under which the transport equations
are derived:
1. The plasma is fully ionized, only consisting of ions and electrons.
Neutral atoms are neglected.
2. Turbulent transport does not dominate.
3. The velocity distribution is close to Maxwellian. This implies:
a) Collisional mean free path ≪ gradient scale length along field.
b) Gyroradius ≪ gradient scale length perpendicular to field.
4. The plasma is highly collisional: collisional frequency ≫ gyrofrequency.
When classical transport is not valid, e.g. due to the presence of strong
gradients or turbulent transport, the transport is significantly increased
by these other effects. Thus classical transport often serves as a lower
bound on the losses / transport encountered in a plasma.
Transport Variables
===================
For documentation on the individual transport variables, please take
the following links to documentation of methods of |ClassicalTransport|.
* `~plasmapy.formulary.braginskii.ClassicalTransport.resistivity`
* `~plasmapy.formulary.braginskii.ClassicalTransport.thermoelectric_conductivity`
* `~plasmapy.formulary.braginskii.ClassicalTransport.ion_thermal_conductivity`
* `~plasmapy.formulary.braginskii.ClassicalTransport.electron_thermal_conductivity`
* `~plasmapy.formulary.braginskii.ClassicalTransport.ion_viscosity`
* `~plasmapy.formulary.braginskii.ClassicalTransport.electron_viscosity`
Using the module
================
Given that many of the transport variables share a lot of the same computation
and many are often needed to be calculated simultaneously, this module provides
a |ClassicalTransport| class that can be initialized once with all of the
variables necessary for calculation. It then provides all of the functionality
as methods (please refer to its documentation).
If you only wish to calculate a single transport variable (or if just don't
like object-oriented interfaces), we have also provided wrapper functions in
the main module namespace that use |ClassicalTransport| under the hood (see below,
in the Functions section).
.. warning::
The API for this package is not yet stable.
Classical transport models
==========================
In this section, we present a broad overview of classical transport models
implemented within this module.
Braginskii :cite:p:`braginskii:1965`
------------------------------------
The original Braginskii treatment as presented in the highly cited review
paper from 1965. Coefficients are found from expansion of the kinetic
equation in Laguerre polynomials, truncated at the second term in their
series expansion (\ :math:`k = 2`\ ). This theory allows for arbitrary Hall parameter
and include results for Z = 1, 2, 3, 4, and infinity (the case of Lorentz
gas completely stripped of electrons, and the stationary ion approximation).
Spitzer-Harm :cite:p:`spitzer:1953,spitzer:1962`
------------------------------------------------
These coefficients were obtained from a numerical solution of the
Fokker-Planck equation. They give one of the earliest and most accurate
(in the Fokker-Planck sense) results for electron transport in simple
plasma. They principally apply in the unmagnetized / parallel field
case, although for resistivity Spitzer also calculated a famous result
for a strong perpendicular magnetic field. Results are for Z = 1, 2, 4,
16, and infinity (Lorentz gas / stationary ion approximation).
Epperlein-Haines :cite:p:`epperlein:1986`
-----------------------------------------
Not yet implemented.
Ji-Held :cite:p:`ji:2013`
-------------------------
This is a modern treatment of the classical transport problem that has been
carried out with laudable care. It allows for arbitrary hall parameter and
arbitrary :math:`Z` for all coefficients. Similar to the Epperlein-Haines model,
it corrects some known inaccuracies in the original Braginskii results,
notably the asymptotic behavior of alpha-cross and beta_perp as Hall →
+infinity. It also studies effects of electron collisions in the ion
terms, which all other treatments have not. To neglect electron-electron
collisions, leave :math:`μ = 0`\ . To consider them, specify mu and theta.
"""
from typing import Optional
__all__ = [
"ClassicalTransport",
"resistivity",
"thermoelectric_conductivity",
"ion_thermal_conductivity",
"electron_thermal_conductivity",
"ion_viscosity",
"electron_viscosity",
]
import warnings
import astropy.units as u
import numpy as np
from astropy.constants.si import e, k_B, m_e
from plasmapy import particles
from plasmapy.formulary.collisions import (
Coulomb_logarithm,
fundamental_electron_collision_freq,
fundamental_ion_collision_freq,
)
from plasmapy.formulary.dimensionless import Hall_parameter
from plasmapy.formulary.misc import _grab_charge
from plasmapy.particles.atomic import _is_electron
from plasmapy.particles.exceptions import InvalidParticleError
from plasmapy.utils.decorators import validate_quantities
from plasmapy.utils.exceptions import CouplingWarning, PhysicsError
class ClassicalTransport:
r"""
Classical transport coefficients (e.g. Braginskii, 1965).
.. attention::
|expect-api-changes|
Notes
-----
Given that many of the transport variables share a lot of the same
computation and many are often needed to be calculated
simultaneously, this class can be initialized once with all of the
variables necessary for calculation. It then provides all of the
functionality as methods (please refer to their documentation).
Parameters
----------
T_e : `~astropy.units.Quantity`
Electron temperature in units of temperature or energy per
particle.
n_e : `~astropy.units.Quantity`
The electron number density in units convertible to per cubic
meter.
T_i : `~astropy.units.Quantity`
Ion temperature in units of temperature or energy per particle.
n_i : `~astropy.units.Quantity`
The ion number density in units convertible to per cubic meter.
ion : `str`
Representation of the ion species (e.g., ``'p'`` for protons,
``'e-'`` for electrons, ``'D+'`` for deuterium, or ``'He-4 +1'``
for singly ionized helium-4). If no charge state information is
provided, then the particles are assumed to be singly charged.
Z : `int` or `numpy.inf`, optional
The ion charge state. Overrides particle charge state if
included. Different theories support different values of
``Z``. For the original Braginskii model, ``Z`` can be any of
[1, 2, 3, 4, infinity]. The Ji-Held model supports arbitrary
``Z``. Average ionization states ``Z_mean`` can be input using
this input and the Ji-Held model, although doing so may neglect
effects caused by multiple ion populations.
B : `~astropy.units.Quantity`, optional
The magnetic field strength in units convertible to tesla.
Defaults to zero.
model: `str`
Indication of whose formulation from literature to use. Allowed
values are:
* ``"Braginskii"`` :cite:p:`braginskii:1965`
* ``"Spitzer-Harm"`` :cite:p:`spitzer:1953,spitzer:1962`
* ``"Epperlein-Haines"`` (not yet implemented) :cite:p:`epperlein:1986`
* ``"Ji-Held"`` :cite:p:`ji:2013`
field_orientation : `str`, defaults to ``'parallel'``
Either of ``'parallel'``, ``'par'``, ``'perpendicular'``,
``'perp'``, ``'cross'``, or ``'all'``, indicating the cardinal
orientation of the magnetic field with respect to the transport
direction of interest. Note that ``'perp'`` refers to transport
perpendicular to the field direction (in the direction of the
temperature gradient), while ``'cross'`` refers to the direction
perpendicular to B and the gradient of temperature
(:math:`B × ∇T`\ ). The option ``'all'`` will return a
`numpy.array` of all three, ``np.array((par, perp, cross))``.
Does not apply to viscosities.
coulomb_log_ei : `float` or dimensionless `~astropy.units.Quantity`, optional
Force a particular value to be used for the electron-ion Coulomb
logarithm (test electrons on field ions). If `None`,
`~plasmapy.formulary.collisions.coulomb.Coulomb_logarithm` will
be used. Useful for comparing calculations.
V_ei : `~astropy.units.Quantity`, optional
The relative velocity between particles. Supplied to
`~plasmapy.formulary.collisions.coulomb.Coulomb_logarithm`
function, not otherwise used. If not provided, thermal velocity
is assumed: :math:`μ V^2 \sim 2 k_B T` where :math:`μ` is the
reduced mass.
coulomb_log_ii : `float` or dimensionless `~astropy.units.Quantity`, optional
Force a particular value to be used for the ion-ion Coulomb
logarithm (test ions on field ions). If `None`, the PlasmaPy
function
`~plasmapy.formulary.collisions.coulomb.Coulomb_logarithm` will
be used. Useful for comparing calculations.
V_ii : `~astropy.units.Quantity`, optional
The relative velocity between particles. Supplied to
`~plasmapy.formulary.collisions.coulomb.Coulomb_logarithm`
function, not otherwise used. If not provided, thermal velocity
is assumed: :math:`μ V^2 \sim 2 k_B T` where :math`μ` is the
reduced mass.
hall_e : `float` or dimensionless `~astropy.units.Quantity`, optional
Force a particular value to be used for the electron Hall
parameter. If `None`,
`~plasmapy.formulary.dimensionless.Hall_parameter` will be
used. Useful for comparing calculations.
hall_i : `float` or dimensionless `~astropy.units.Quantity`, optional
Force a particular value to be used for the ion Hall parameter.
If `None`, `~plasmapy.formulary.dimensionless.Hall_parameter`
will be used. Useful for comparing calculations.
mu : `float` or dimensionless `~astropy.units.Quantity`, optional
Ji-Held model only, may be used to include ion-electron effects
on the ion transport coefficients. Defaults to zero, thus
disabling these effects.
theta : `float` or dimensionless `~astropy.units.Quantity`, optional
Ji-Held model only, may be used to include ion-electron effects
on the ion transport coefficients. Defaults to
:math:`T_e / T_i`\ . Only has effect if ``mu`` is non-zero.
coulomb_log_method : `str`, optional
The method by which to compute the Coulomb logarithm.
The default method is the classical straight-line
Landau-Spitzer method (``"classical"`` or ``"ls"``). The other
6 supported methods are ``"ls_min_interp"``,
``"ls_full_interp"``, ``"ls_clamp_mininterp"``,
``"hls_min_interp"``, ``"hls_max_interp"``, and
``"hls_full_interp"``. Please refer to the docstring of
`~plasmapy.formulary.collisions.coulomb.Coulomb_logarithm` for
more information about these methods.
Raises
------
`ValueError`
On incorrect or unknown values of arguments.
`~plasmapy.utils.exceptions.PhysicsError`
If input or calculated values for Coulomb logarithms are nonphysical.
Examples
--------
>>> import astropy.units as u
>>> t = ClassicalTransport(1 * u.eV, 1e20 / u.m**3, 1 * u.eV, 1e20 / u.m**3, "p")
>>> t.resistivity # doctest: +SKIP
<Quantity 0.0003670... Ohm m>
>>> t.thermoelectric_conductivity
<Quantity 0.71108...>
>>> t.ion_thermal_conductivity
<Quantity 0.01552... W / (K m)>
>>> t.electron_thermal_conductivity
<Quantity 0.38064... W / (K m)>
>>> t.ion_viscosity
<Quantity [4.621297...e-07, 4.607248...e-07, 4.607248...e-07, 0.000000...e+00,
0.000000...e+00] Pa s>
>>> t.electron_viscosity
<Quantity [5.822738...e-09, 5.820820...e-09, 5.820820...e-09, 0.000000...e+00,
0.000000...e+00] Pa s>
"""
@validate_quantities(
T_e={"can_be_negative": False, "equivalencies": u.temperature_energy()},
T_i={"can_be_negative": False, "equivalencies": u.temperature_energy()},
m_i={"can_be_negative": False},
)
def __init__( # noqa: PLR0912, PLR0915
self,
T_e: u.Quantity[u.K],
n_e: u.Quantity[u.m**-3],
T_i: u.Quantity[u.K],
n_i: u.Quantity[u.m**-3],
ion,
m_i: u.Quantity[u.kg] = None,
Z=None,
B: u.Quantity[u.T] = 0.0 * u.T,
model="Braginskii",
field_orientation="parallel",
coulomb_log_ei=None,
V_ei=None,
coulomb_log_ii=None,
V_ii=None,
hall_e=None,
hall_i=None,
mu=None,
theta: Optional[float] = None,
coulomb_log_method="classical",
) -> None:
# check the model
self.model = model.lower() # string inputs should be case-insensitive
valid_models = ["braginskii", "spitzer", "spitzer-harm", "ji-held"]
if self.model not in valid_models:
raise ValueError(f"Unknown transport model '{self.model}'")
# check the field orientation
self.field_orientation = field_orientation.lower()
valid_fields = ["parallel", "par", "perpendicular", "perp", "cross", "all"]
is_valid_field = self.field_orientation in valid_fields
if not is_valid_field:
raise ValueError(f"Unknown field orientation '{self.field_orientation}'")
# values and units have already been checked by decorator
self.T_e = T_e
self.T_i = T_i
self.n_e = n_e
self.n_i = n_i
# get ion mass and charge state
if m_i is None:
try:
self.m_i = particles.particle_mass(ion)
except InvalidParticleError as ex:
raise ValueError(
f"Unable to find mass of particle: {ion} in ClassicalTransport"
) from ex
else:
self.m_i = m_i
self.Z = _grab_charge(ion, Z) * u.dimensionless_unscaled
if self.Z < 0:
raise ValueError("Z is not allowed to be negative!") # TODO: remove?
# decide on the particle string for the electrons
self.e_particle = "e-"
self.ion = ion
# save other arguments
self.B = B
self.V_ei = V_ei
self.V_ii = V_ii
# calculate Coulomb logs if not forced in input
if coulomb_log_ei is not None:
self.coulomb_log_ei = coulomb_log_ei
else:
self.coulomb_log_ei = Coulomb_logarithm(
T_e, n_e, (self.e_particle, self.ion), V_ei, method=coulomb_log_method
)
if self.coulomb_log_ei < 1:
# TODO: discuss whether this is not too strict
raise PhysicsError(
f"Coulomb logarithm is {coulomb_log_ei} (below 1),"
"this is probably not physical!"
)
elif self.coulomb_log_ei < 4:
warnings.warn(
f"Coulomb logarithm is {coulomb_log_ei},"
f" you might have strong coupling effects",
CouplingWarning,
)
if coulomb_log_ii is not None:
self.coulomb_log_ii = coulomb_log_ii
else:
self.coulomb_log_ii = Coulomb_logarithm(
T_i,
n_e, # this is not a typo!
(self.ion, self.ion),
V_ii,
method=coulomb_log_method,
)
if self.coulomb_log_ii < 1:
# TODO: discuss whether this is not too strict
raise PhysicsError(
f"Coulomb logarithm is {coulomb_log_ii} (below 1),"
"this is probably not physical!"
)
elif self.coulomb_log_ii < 4:
warnings.warn(
f"Coulomb logarithm is {coulomb_log_ii},"
f" you might have strong coupling effects",
CouplingWarning,
)
# calculate Hall parameters if not forced in input
if hall_e is not None:
self.hall_e = hall_e
else:
self.hall_e = Hall_parameter(
n_e,
T_e,
B,
self.ion,
self.e_particle,
coulomb_log_ei,
V_ei,
coulomb_log_method=coulomb_log_method,
)
if hall_i is not None:
self.hall_i = hall_i
else:
self.hall_i = Hall_parameter(
n_i,
T_i,
B,
self.ion,
self.ion,
coulomb_log_ii,
V_ii,
coulomb_log_method=coulomb_log_method,
)
# set up the ion non-dimensional coefficients for the Ji-Held model
self.mu = 0 if mu is None else mu # disable the JH special features by default
# self.mu = m_e / self.m_i # enable the JH special features
self.theta = self.T_e / self.T_i if theta is None else theta
@property
@validate_quantities
def resistivity(self) -> u.Quantity[u.Ohm * u.m]:
r"""
Calculate the resistivity.
The resistivity (:math:`α`) of a plasma is defined by
.. math::
α = \frac{\hat{α}}{n_e e^2 \frac{τ_e}{m_e}}
where :math:`\hat{α}` is the non-dimensional resistivity of the plasma,
:math:`n_e` is the electron number density of the plasma,
:math:`e` is Euler's number,
:math:`τ_e` is the fundamental electron collision period of the plasma,
and :math:`m_e` is the mass of an electron.
Notes
-----
The resistivity here is defined similarly to solid conductors, and thus
represents the classical plasmas' property to resist the flow of
electrical current. The result is in units of ohm meters, so if you
assume where the current is flowing in the plasma (length and
cross-sectional area), you could calculate a DC resistance of the
plasma in ohms as resistivity × length / cross-sectional area.
Experimentalists with plasma discharges may observe different
:math:`V = IR` Ohm's law behavior than suggested by the
resistance calculated here, for reasons such as the occurrence
of plasma sheath layers at the electrodes or the plasma not
satisfying the classical assumptions.
Returns
-------
`~astropy.units.quantity.Quantity`
"""
alpha_hat = _nondim_resistivity(
self.hall_e, self.Z, self.e_particle, self.model, self.field_orientation
)
tau_e = 1 / fundamental_electron_collision_freq(
self.T_e, self.n_e, self.ion, self.coulomb_log_ei, self.V_ei
)
alpha = alpha_hat / (self.n_e * e**2 * tau_e / m_e)
return alpha
@property
def thermoelectric_conductivity(self):
r"""
Calculate the thermoelectric conductivity.
.. todo::
The thermoelectric conductivity (:math:`\hat{β}`) of a plasma
is defined by...
Notes
-----
To be improved.
Returns
-------
`~astropy.units.quantity.Quantity`
"""
beta_hat = _nondim_te_conductivity(
self.hall_e, self.Z, self.e_particle, self.model, self.field_orientation
)
return u.Quantity(beta_hat)
@property
@validate_quantities
def ion_thermal_conductivity(self) -> u.Quantity[u.W / u.m / u.K]:
r"""
Calculate the thermal conductivity for ions.
The ion thermal conductivity (:math:`κ`) of a plasma is defined by
.. math::
κ = \hat{κ} \frac{n_i k_B^2 T_i τ_i}{m_i}
where :math:`\hat{κ}` is the non-dimensional ion thermal
conductivity of the plasma,
:math:`n_i` is the ion number density of the plasma,
:math:`k_B` is the Boltzmann constant,
:math:`T_i` is the ion temperature of the plasma,
:math:`τ_i` is the fundamental ion collision period of the plasma,
and :math:`m_i` is the mass of an ion of the plasma.
Notes
-----
This is the classical plasma ions' ability to conduct energy and heat,
defined similarly to other materials. The result is a conductivity in
units of W / m / K, so if you assume you know where the heat is flowing
(temperature gradient, cross-sectional area) you can calculate the
energy transport in watts as conductivity × cross-sectional area ×
temperature gradient. In lab plasmas, typically the energy is flowing
out of your high-temperature plasma to something else, like the walls
of your device, and you are sad about this.
Returns
-------
`~astropy.units.quantity.Quantity`
See Also
--------
electron_thermal_conductivity
"""
kappa_hat = _nondim_thermal_conductivity(
self.hall_i,
self.Z,
self.ion,
self.model,
self.field_orientation,
self.mu,
self.theta,
)
tau_i = 1 / fundamental_ion_collision_freq(
self.T_i, self.n_i, self.ion, self.coulomb_log_ii, self.V_ii
)
kappa = kappa_hat * (self.n_i * k_B**2 * self.T_i * tau_i / self.m_i)
return kappa
@property
@validate_quantities
def electron_thermal_conductivity(self) -> u.Quantity[u.W / u.m / u.K]:
r"""
Calculate the thermal conductivity for electrons.
The electron thermal conductivity (:math:`κ`) of a plasma is defined by
.. math::
κ = \hat{κ} \frac{n_e k_B^2 T_e τ_e}{m_e}
where :math:`\hat{κ}` is the non-dimensional electron thermal
conductivity of the plasma,
:math:`n_e` is the electron number density of the plasma,
:math:`k_B` is the Boltzmann constant,
:math:`T_e` is the electron temperature of the plasma,
:math:`τ_e` is the fundamental electron collision period of the plasma,
and :math:`m_e` is the mass of an electron.
Notes
-----
This is quite similar to the ion thermal conductivity, except that it's
for the plasma electrons. In a typical unmagnetized plasma, the
electron thermal conductivity is much higher than the ions and will
dominate, due to the electrons' low mass and fast speeds.
In a strongly magnetized plasma, following the classical transport
analysis, you calculate that the perpendicular-field thermal
conductivity becomes greatly reduced for the ions and electrons, with
the electrons actually being restrained even more than the ions due to
their low mass and small gyroradius. In reality, the electrons and ions
are pulling on each other strongly due to their opposing charges, so
you have the situation of ambipolar diffusion.
This situation has been likened to an energetic little child (the
electrons) not wanting to be pulled away from the playground (the
magnetic field) by the parents (the ions).
The ultimate rate must typically be in between the individual rates for
electrons and ions, so at least you can get some bounds from this type
of analysis.
Returns
-------
`~astropy.units.quantity.Quantity`
See Also
--------
ion_thermal_conductivity
"""
kappa_hat = _nondim_thermal_conductivity(
self.hall_e,
self.Z,
self.e_particle,
self.model,
self.field_orientation,
self.mu,
self.theta,
)
tau_e = 1 / fundamental_electron_collision_freq(
self.T_e, self.n_e, self.ion, self.coulomb_log_ei, self.V_ei
)
kappa = kappa_hat * (self.n_e * k_B**2 * self.T_e * tau_e / m_e)
return kappa
@property
@validate_quantities
def ion_viscosity(self) -> u.Quantity[u.Pa * u.s]:
r"""
Calculate the ion viscosity.
.. todo::
The ion viscosity (:math:`\eta`) of a plasma is defined by...
Notes
-----
This is the dynamic viscosity that you find for ions in the classical
plasma, similar to the viscosity of air or water or honey. The big
effect is the :math:`T^{5/2}` dependence, so as classical plasmas
get hotter they become dramatically more viscous. The ion
viscosity typically dominates over the electron viscosity.
Returns
-------
`~astropy.units.quantity.Quantity`
See Also
--------
electron_viscosity
"""
eta_hat = _nondim_viscosity(
self.hall_i,
self.Z,
self.ion,
self.model,
self.field_orientation,
self.mu,
self.theta,
)
tau_i = 1 / fundamental_ion_collision_freq(
self.T_i, self.n_i, self.ion, self.coulomb_log_ii, self.V_ii
)
common_factor = self.n_i * k_B * self.T_i * tau_i
eta1 = np.array(eta_hat) * common_factor
if not np.isclose(self.hall_i, 0, rtol=1e-8):
eta1[1:3] /= self.hall_i**2
eta1[3:] /= self.hall_i
if eta1[0].unit == eta1[2].unit == eta1[4].unit:
unit_val = eta1[0].unit
eta = eta1.value * unit_val
return eta
@property
@validate_quantities
def electron_viscosity(self) -> u.Quantity[u.Pa * u.s]:
r"""
Calculate the electron viscosity.
.. todo::
The electron viscosity (:math:`\eta`) of a plasma is defined by...
Notes
-----
This is the dynamic viscosity that you find for electrons in the
classical plasma, similar to the viscosity of air or water or honey.
The big effect is the :math:`T^{5/2}` dependence, so as classical
plasmas get hotter they become dramatically more viscous. The
ion viscosity typically dominates over the electron viscosity.
Returns
-------
`~astropy.units.quantity.Quantity`
See Also
--------
~plasmapy.formulary.braginskii.ClassicalTransport.ion_viscosity
"""
eta_hat = _nondim_viscosity(
self.hall_e,
self.Z,
self.e_particle,
self.model,
self.field_orientation,
self.mu,
self.theta,
)
tau_e = 1 / fundamental_electron_collision_freq(
self.T_e, self.n_e, self.ion, self.coulomb_log_ei, self.V_ei
)
common_factor = self.n_e * k_B * self.T_e * tau_e
if np.isclose(self.hall_e, 0, rtol=1e-8):
eta1 = (
eta_hat[0] * common_factor,
eta_hat[1] * common_factor,
eta_hat[2] * common_factor,
eta_hat[3] * common_factor,
eta_hat[4] * common_factor,
)
else:
eta1 = (
eta_hat[0] * common_factor,
eta_hat[1] * common_factor / self.hall_e**2,
eta_hat[2] * common_factor / self.hall_e**2,
eta_hat[3] * common_factor / self.hall_e,
eta_hat[4] * common_factor / self.hall_e,
)
if eta1[0].unit == eta1[2].unit == eta1[4].unit:
unit_val = eta1[0].unit
eta = (
np.array(
(
eta1[0].value,
eta1[1].value,
eta1[2].value,
eta1[3].value,
eta1[4].value,
)
)
* unit_val
)
return eta
@property
def all_variables(self) -> dict:
"""
Return all transport variables as a dictionary.
Returns
-------
dict
"""
d = {
"resistivity": self.resistivity,
"thermoelectric conductivity": self.thermoelectric_conductivity,
"electron thermal conductivity": self.electron_thermal_conductivity,
"electron viscosity": self.electron_viscosity,
}
if self.model != "spitzer":
d["ion thermal conductivity"] = self.ion_thermal_conductivity
d["ion viscosity"] = self.ion_viscosity
return d
@validate_quantities
def resistivity(
T_e,
n_e,
T_i,
n_i,
ion,
m_i=None,
Z=None,
B: u.Quantity[u.T] = 0.0 * u.T,
model="Braginskii",
field_orientation="parallel",
mu=None,
theta: Optional[float] = None,
coulomb_log_method="classical",
) -> u.Quantity[u.Ohm * u.m]:
r"""
Calculate the resistivity.
The resistivity (:math:`α`) of a plasma is defined by
.. math::
α = \frac{\hat{α}}{n_e e^2 \frac{τ_e}{m_e}}
where :math:`\hat{α}` is the non-dimensional resistivity of the plasma,
:math:`n_e` is the electron number density of the plasma,
:math:`e` is Euler's number,
:math:`τ_e` is the fundamental electron collision period of the plasma,
and :math:`m_e` is the mass of an electron.
Notes
-----
The resistivity here is defined similarly to solid conductors, and thus
represents the classical plasmas' property to resist the flow of
electrical current. The result is in units of ohm meters, so if you
assume where the current is flowing in the plasma (length and
cross-sectional area), you could calculate a DC resistance of the
plasma in ohms as resistivity × length / cross-sectional area.
Experimentalists with plasma discharges may observe different
:math:`V = IR` Ohm's law behavior than suggested by the resistance
calculated here, for reasons such as the occurrence of plasma sheath
layers at the electrodes or the plasma not satisfying the classical
assumptions.
Returns
-------
`~astropy.units.quantity.Quantity`
"""
ct = ClassicalTransport(
T_e,
n_e,
T_i,
n_i,
ion,
m_i,
Z=Z,
B=B,
model=model,
field_orientation=field_orientation,
mu=mu,
theta=theta,
coulomb_log_method=coulomb_log_method,
)
return ct.resistivity
@validate_quantities
def thermoelectric_conductivity(
T_e,
n_e,
T_i,
n_i,
ion,
m_i=None,
Z=None,
B: u.Quantity[u.T] = 0.0 * u.T,
model="Braginskii",
field_orientation="parallel",
mu=None,
theta: Optional[float] = None,
coulomb_log_method="classical",
):
r"""
Calculate the thermoelectric conductivity.
.. todo::
The thermoelectric conductivity (:math:`\hat{β}`) of a plasma is
defined by...
"""
ct = ClassicalTransport(
T_e,
n_e,
T_i,
n_i,
ion,
m_i,
Z=Z,
B=B,
model=model,
field_orientation=field_orientation,
mu=mu,
theta=theta,
coulomb_log_method=coulomb_log_method,
)
return ct.thermoelectric_conductivity
@validate_quantities
def ion_thermal_conductivity(
T_e,
n_e,
T_i,
n_i,
ion,
m_i=None,
Z=None,
B: u.Quantity[u.T] = 0.0 * u.T,
model="Braginskii",
field_orientation="parallel",
mu=None,
theta: Optional[float] = None,
coulomb_log_method="classical",
) -> u.Quantity[u.W / u.m / u.K]:
r"""
Calculate the thermal conductivity for ions.
The ion thermal conductivity (:math:`κ`) of a plasma is defined by
.. math::
κ = \hat{κ} \frac{n_i k_B^2 T_i τ_i}{m_i}
where :math:`\hat{κ}` is the non-dimensional ion thermal conductivity
of the plasma,
:math:`n_i` is the ion number density of the plasma,
:math:`k_B` is the Boltzmann constant,
:math:`T_i` is the ion temperature of the plasma,
:math:`τ_i` is the fundamental ion collision period of the plasma,
and :math:`m_i` is the mass of an ion of the plasma.
Notes
-----
This is the classical plasma ions' ability to conduct energy and heat,
defined similarly to other materials. The result is a conductivity in units
of W / m / K, so if you assume you know where the heat is flowing
(temperature gradient, cross-sectional area) you can calculate the energy
transport in watts as conductivity × cross-sectional area × temperature
gradient. In laboratory plasmas, typically the energy is flowing out of your
high-temperature plasma to something else, like the walls of your device,
and you are sad about this.
Returns
-------
`~astropy.units.quantity.Quantity`
See Also
--------
electron_thermal_conductivity
"""
ct = ClassicalTransport(
T_e,
n_e,
T_i,
n_i,
ion,
m_i,
Z=Z,
B=B,
model=model,
field_orientation=field_orientation,
mu=mu,
theta=theta,
coulomb_log_method=coulomb_log_method,
)
return ct.ion_thermal_conductivity
@validate_quantities
def electron_thermal_conductivity(
T_e,
n_e,
T_i,
n_i,
ion,
m_i=None,
Z=None,
B: u.Quantity[u.T] = 0.0 * u.T,
model="Braginskii",
field_orientation="parallel",
mu=None,
theta: Optional[float] = None,
coulomb_log_method="classical",
) -> u.Quantity[u.W / u.m / u.K]:
r"""
Calculate the thermal conductivity for electrons.
The electron thermal conductivity (:math:`κ`) of a plasma is defined by
.. math::
κ = \hat{κ} \frac{n_e k_B^2 T_e τ_e}{m_e}
where :math:`\hat{κ}` is the non-dimensional electron thermal
conductivity of the plasma,
:math:`n_e` is the electron number density of the plasma,
:math:`k_B` is the Boltzmann constant,
:math:`T_e` is the electron temperature of the plasma,
:math:`τ_e` is the fundamental electron collision period of the
plasma, and :math:`m_e` is the mass of an electron.