1C*************************************************************
2C This routine was written by Anne A. Thoul, at the Institute
3C for Advanced Study, Princeton, NJ 08540.
4C See Thoul et al., Ap.J. 421, p. 828 (1994)
5C The subroutines LUBKSB and LUDCMP are from Numerical Recipes.
6C*************************************************************
7C This routine inverses the burgers equations.
8C
9C The system contains N equations with N unknowns.
10C The equations are: the M momentum equations,
11C the M energy equations,
12C two constraints: the current neutrality
13C the zero fluid velocity.
14C The unknowns are: the M diffusion velocities,
15C the M heat fluxes,
16C the electric field E
17C the gravitational force g.
18C
19C**************************************************
20 SUBROUTINE THDIFF(M,A,Z,X,CL,AP,AT,AX)
21C 10/20/26 MHP via Claude
22C code changed to replace implicit typing with IMPLICIT NONE and
23C explicit declarations.
24 IMPLICIT NONE
25 REAL*8 A,AC,ALPHA,AP,AT,AX,C,CC,CL,D,DELTA,GA,GAMMA,TEMP,X,XX,Y,
26 * * YY,Z
27 INTEGER I,INDX,J,L,M,MMAX,N,NMAX
28
29C The parameter M is the number of species considered.
30C
31C Fluid 1 is the hydrogen
32C Fluid 2 is the helium
33C Fluids 3 to M-1 are the heavy elements
34C Fluid M is the electrons
35C
36C The vectors A,Z and X contain the atomic mass numbers,
37C the charges (ionization), and the mass fractions, of the elements.
38C NOTE: Since M is the electron fluid, its mass and charge must be
39C A(M)=m_e/m_u
40C Z(M)=-1.
41C
42C The array CL contains the values of the Coulomb Logarithms.
43C The vector AP, AT, and array AX contains the results for the diffusion
44C coefficients.
45
46
47C INTEGER M,N,I,J,L,MMAX,NMAX
48 PARAMETER (MMAX=20,NMAX=42)
49 DIMENSION INDX(NMAX)
50 DIMENSION A(M),Z(M),X(M),AP(M),AT(M),AX(M,M),CL(M,M)
51 DIMENSION C(MMAX),XX(MMAX,MMAX),Y(MMAX,MMAX),YY(MMAX,MMAX)
52 REAL*8 K(MMAX,MMAX),NU(NMAX)
53 DIMENSION ALPHA(NMAX),GAMMA(NMAX,NMAX),DELTA(NMAX,NMAX),
54 $ $ GA(NMAX)
55 REAL*8 KO
56 SAVE
57
58C The vectors C and GRADC contain the concentrations and the
59C concentration gradients;
60C CC is the total concentration: CC=sum(C_s)
61C AC is proportional to the mass density: AC=sum(A_s C_s)
62C The arrays XX,Y,YY and K are various parameters which appear in
63C Burgers equations.
64C The vectors and arrays ALPHA, NU, GAMMA, DELTA, and GA represent
65C the "right- and left-hand-sides" of Burgers equations, and later
66C the diffusion coefficients.
67
68
69C Initialize parameters:
70
71 KO=2
72 N=2*M+2
73 DO I=1,M
74 C(I)=0.D0
75 ENDDO
76 CC=0.D0
77 AC=0.D0
78
79C Calculate concentrations from mass fractions:
80
81 TEMP=0.D0
82 DO I=1,M-1
83 TEMP=TEMP+Z(I)*X(I)/A(I)
84 ENDDO
85 DO I=1,M-1
86 C(I)=X(I)/A(I)/TEMP
87 ENDDO
88 C(M)=1.D0
89
90C Calculate CC and AC:
91
92 DO I=1,M
93 CC=CC+C(I)
94 AC=AC+A(I)*C(I)
95 ENDDO
96
97C Calculate the mass fraction of electrons:
98
99 X(M)=A(M)/AC
100
101C Calculate the coefficients of the burgers equations
102c do I = 1,M
103c DO J = 1,M
104c CL(I,J) = 2.2D0
105c END DO
106c END DO
107 DO I=1,M
108 DO J=1,M
109 XX(I,J)=A(J)/(A(I)+A(J))
110 Y(I,J)=A(I)/(A(I)+A(J))
111 YY(I,J)=3.0D0*Y(I,J)+1.3D0*XX(I,J)*A(J)/A(I)
112 K(I,J)=1.D0*CL(I,J)*
113 $ $ SQRT(A(I)*A(J)/(A(I)+A(J)))*C(I)*C(J)*
114 $ $ Z(I)**2*Z(J)**2
115 ENDDO
116 ENDDO
117
118C Write the burgers equations and the two constraints as
119C alpha_s dp + nu_s dT + sum_t(not 2 or M) gamma_st dC_t
120C = sum_t delta_st w_t
121
122 DO I=1,M
123 ALPHA(I)=C(I)/CC
124 NU(I)=0.D0
125 DO J=1,M
126 GAMMA(I,J)=0.D0
127 ENDDO
128 DO J=1,M
129 IF ((J.NE.2).AND.(J.NE.M)) THEN
130 GAMMA(I,J)=-C(J)/CC+C(2)/CC*Z(J)*C(J)/Z(2)/C(2)
131 IF (J.EQ.I) THEN
132 GAMMA(I,J)=GAMMA(I,J)+1.D0
133 ENDIF
134 IF (I.EQ.2) THEN
135 GAMMA(I,J)=GAMMA(I,J)-Z(J)*C(J)/Z(2)/C(2)
136 ENDIF
137 GAMMA(I,J)=GAMMA(I,J)*C(I)/CC
138 ENDIF
139 ENDDO
140
141 DO J=M+1,N
142 GAMMA(I,J)=0.D0
143 ENDDO
144 ENDDO
145
146 DO I=M+1,N-2
147 ALPHA(I)=0.D0
148 NU(I)=2.5D0*C(I-M)/CC
149 DO J=1,N
150 GAMMA(I,J)=0.D0
151 ENDDO
152 ENDDO
153
154 ALPHA(N-1)=0.D0
155 NU(N-1)=0
156 DO J=1,N
157 GAMMA(N-1,J)=0.D0
158 ENDDO
159
160 ALPHA(N)=0.D0
161 NU(N)=0
162 DO J=1,N
163 GAMMA(N,J)=0.D0
164 ENDDO
165
166 DO I=1,N
167 DO J=1,N
168 DELTA(I,J)=0.D0
169 ENDDO
170 ENDDO
171
172 DO I=1,M
173 DO J=1,M
174 IF (J.EQ.I) THEN
175 DO L=1,M
176 IF(L.NE.I) THEN
177 DELTA(I,J)=DELTA(I,J)-K(I,L)
178 ENDIF
179 ENDDO
180 ELSE
181 DELTA(I,J)=K(I,J)
182 ENDIF
183 ENDDO
184
185 DO J=M+1,N-2
186 IF(J-M.EQ.I) THEN
187 DO L=1,M
188 IF (L.NE.I) THEN
189 DELTA(I,J)=DELTA(I,J)+0.6D0*XX(I,L)*K(I,L)
190 ENDIF
191 ENDDO
192 ELSE
193 DELTA(I,J)=-0.6D0*Y(I,J-M)*K(I,J-M)
194 ENDIF
195 ENDDO
196
197 DELTA(I,N-1)=C(I)*Z(I)
198
199 DELTA(I,N)=-C(I)*A(I)
200 ENDDO
201
202 DO I=M+1,N-2
203 DO J=1,M
204 IF (J.EQ.I-M) THEN
205 DO L=1,M
206 IF (L.NE.I-M) THEN
207 DELTA(I,J)=DELTA(I,J)+1.5D0*XX(I-M,L)*K(I-M,L)
208 ENDIF
209 ENDDO
210 ELSE
211 DELTA(I,J)=-1.5D0*XX(I-M,J)*K(I-M,J)
212 ENDIF
213 ENDDO
214
215 DO J=M+1,N-2
216 IF (J-M.EQ.I-M) THEN
217 DO L=1,M
218 IF (L.NE.I-M) THEN
219 DELTA(I,J)=DELTA(I,J)-Y(I-M,L)*K(I-M,L)*
220 $ $ (1.6D0*XX(I-M,L)+YY(I-M,L))
221 ENDIF
222 ENDDO
223 DELTA(I,J)=DELTA(I,J)-0.8D0*K(I-M,I-M)
224 ELSE
225 DELTA(I,J)=2.7D0*K(I-M,J-M)*XX(I-M,J-M)*Y(I-M,J-M)
226 ENDIF
227 ENDDO
228
229 DELTA(I,N-1)=0.D0
230
231 DELTA(I,N)=0.D0
232 ENDDO
233
234 DO J=1,M
235 DELTA(N-1,J)=C(J)*Z(J)
236 ENDDO
237 DO J=M+1,N
238 DELTA(N-1,J)=0.D0
239 ENDDO
240
241 DO J=1,M
242 DELTA(N,J)=C(J)*A(J)
243 ENDDO
244 DO J=M+1,N
245 DELTA(N,J)=0.D0
246 ENDDO
247c WRITE(*,911)((DELTA(II,JJ),II=1,N),JJ=1,N),(C(JJ),JJ=1,M)
248c911 FORMAT(1P10E10.2)
249
250
251C Inverse the system for each possible right-hand-side, i.e.,
252C if alpha is the r.h.s., we obtain the coefficient A_p
253C if nu ---------------------------------------- A_T
254C if gamma(i,j) ----------------------------------- A_Cj
255C
256C If I=1, we obtain the hydrogen diffusion velocity
257C If I=2, ------------- helium ------------------
258C If I=3,M-1, --------- heavy element -------------
259C If I=M, ------------- electrons -----------------
260C For I=M,2M, we get the heat fluxes
261C For I=N-1, we get the electric field
262C For I=N, we get the gravitational force g
263
264 CALL LUDCMP(DELTA,N,NMAX,INDX,D)
265
266 CALL LUBKSB(DELTA,N,NMAX,INDX,ALPHA)
267 CALL LUBKSB(DELTA,N,NMAX,INDX,NU)
268 DO J=1,N
269 DO I=1,N
270 GA(I)=GAMMA(I,J)
271 ENDDO
272 CALL LUBKSB(DELTA,N,NMAX,INDX,GA)
273 DO I=1,N
274 GAMMA(I,J)=GA(I)
275 ENDDO
276 ENDDO
277
278C The results for the coefficients must be multiplied by p/K_0:
279
280 DO I=1,M
281 ALPHA(I)=ALPHA(I)*KO*AC*CC
282 NU(I)=NU(I)*KO*AC*CC
283 DO J=1,M
284 GAMMA(I,J)=GAMMA(I,J)*KO*AC*CC
285 ENDDO
286 ENDDO
287
288 DO I=1,M
289 AP(I)=ALPHA(I)
290 AT(I)=NU(I)
291 DO J=1,M
292 AX(I,J)=GAMMA(I,J)
293 ENDDO
294 ENDDO
295
296
297 RETURN
298
299 END
1"""Python version of thdiff.f (YREC 7be4133): Burgers' equations for the
2diffusion of the species in a fully ionised plasma (Thoul et al. 1994)."""
3
4import math
5
6import numpy as np
7
8from pyrec.lubksb import lubksb
9from pyrec.ludcmp import ludcmp
10
11MMAX = 20
12NMAX = 42
13
14
15def thdiff(m: int, a: np.ndarray, z: np.ndarray, x: np.ndarray, cl: np.ndarray, ap: np.ndarray, at: np.ndarray,
16 ax: np.ndarray) -> None:
17 """Solve Burgers' equations (Thoul, Bahcall & Loeb 1994) for the
18 coefficients of the pressure, temperature and concentration gradients
19 in each species' diffusion velocity.
20
21 Translates: thdiff.f#THDIFF (7be4133)
22
23 Arguments: m, the number of species (1 hydrogen, 2 helium, 3..m-1 heavy
24 elements, m the electrons); a, z, x, their atomic masses, charges and
25 mass fractions (index 0 unused); cl[s, t], the Coulomb logarithms; ap,
26 at and ax[s, t], set in place. x[m] is overwritten with the electrons'
27 mass fraction. None is returned.
28
29 """
30
31 # Work arrays (Fortran lines 48–56).
32 # Suspected bug (see the page): no check that m <= MMAX.
33 indx = np.zeros(NMAX + 1, dtype=int)
34 c = np.zeros(MMAX + 1)
35 xx = np.zeros((MMAX + 1, MMAX + 1))
36 y = np.zeros((MMAX + 1, MMAX + 1))
37 yy = np.zeros((MMAX + 1, MMAX + 1))
38 k = np.zeros((MMAX + 1, MMAX + 1))
39 nu = np.zeros(NMAX + 1)
40 alpha = np.zeros(NMAX + 1)
41 gamma = np.zeros((NMAX + 1, NMAX + 1))
42 delta = np.zeros((NMAX + 1, NMAX + 1))
43 ga = np.zeros(NMAX + 1)
44
45 # Initialize parameters; concentrations, normalised to the electrons
46 # (Fortran lines 69–95).
47 ko = 2.0
48 n = 2 * m + 2
49 for i in range(1, m + 1):
50 c[i] = 0.0
51 cc = 0.0
52 ac = 0.0
53 temp = 0.0
54 for i in range(1, m):
55 temp = temp + z[i] * x[i] / a[i]
56 for i in range(1, m):
57 c[i] = x[i] / a[i] / temp
58 c[m] = 1.0
59 for i in range(1, m + 1):
60 cc = cc + c[i]
61 ac = ac + a[i] * c[i]
62
63 # The electrons' mass fraction, written into the caller's x[m] (Fortran
64 # lines 97–99).
65 x[m] = a[m] / ac
66
67 # Mass ratios and collision coefficients (Fortran lines 101–116).
68 for i in range(1, m + 1):
69 for j in range(1, m + 1):
70 xx[i, j] = a[j] / (a[i] + a[j])
71 y[i, j] = a[i] / (a[i] + a[j])
72 yy[i, j] = 3.0 * y[i, j] + 1.3 * xx[i, j] * a[j] / a[i]
73 k[i, j] = (1.0 * cl[i, j]
74 * math.sqrt(a[i] * a[j] / (a[i] + a[j])) * c[i] * c[j]
75 * z[i]**2 * z[j]**2)
76
77 # Right-hand sides: alpha (pressure), nu (temperature), gamma
78 # (concentrations) (Fortran lines 118–164).
79 for i in range(1, m + 1):
80 alpha[i] = c[i] / cc
81 nu[i] = 0.0
82 for j in range(1, m + 1):
83 gamma[i, j] = 0.0
84 for j in range(1, m + 1):
85 if j != 2 and j != m:
86 gamma[i, j] = -c[j] / cc + c[2] / cc * z[j] * c[j] / z[2] / c[2]
87 if j == i:
88 gamma[i, j] = gamma[i, j] + 1.0
89 if i == 2:
90 gamma[i, j] = gamma[i, j] - z[j] * c[j] / z[2] / c[2]
91 gamma[i, j] = gamma[i, j] * c[i] / cc
92 for j in range(m + 1, n + 1):
93 gamma[i, j] = 0.0
94 for i in range(m + 1, n - 1):
95 alpha[i] = 0.0
96 nu[i] = 2.5 * c[i - m] / cc
97 for j in range(1, n + 1):
98 gamma[i, j] = 0.0
99 alpha[n - 1] = 0.0
100 nu[n - 1] = 0.0
101 for j in range(1, n + 1):
102 gamma[n - 1, j] = 0.0
103 alpha[n] = 0.0
104 nu[n] = 0.0
105 for j in range(1, n + 1):
106 gamma[n, j] = 0.0
107
108 # The matrix delta (Fortran lines 166–246).
109 for i in range(1, n + 1):
110 for j in range(1, n + 1):
111 delta[i, j] = 0.0
112 for i in range(1, m + 1): # momentum equations
113 for j in range(1, m + 1):
114 if j == i:
115 for l in range(1, m + 1):
116 if l != i:
117 delta[i, j] = delta[i, j] - k[i, l]
118 else:
119 delta[i, j] = k[i, j]
120 for j in range(m + 1, n - 1):
121 if j - m == i:
122 for l in range(1, m + 1):
123 if l != i:
124 delta[i, j] = delta[i, j] + 0.6 * xx[i, l] * k[i, l]
125 else:
126 delta[i, j] = -0.6 * y[i, j - m] * k[i, j - m]
127 delta[i, n - 1] = c[i] * z[i]
128 delta[i, n] = -c[i] * a[i]
129 for i in range(m + 1, n - 1): # heat-flow equations
130 for j in range(1, m + 1):
131 if j == i - m:
132 for l in range(1, m + 1):
133 if l != i - m:
134 delta[i, j] = delta[i, j] + 1.5 * xx[i - m, l] * k[i - m, l]
135 else:
136 delta[i, j] = -1.5 * xx[i - m, j] * k[i - m, j]
137 for j in range(m + 1, n - 1):
138 if j - m == i - m:
139 for l in range(1, m + 1):
140 if l != i - m:
141 delta[i, j] = (delta[i, j] - y[i - m, l] * k[i - m, l]
142 * (1.6 * xx[i - m, l] + yy[i - m, l]))
143 delta[i, j] = delta[i, j] - 0.8 * k[i - m, i - m]
144 else:
145 delta[i, j] = (2.7 * k[i - m, j - m] * xx[i - m, j - m]
146 * y[i - m, j - m])
147 delta[i, n - 1] = 0.0
148 delta[i, n] = 0.0
149 for j in range(1, m + 1): # current neutrality
150 delta[n - 1, j] = c[j] * z[j]
151 for j in range(m + 1, n + 1):
152 delta[n - 1, j] = 0.0
153 for j in range(1, m + 1): # zero mass flow
154 delta[n, j] = c[j] * a[j]
155 for j in range(m + 1, n + 1):
156 delta[n, j] = 0.0
157
158 # Factorise once, solve for each right-hand side (Fortran lines
159 # 251–276).
160 d = 0.0
161 d = ludcmp(delta, n, NMAX, indx, d)
162 lubksb(delta, n, NMAX, indx, alpha)
163 lubksb(delta, n, NMAX, indx, nu)
164 for j in range(1, n + 1):
165 for i in range(1, n + 1):
166 ga[i] = gamma[i, j]
167 lubksb(delta, n, NMAX, indx, ga)
168 for i in range(1, n + 1):
169 gamma[i, j] = ga[i]
170
171 # The normalisation (Fortran lines 278–286).
172 # Question (see the page): the factor ko*ac*cc against the comment's p/K0.
173 for i in range(1, m + 1):
174 alpha[i] = alpha[i] * ko * ac * cc
175 nu[i] = nu[i] * ko * ac * cc
176 for j in range(1, m + 1):
177 gamma[i, j] = gamma[i, j] * ko * ac * cc
178
179 # The results (Fortran lines 288–294).
180 for i in range(1, m + 1):
181 ap[i] = alpha[i]
182 at[i] = nu[i]
183 for j in range(1, m + 1):
184 ax[i, j] = gamma[i, j]