1C $$$$$$
2C MHP 06/02
3C SUBROUTINE DADCOEFT(DR,DT,EI,EJ,EW,NTOT,WIND1,WIND2,DJ, ! KC 2025-05-31
4 SUBROUTINE DADCOEFT(DR,DT,EI,EW,NTOT,WIND1,WIND2,DJ,
5 * * ECOD2,SUMDJ,LFIX,LOKAD)
6C 10/15/26 MHP via Claude
7C code changed to take JSON from DIMENSIONS_MOD instead of declaring
8C PARAMETER(JSON=5000) here.
9 USE DIMENSIONS_MOD
10C 10/14/26 MHP via Claude
11C code changed to convert COMMON/OVRTRN/ into OVRTRN_MOD.
12 USE OVRTRN_MOD
13C 10/14/26 MHP via Claude
14C code changed to convert COMMON/EGRIDDER/ into EGRIDDER_MOD.
15 USE EGRIDDER_MOD
16C 10/14/26 MHP via Claude
17C code changed to convert COMMON/DIFAD3/ into DIFAD3_MOD.
18 USE DIFAD3_MOD
19C 10/14/26 MHP via Claude
20C code changed to convert COMMON/DIFAD/ into DIFAD_MOD.
21 USE DIFAD_MOD
22C 10/14/26 MHP via Claude
23C code changed to convert COMMON/NMLPAR/ into NMLPAR_MOD.
24 USE NMLPAR_MOD
25C 10/20/26 MHP via Claude
26C code changed to replace implicit typing with IMPLICIT NONE and
27C explicit declarations.
28 IMPLICIT NONE
29 REAL*8 A,AA,B,C,CORR,D,DCMIX,DELJ,DELJ0,DJ,DR,DT,DT0,DW,DW2,DWI,
30 * * DWI2,DWIT,DWMAX,DWW,ECOD2,EI,EQWRST,ETHVN,ETHVP,EW,EWIT,
31 * * EWIT2,EWPREV,EWST,EWT,FACT,FACT0,FACTA,FGEOMIX,FX,FX1,FXX,
32 * * QCHIRC,QCHIRE,QQWCC,QWR,QWR2,QWRI,QWRINIT,QWRP,REQ,SUMDJ,
33 * * SUMDJ2,SUMDT,SUMJ,SUMJ2,TINY,V0,V1,V1E,V2,V3,VESN,VTHN,
34 * * VTHP,VTOT,VTOT2,W2M,WIND1,WIND2,WIND20,WM,WM0,WMI,WMINIT,
35 * * WMM,WMP,WN,WP,WSAT
36 INTEGER I,II,IWI,IWIT,IWMAX,IWW,J,K,NCUT,NM,NMAX,NN,NNN,NNNN,
37 * * NSTEP,NTOT
38 LOGICAL*4 LFIX,LOKAD
39 PARAMETER (NMAX=8000)
40C MHP 3/09 ADDED OPTION TO SCALE THE SATURATION RATE BY THE OVERTURN TIMESCALE
41C 10/13/26 MHP via Claude: removed the unused COMMON/DEUTER/ declaration
42C (no member referenced here; residue of the obsolete-option removals).
43C DIFFUSION COEFFICIENTS FOR THE TERMS INVOLVING D/DR (OMEGA)
44C (ECOD3) AND D/DR (D OMEGA/DR) (ECOD4).
45C time change of theta
46C 10/9/26 MHP via Claude
47C code changed to convert COMMON/DIFADDT/, COMMON/EGRIDCHI/, and
48C COMMON/DIFAD4/ (below) to plain local arrays: all three are declared
49C only in this file (confirmed via a codebase-wide scan), so there's
50C nothing to share via COMMON. The existing blanket SAVE statement
51C below already preserves their values across calls, same as COMMON
52C did.
53 DIMENSION ETHVN(JSON),ETHVP(JSON),EWST(JSON),EQWRST(JSON)
54C 10/12/26 MHP via Claude
55C code changed to extend COMMON/NMLPAR/ to 234 members, adding the
56C namelist variables that the physics routines read from 27 COMMON
57C blocks which also held derived or working members. Those blocks keep
58C only their non-namelist members; five of them -- NEWMX, VMULT,
59C PMMWIND, CCOUT1 and ENVGEN -- had nothing left and are gone.
60C Derivation-only namelist variables from the same blocks went to
61C COMMON/NMLBYPASS/ instead, not here.
62C
63C Declared identically in all 121 files that hold any of these members.
64C Generated from one member list, so every copy is byte-identical; the
65C linker's 'size of symbol changed' warning is the check that they are.
66C VALUES OF D CHI/DR AT THE ZONE EDGES AND ZONE CENTERS
67 DIMENSION QCHIRE(JSON),QCHIRC(JSON)
68C DEFINITION TERMS FOR THE SECOND AND THIRD DERIVATIVE
69C TERMS
70 DIMENSION FGEOMIX(JSON),VESN(JSON),REQ(JSON)
71C MHP 8/17 ADDED EXCEN, C_2 TO COMMON BLOCK FOR MATT ET AL. 2012 CENT. TERM
72C 10/13/26 MHP via Claude: removed the unused COMMON/CWIND/ declaration
73C (no member referenced here; residue of the obsolete-option removals).
74C 10/11/26 MHP via Claude
75C BUG FIX: this file reads LROSSBY and PMMSOLTAU below (the Rossby
76C scaling of the saturation threshold) but never declared
77C COMMON/PMMWIND/, so both were uninitialized locals -- LROSSBY was
78C always .FALSE. and the branch never executed, even though its
79C namelist default is .TRUE. and ~105 test/example namelists set it
80C .TRUE. explicitly. Declaring the block (same layout as mwind.f)
81C makes the namelist values actually arrive here.
82C 10/12/26 MHP via Claude
83C code changed to remove the trailing CHARACTER member AWIND from
84C COMMON/PMMWIND/. Character data does not belong in a COMMON block, and
85C this file never referenced AWIND. It is now a local of parmin.f, the
86C only routine that reads it. Being last, its removal moves no other
87C member, and the block shrinks identically in all five files.
88C COMMON/CWIND/WMAX,EXMD,EXW,EXTAU,EXR,EXM,CONSTFACTOR,STRUCTFACTOR,LJDOT0
89C G Somers 3/17, ADDING NEW TAUCZ COMMON BLOCK
90C DIMENSION EI(JSON),EW(JSON),EJ(JSON),DJ(JSON), ! KC 2025-05-31
91 DIMENSION EI(JSON),EW(JSON),DJ(JSON),
92 * * A(NMAX,10),B(NMAX),EWPREV(JSON),DWIT(50),IWIT(50),
93 * * FX1(JSON),QWR(JSON),WM(JSON),ECOD2(JSON),
94 * * EWIT(JSON),WM0(JSON),EWIT2(JSON),WMP(JSON),
95 * * QWRP(JSON),EWT(JSON),WMINIT(JSON),QWRINIT(JSON)
96 DIMENSION C(NMAX),D(NMAX),AA(NMAX,10),QQWCC(JSON)
97 SAVE
98C DCOEFT SETS UP THE COEFFICIENTS FOR THE DIFFUSION DIFFERENCE EQUATION.
99C
100C INPUT VARIABLES:
101C ECOD : DIFFUSION COEFFICIENTS AT THE EQUALLY SPACED GRID POINTS.
102C DR : GRID SPACING.
103C DT : TIMESTEP.
104C EI : RUN OF MOMENTS OF INERTIA OF EQUALLY SPACED GRID POINTS.
105C EW : RUN OF ANGULAR VELOCITY OF EQUALLY SPACED GRID POINTS.
106C NTOT : NUMBER OF EQUALLY SPACED GRID POINTS.
107C WIND1 : THE ANGULAR MOMENTUM LOSS FROM A SURFACE C.Z. COMPUTED
108C EXPLICITILY.
109C WIND2 : AS WIND1, BUT COMPUTED IMPLICITLY.
110C *NOTE: IF NOT APPLICABLE, WIND1 AND WIND2 ARE ZEROED OUT.
111C
112C OUTPUT VARIABLES :
113C THE ANGULAR VELOCITY OF SHELL I AT TIME N+1 (W(I,N+1)) IS A FUNCTION OF
114C W(I-1),W(I),AND W(I+1) AS DISCUSSED BELOW. THIS CAN BE EXPRESSED
115C AS A TRIDIAGONAL MATRIX.
116C A(I) : CONTAINS ALL TERMS INVOLVING OMEGA(I-1).
117C B(I) : CONTAINS ALL TERMS INVOLVING OMEGA(I).
118C C(I) : CONTAINS ALL TERMS INVOLVING OMEGA(I+1)
119C D(I) : THE ANGULAR VELOCITY TERMS AT THE BEGINNING OF THE TIMESTEP.
120C *NOTE: ANGULAR MOMENTUM LOSS FROM A SURFACE C.Z. IS SUBTRACTED FROM
121C THE LAST ELEMENT OF ARRAY D IF APPLICABLE.
122C
123C THE DIFFUSION EQUATION WE ARE SOLVING IS
124C dW/dT = 1/(4pi*RHO*R**2) 1/(I/M) d/dR(D*dW/dR)
125C WHERE D IS OUR DIFFUSION COEFFICIENT,W IS THE ANGULAR VELOCITY,
126C I IS THE MOMENT OF INERTIA,M IS MASS,T IS TIME,R IS RADIUS,
127C AND RHO IS DENSITY.
128C USING M = 4pi*RHO*R**2*DR THIS IS DIFFERENCED FOR SHELL I AS
129C W(I,N+1)-W(I,N)=(DT/DR)*(1/I)*(D(I+1/2)*(W(I+1,N+1)-W(I,N+1)) -
130C D(I-1/2)*(W(I,N+1)-W(I-1,N+1)))
131C WHERE INDEX N+1 REFERS TO VALUES AT THE END OF THE TIMESTEP,AND
132C INDEX N REFERS TO VALUES AT THE BEGINNING OF THE TIMESTEP.
133C THIS SYSTEM IS SUPPLEMENTED WITH APPROPRIATE BOUNDARY CONDITIONS.
134C
135C WE ARE SOLVING A 4XN SYSTEM OF EQUATIONS.
136C INITIAL DEFINITIONS:
137C OMEGA IS STORED IN THE FIRST ENTRY
138C D^2 OMEGA/DR^2 TERM IS STORED IN THE SECOND
139C D OMEGA/DR TERM IS STORED IN THE THIRD
140C D^3 OMEGA/DR^3 TERM IS STORED IN THE FOURTH
141C NOTE THAT SINCE THE DERIVATIVES ARE DEFINED IN
142C TERMS OF LOWER ORDER QUANTITIES WE DON'T NEED THE
143C START OF TIMESTEP VALUES FOR THEM.
144 NCUT = 0
145 NSTEP = 1
146 DT0 = DT
147 WIND20 = WIND2
148 TINY = 1.0D-30
149C STORE START OF TIMESTEP GRADIENTS AND
150C AVERAGED OMEGAS.
151 DO I = 2,NTOT
152 QWR(I) = QCHIRE(I)*(EW(I)-EW(I-1))/DR
153 WM0(I) = 0.5D0*(EW(I)+EW(I-1))
154 END DO
155 NM = 4*NTOT-2
156C LOOP FOR TIMESTEP CUTTING
157 5 5 CONTINUE
158 SUMDT = 0.0D0
159C STORE START OF TIMESTEP OMEGA VALUES
160 WIND2 = WIND20
161 SUMJ = 0.0D0
162 DO I = 1,NTOT
163 EWPREV(I) = EW(I)
164 EWIT(I) = EW(I)
165 EWIT2(I) = EW(I)
166 EWT(I) = EW(I)
167 SUMJ = SUMJ + EW(I)*EI(I)
168 END DO
169 DO I = 2,NTOT
170 WMP(I) = WM0(I)
171 QWRP(I) = QWR(I)
172 END DO
173 DO NNNN = 1,NSTEP
174 DT = DT0/DFLOAT(NSTEP)
175 SUMDT = SUMDT + DT
176 FXX = DT/DT0
177C LOOP FOR ITERATION ON THE D THETA/DT TERM;
178C COEFFICIENTS UPDATED ONCE PER NNN
179 DO NNN = 1,ITDIF2
180C LOOP FOR ITERATION ON THE OTHER COEFFICIENTS
181C THAT ARE FUNCTIONS OF OMEGA; UPDATED ONCE PER
182C NN.
183 LOKAD = .FALSE.
184C UPDATE JDOT TERM
185 IF(NNN.GT.1 .AND. WIND2.GT.0.0D0)THEN
186C G Somers 8/17
187C ADD ROSSBY SCALING IF DESIRED.
188 IF(LROSSBY)THEN
189 WSAT = WMAX*PMMSOLTAU/TAUCZ
190 ELSE
191 WSAT = WMAX
192 ENDIF
193C COMMENT OUT OLD WMAX STUFF
194CC MHP 3/09 IF WMAX > 1 THEN ASSUME THAT THE PARAMETER WMAX IS DEFINED BY
195CC WMAX = WMAX(SUN)*TAUCZ(SUN) AND THE SATURATION THRESHOLD WSAT = WMAX/TAUCZ(STAR)
196C IF(WMAX.GT.1.0D0)THEN
197C IF(TAUCZ.GT.1.0D0)THEN
198C WSAT = WMAX/TAUCZ
199C ELSE
200C WRITE(*,912)WMAX,TAUCZ
201C 912 FORMAT('ERROR IN WIND - TAUCZ NOT DEFINED ',1P2E12.3,'STOPPED')
202C STOP
203C ENDIF
204C ELSE
205C WSAT = WMAX
206C ENDIF
207 WP = MIN(EW(NTOT),WSAT)
208 WN = MIN(EWPREV(NTOT),WSAT)
209 WIND2 = WIND20*(WN/WP)**(EXW-1.0D0)*
210 * * (EWPREV(NTOT)/EW(NTOT))
211 ENDIF
212 DO NN = 1,ITDIF2
213C COMPUTE THE DIFFUSION COEFFICIENTS FOR
214C THE FIRST AND SECOND ORDER TERMS.
215 IF(NNNN.EQ.1)THEN
216 DO I = 2,NTOT
217 WMINIT(I) = 0.5D0*(EWST(I)+EWST(I-1))
218 QWRINIT(I) = EQWRST(I)
219 END DO
220 ELSE
221 DO I = 2,NTOT
222 WMINIT(I) = WMP(I)
223 QWRINIT(I) = QWRP(I)
224 END DO
225 ENDIF
226 QQWCC(1) = 0.0D0
227 DO I = 2,NTOT-1
228 QQWCC(I) = (EWPREV(I+1)-2.0D0*EWPREV(I)+
229 * * EWPREV(I-1))
230 END DO
231 QQWCC(NTOT) = 0.0D0
232 DO I = 2,NTOT
233 WM(I) = 0.5D0*(EWPREV(I)+EWPREV(I-1))
234 * * -0.125D0*(QQWCC(I)-QQWCC(I-1))
235C WM(I) = 0.5D0*(WM(I)+WMINIT(I))
236 WMI = 0.5D0*(EWIT2(I)+EWIT2(I-1))
237 QWR2 = QCHIRE(I)*(EWPREV(I)-EWPREV(I-1))/DR
238C QWR2 = 0.5D0*(QWR2+QWRINIT(I))
239 QWRI = QCHIRE(I)*(EWIT2(I)-EWIT2(I-1))/DR
240 IF(ABS(QWR(I)).GT.TINY)THEN
241 ESS(I) = ESS(I)*(QWR2/QWR(I))**2
242 EGSF(I) = EGSF(I)*(QWR2/QWR(I))**2
243 ENDIF
244 V1 = FW*EV0(I)*WM(I)**2*(EV1A(I)+WM(I)**2*EV1B(I))
245C VTH = FW*(ETHVN(I)*WM(I)*QWR2-ETHVP(I))/DT
246 VTHN = 0.0D0
247C VTHN = FW*ETHVN(I)*WM(I)**2/DT
248C VTHP = -FW*ETHVP(I)/DT
249C VTHP = FW/DT0*(ETHVN(I)*WMI*QWRI-ETHVP(I))
250CC VTHP0 = FW/DT0*(ETHVN(I)*WM0(I)*QWR(I)-ETHVP(I))
251CC VTHP1 = FW/DT*ETHVN(I)*(WMI*QWRI-WMP(I)*QWRP(I))
252CC IF(NSTEP.LE.2)THEN
253CC VTHP = VTHP0+VTHP1
254CC ELSE
255 VTHP = 0.0D0
256CC ENDIF
257C VTHN = FW*WM(I)*(ETHVN(I)*WM(I)-ETHVP(I)/QWR2)/DT
258C VTHN = MAX(0.0D0,VTHN)
259C SET D THETA/DT TERM TO ZERO ON THE FIRST ITERATION
260 IF(NNN.EQ.1)THEN
261C IF(NTOT.GT.1)THEN
262 VTHN=0.0D0
263 VTHP=0.0D0
264 ENDIF
265 V2 = FW*EV0(I)*WM(I)**2*(EV2A(I)+EV2B(I))+VTHN
266 V1 = V1 + VTHP
267C ECOD3(I) = 0.2D0*(V1+VTH)*FGEOM(I)
268 ECOD3(I) = 0.2D0*V1*FGEOM(I)
269 ECOD4(I) = (0.2D0*V2+ESS(I)+EGSF(I))*FGEOM(I)
270 ECOD4(I) = MAX(0.0D0,ECOD4(I))
271 END DO
272C USE THE PRIOR RUN TO CORRECT THE
273C DIFFUSION COEFFICIENTS FOR CHANGES IN OMEGA;
274C FX1 IS USED FOR THE THIRD AND FOURTH ORDER TERMS.
275 DO I = 2,NTOT
276 FX1(I) = 2.0D0*WM(I)/(EW(I)+EW(I-1))
277 END DO
278C RIGHT HAND SIDE - STARTING OMEGA RUN
279 DO I = 1,NTOT
280 II = 1 + 4*(I-1)
281 B(II) = EWT(I)
282 B(II+1) = 0.D0
283 B(II+2) = 0.D0
284 B(II+3) = 0.D0
285 D(II) = EWT(I)
286 D(II+1) = 0.D0
287 D(II+2) = 0.D0
288 D(II+3) = 0.D0
289 END DO
290C INCLUDE ANGULAR MOMENTUM LOSS
291 DELJ = -0.5D0*(WIND1+WIND2)*EI(NTOT)*FXX
292 B(4*NTOT-3) = B(4*NTOT-3)*(1.0D0+DELJ/EI(NTOT)/EWT(NTOT))
293 D(4*NTOT-3) = B(4*NTOT-3)
294C GLOBAL FACTOR FOR THE DIFFUSION COEFFICIENTS
295 FACT0 = DT/DR
296C IF LDIFAD=T, WE ARE SOLVING A COMBINED DIFFUSION/ADVECTION EQUATION.
297C THIS ADDS A TERM D/DR(RHO*R**4*V*W) TO THE ORIGINAL D/DR(RHO*R**4*
298C V*R*DW/DR) EQUATION. SINCE V DEPENDS ON OMEGA AND ITS FIRST THROUGH
299C THIRD DERIVATIVES, WE CAN EFFECTIVELY RECAST THIS AS A SET OF 4 FIRST
300C ORDER EQUATIONS.
301C FIRST SHELL BOUNDARY CONDITIONS: NO FLOW BELOW THE BOUNDARY
302C I.E. THE ANGULAR MOMENTUM TRANSPORT AT THE FIRST SHELL DOES NOT
303C DEPEND ON THE SHELLS BELOW IT.
304 FACT = FACT0/EI(1)
305 FACTA = 0.5D0*DT/EI(1)/DR
306C ZERO OUT INITIAL COEFFICIENT MATRIX
307 DO I = 1,NM
308 DO J = 1,10
309 A(I,J) = 0.0D0
310 END DO
311 END DO
312C OMEGA TERMS - ADVECTIVE
313 A(1,5) = 1.0D0 - FACTA*ECOD3(2)
314 A(1,9) = -FACTA*ECOD3(2)
315C OMEGA TERMS - DW/DR
316 A(1,7) = -FACT*QCHIRE(2)*ECOD4(2)
317C OMEGA TERMS - D2W/DR2
318C A(1,6) = -FACTA*ECOD5(2)*FX1(2)
319C FPL = EQQCOD(2)*QCHIRE(2)*FX1(2)
320 A(1,10) = -FACTA*QCHIRE(2)*ECOD5(2)*FX1(2)
321C * +0.125D0*ECOD3(2)*DR**2/FPL
322C OMEGA TERMS - D3W/DR3
323 A(1,8) = FACT*QCHIRE(2)*ECOD6(2)*FX1(2)
324C D^2W/DR^2 - SET TO ZERO AT THE LOWER BOUNDARY.
325 A(2,5) = 1.0D0
326C A(2,6) = -EQQCOD(2)*QCHIRE(2)/DR*FX1(2)
327C D OMEGA/DR TERMS
328 A(3,3) = 1.0D0/DR
329 A(3,5) = 1.0D0
330 A(3,7) = -1.0D0/DR
331C D^3W/DR^3
332C APPLY B.C. TO THE HIGHEST ORDER TERM
333C A(4,3) = EQQQCOD(1)*QCHIRE(2)/DR
334 A(4,5) = 1.0D0
335C A(4,7) = -EQQQCOD(2)*QCHIRE(2)/DR
336 A(4,9) = -1.0D0/3.0D0
337 DO II = 2,NTOT-1
338 FACT = FACT0/EI(II)
339 FACTA = 0.5D0*DT/EI(II)/DR
340 I = 1+(II-1)*4
341C OMEGA TERMS - ADVECTIVE
342 A(I,1) = FACTA*ECOD3(II)
343 A(I,5) = 1.0D0 + FACTA*(ECOD3(II)-
344 * * ECOD3(II+1))
345 A(I,9) = -FACTA*ECOD3(II+1)
346C OMEGA TERMS - DW/DR
347 A(I,3) = FACT*QCHIRE(II)*ECOD4(II)
348 A(I,7) = -FACT*QCHIRE(II+1)*ECOD4(II+1)
349C OMEGA TERMS - D2W/DR2
350C FMI = EQQCOD(II)*QCHIRE(II)*FX1(II)
351C FPL = EQQCOD(II+1)*QCHIRE(II+1)*FX1(II+1)
352 A(I,2) = FACTA*QCHIRE(II)*ECOD5(II)*FX1(II)
353C * -0.125D0*ECOD3(II)*DR**2/FMI
354 A(I,6) = FACTA*(ECOD5(II)*QCHIRE(II)*FX1(II)
355 * * - ECOD5(II+1)*QCHIRE(II+1)*FX1(II+1))
356C * +0.125D0*DR**2*(ECOD3(II)/FMI - ECOD3(II+1)/FPL)
357 A(I,10) = -FACTA*ECOD5(II+1)*QCHIRE(II+1)*FX1(II+1)
358C * +0.125D0*ECOD3(II+1)*DR**2/FPL
359C OMEGA TERMS - D3W/DR3
360 A(I,4) = FACT*ECOD6(II)*QCHIRE(II)*FX1(II)
361 A(I,8) = -FACT*ECOD6(II+1)*QCHIRE(II+1)*FX1(II+1)
362C D^2W/DR^2 COEFFICIENTS
363 A(I+1,2) = EQQCOD(II)*QCHIRE(II)/DR*FX1(II)
364 A(I+1,5) = 1.0D0
365 A(I+1,6) = -EQQCOD(II+1)*QCHIRE(II+1)/DR*FX1(II+1)
366C D W/DR COEFFICIENTS
367 A(I+2,3) = 1.0D0/DR
368 A(I+2,5) = 1.0D0
369 A(I+2,7) = -1.0D0/DR
370C D^3 W/DR^3 COEFFICIENTS
371 A(I+3,3) = QCHIRE(II)*EQQQCOD(II)/DR
372 A(I+3,5) = 1.0D0
373 A(I+3,7) = -QCHIRE(II)*EQQQCOD(II+1)/DR
374 END DO
375C LAST SHELL B.C. : SAME AS FIRST SHELL B.C.
376 FACT = FACT0/EI(NTOT)
377 FACTA = 0.5D0*DT/EI(NTOT)/DR
378 I = 4*NTOT - 3
379C A(I-1,3) = 0.0D0
380C A(I-1,7) = 0.0D0
381C A(I-1,1) = -1.0D0/3.0D0
382C ZERO OUT TERMS RELATED TO D2W/DR2 AT THE EDGES
383 A(I-4,10) = 0.0D0
384 A(5,2) = 0.0D0
385 IF(.NOT.LFIX)THEN
386C OMEGA TERMS - ADVECTIVE
387 A(I,1) = FACTA*ECOD3(NTOT)
388 A(I,5) = 1.0D0 + FACTA*ECOD3(NTOT)
389C OMEGA TERMS - DW/DR
390 A(I,3) = FACT*QCHIRE(NTOT)*ECOD4(NTOT)
391C OMEGA TERMS - D2W/DR2
392C FMI = EQQCOD(NTOT)*QCHIRE(NTOT)*FX1(NTOT)
393 A(I,2) = FACTA*QCHIRE(NTOT)*ECOD5(NTOT)*FX1(NTOT)
394C * -0.125D0*ECOD3(NTOT)*DR**2/FMI
395C A(I,6) = FACTA*QCHIRE(NTOT)*ECOD5(NTOT)*FX1(NTOT)
396C OMEGA TERMS - D3W/DR3
397 A(I,4) = FACT*QCHIRE(NTOT)*ECOD6(NTOT)
398 ELSE
399C HOLD OMEGA FIXED
400 A(I,5) = 1.0D0
401 ENDIF
402C D^2W/DR^2 COEFFICIENTS: ASSUME DW/DR = 0 ABOVE BOUNDARY
403C A(I+1,2) = EQQCOD(NTOT)*QCHIRC(NTOT)/DR*FX1(NTOT)
404 A(I+1,5) = 1.0D0
405C D W/DR COEFFICIENTS AND D^3 W/DR^3 COEFFICIENTS NOT USED,
406C SINCE THEY ARE TREATED AS ZERO ABOVE THE UNSTABLE REGION
407C STORE COEFFICIENT MATRIX TO CHECK ON THE MATRIX INVERSION
408 DO I = 1,10
409 DO J = 1,NM
410 AA(J,I) = A(J,I)
411 END DO
412 END DO
413C NOW DECOMPOSE THE BAND MATRIX. SRS. ARE FROM NUMERICAL
414C RECIPES.
415C SUBDIAGONAL ROWS
416C M1 = 4 ! KC 2025-05-31
417C SUPERDIAGONAL ROWS
418C M2 = 5 ! KC 2025-05-31
419C NM = TOTAL NUMBER OF ELEMENTS, 4 PER SHELL
420C WRITE(*,909)(ECOD3(I),ECOD4(I),ECOD5(I),ECOD6(I),
421C * EV0(I),EV1A(I),EV1B(I),EV2A(I),
422C * EV2B(I),I=1,NTOT)
423C 909 FORMAT(1P9E12.3)
424C WRITE(*,910)((A(J,I),I=1,10),J=1,NM)
425C 910 FORMAT(1P10E12.3)
426C CALL BANDW(A,NM,M1,M2,B) ! KC 2025-05-31
427 CALL BANDW(A,NM,B)
428C CHECK ON MATRIX INVERSION
429 DO I =1,NM
430 C(I) = 0.0D0
431 END DO
432 DO I = 5,10
433 C(1) = C(1) + AA(1,I)*B(I-4)
434 END DO
435 DO I = 4,10
436 C(2) = C(2) + AA(2,I)*B(I-3)
437 END DO
438 DO I = 3,10
439 C(3) = C(3) + AA(3,I)*B(I-2)
440 END DO
441 DO I = 2,10
442 C(4) = C(4) + AA(4,I)*B(I-1)
443 END DO
444 DO J = 5,NM-5
445 DO I = 1,10
446 C(J) = C(J) + AA(J,I)*B(I-5+J)
447 END DO
448 END DO
449 DO I = 1,9
450 C(NM-4) = C(NM-4)+AA(NM-4,I)*B(I+NM-9)
451 END DO
452 DO I = 1,8
453 C(NM-3) = C(NM-3)+AA(NM-3,I)*B(I+NM-8)
454 END DO
455 DO I = 1,7
456 C(NM-2) = C(NM-2)+AA(NM-2,I)*B(I+NM-7)
457 END DO
458 DO I = 1,6
459 C(NM-1) = C(NM-1)+AA(NM-1,I)*B(I+NM-6)
460 END DO
461 DO I = 1,5
462 C(NM) = C(NM)+AA(NM,I)*B(I+NM-5)
463 END DO
464C CONVERT RUN OF OMEGA TO DELTA OMEGA
465 SUMDJ = 0.0D0
466 SUMDJ2 = 0.0D0
467C DWMAX - CHANGE FROM THE PREVIOUS LOW-LEVEL ITERATION
468C (NN).
469 DWMAX = (B(1)-EWPREV(1))/EWPREV(1)
470 IWMAX = 1
471C DWW - ABSOLUTE CHANGE FROM THE INITIAL VECTOR OF OMEGA
472 DWW = (B(1)-EW(1))/EW(1)
473 IWW = 1
474C DWI - CHANGE FROM THE RESULT OF THE PRIOR MEDIUM
475C LEVEL ITERATION (NNN).
476 DWI = (B(1)-EWIT(1))/EWIT(1)
477 IWI = 1
478 DO I = 1,NTOT
479 II = 1+4*(I-1)
480 DJ(I) = (B(II)-EW(I))*EI(I)
481 SUMDJ2 = SUMDJ2 + (B(II)-EWT(I))*EI(I)
482 SUMDJ = SUMDJ + DJ(I)
483 DW = (B(II)-EWPREV(I))/EWPREV(I)
484 DW2 = (B(II)-EW(I))/EW(I)
485 DWI2 = (B(II)-EWIT(I))/EWIT(I)
486 IF(ABS(DW).GT.ABS(DWMAX))THEN
487 IWMAX = I
488 DWMAX = DW
489 ENDIF
490 IF(ABS(DW2).GT.ABS(DWW))THEN
491 IWW = I
492 DWW = DW2
493 ENDIF
494 IF(ABS(DWI2).GT.ABS(DWI))THEN
495 IWI = I
496 DWI = DWI2
497 ENDIF
498 END DO
499C DAMP OUT LARGE (SPURIOUS) CHANGES IN OMEGA
500 IF(ABS(DWMAX).GT.0.1D0)THEN
501 WRITE(*,*)NNNN,NNN,NN
502 WRITE(*,*)'CORRECTIONS TOO LARGE ',DWMAX,IWMAX
503 LOKAD = .FALSE.
504C WRITE(*,920)((AA(I,J),J=1,10),B(I),C(I),D(I),I=1,NM)
505C 920 FORMAT(1P13E10.3)
506 GOTO 950
507 ELSE IF(ABS(DWMAX).LT.1.0D-2)THEN
508 FX = 1.0D0
509 ELSE
510C FX = 0.01D0/ABS(DWMAX)
511 FX = 1.0D0
512 ENDIF
513 SUMJ2 = 0.0D0
514 DO I = 1,NTOT
515 II = 1+4*(I-1)
516 EWPREV(I) = EWPREV(I)+FX*(B(II)-EWPREV(I))
517 DJ(I) = DJ(I)*FX
518 SUMJ2 = SUMJ2+EWPREV(I)*EI(I)
519 END DO
520C ANGULAR MOMENTUM CONSERVATION ENFORCED
521 CORR = (SUMJ+DELJ)/SUMJ2
522 WRITE(*,*)SUMJ,DELJ,SUMJ2,CORR
523 SUMDJ = 0.0D0
524 DO I = 1,NTOT
525 EWPREV(I) = EWPREV(I)*CORR
526 DJ(I) = (EWPREV(I)-EW(I))*EI(I)
527 SUMDJ = SUMDJ + DJ(I)
528 END DO
529 WRITE(*,*)SUMDJ,DELJ
530C WRITE(*,912)FX,DWMAX,SUMDJ
531C 912 FORMAT(1P2E12.3)
532C WRITE(*,913)(EW(I),EWPREV(I),DJ(I),I=1,NTOT)
533C 913 FORMAT(1P6E12.3)
534 DWIT(NN) = DWMAX
535 IWIT(NN) = IWMAX
536C DETERMINE IF RUN HAS CONVERGED
537 IF(ABS(DWMAX).LT.DJOK)THEN
538 LOKAD = .TRUE.
539 GOTO 900
540 ENDIF
541 END DO
542 900 900 CONTINUE
543 WRITE(*,*)NNNN,NNN,NN
544 WRITE(*,100)DWW,IWW,(DWIT(J),IWIT(J),J=1,NN)
545 100 100 FORMAT(' MAX D(OMEGA)/OMEGA',1PE12.3,' AT PT.',I5,
546 * * ' BY ITERATION'/5(1X,E11.3,I4))
547 IF(NNN.LE.2)THEN
548 DO K = 1,NTOT
549 EWIT(K) = EWPREV(K)
550 EWIT2(K) = EWPREV(K)
551 END DO
552 ELSE
553 DO K = 1,NTOT
554 EWIT(K) = EWPREV(K)
555 EWIT2(K) = 0.5D0*EWIT(K)+0.5D0*EWPREV(K)
556 END DO
557 ENDIF
558 IF(ABS(DWI).LE.DJOK .AND. NNN.GE.2)THEN
559 GOTO 9999
560 ELSE
561 LOKAD = .FALSE.
562 ENDIF
563 END DO
564 9999 9999 CONTINUE
565 DO K = 1,NTOT
566 EWT(K) = EWPREV(K)
567 END DO
568 SUMJ = SUMJ + DELJ
569 DO K = 2,NTOT
570 WMP(K) = 0.5D0*(EWPREV(K)+EWPREV(K-1))
571 QWRP(K) = QCHIRE(K)*(EWPREV(K)-EWPREV(K-1))/DR
572 END DO
573 END DO
574 950 950 CONTINUE
575 IF(.NOT.LOKAD)THEN
576 NCUT = NCUT + 1
577 NSTEP = 2*NSTEP
578 IF(NCUT.GT.5)THEN
579 WRITE(*,*)'TIMESTEP CUT MORE THAN 5 TIMES - RUN STOPPED'
580 STOP 111
581 ELSE
582 WRITE(*,*)'TIMESTEP CUT #',NCUT,' IN DADCOEFT'
583 ENDIF
584 GOTO 5
585 ENDIF
586 WRITE(*,914)B(1),EW(1),B(2),B(3),B(4)
587 914 914 FORMAT(1P5E12.3)
588 DO I = 2,NTOT
589 II = 1 + 4*(I-1)
590 WMM = 0.5D0*(B(II)+B(II-4))
591 W2M = 0.5D0*(B(II+1)+B(II-3))
592 V0 = ECOD3(I)/FGEOM(I)
593 V1 = ECOD4(I)/FGEOM(I)*B(II-2)*QCHIRE(I)/WMM
594 V1E = 0.2D0*FW*EV0(I)*WMM*QCHIRE(I)*(EV2A(I)+EV2B(I))*B(II-2)
595 IF(ECOD4(I).LE.0.0D0)V1E = 0.0D0
596 V2 = ECOD5(I)/FGEOM(I)*QCHIRE(I)*W2M/WMM
597 V3 = ECOD6(I)/FGEOM(I)*B(II-1)*QCHIRE(I)/WMM
598 VTOT = V0+ V1 + V2 + V3
599 VTOT2 = V0 + V1E + V2 + V3
600 IF(I.LE.10 .OR. (NTOT-I).LE.10)THEN
601 WRITE(*,911)B(II),EW(I),V0,V1,V2,V3,VTOT,
602 * * B(II+1),B(II+2),B(II+3)
603 ENDIF
604 VESN(I) = 5.0D0*ABS(FC*FESC*VTOT2*REQ(I))
605 DCMIX = (VESN(I)+FC*FSSC*ESS(I)+FC*FGSFC*EGSF(I))
606 ECOD2(I) = DCMIX*FGEOMIX(I)
607C WRITE(*,1111)I,VESN(I),DCMIX,ECOD2(I),REQ(I)
608 911 911 FORMAT(1P10E12.3)
609C 1111 FORMAT(I5,1P4E12.3)
610 END DO
611 DT = DT0
612 DELJ0 = DELJ/FXX
613 WRITE(*,*)SUMDJ,DELJ0
614C IF(.NOT.LOKAD)THEN
615C SUMDJ = 0.0D0
616C DO I = 1,NTOT
617C DJ(I) = (EWPREV(I)-EW(I))*EI(I)
618C SUMDJ = SUMDJ + DJ(I)
619C END DO
620C ENDIF
621C LOKAD = .TRUE.
622 RETURN
623 END1"""Python version of dadcoeft.f (YREC 7be4133): angular-momentum transport
2by diffusion and advection (meridional circulation) over a step, as a band
3system with four unknowns per shell."""
4
5import numpy as np
6
7from pyrec import difad3_mod
8from pyrec import difad_mod
9from pyrec import dimensions_mod
10from pyrec import egridder_mod
11from pyrec import nmlpar_mod
12from pyrec import ovrtrn_mod
13from pyrec.bandw import bandw
14
15JSON = dimensions_mod.json
16NMAX = 8000
17
18# SAVE: the local arrays. The first five were COMMON blocks declared only
19# here (/EGRIDCHI/, /DIFADDT/, /DIFAD4/) and are set nowhere in the code,
20# so they hold zeros (suspected bug, see the page). ETHVN, ETHVP and QCHIRC
21# are declared and never used, and are left out.
22qchire = np.zeros(JSON + 1)
23ewst = np.zeros(JSON + 1)
24eqwrst = np.zeros(JSON + 1)
25req = np.zeros(JSON + 1)
26fgeomix = np.zeros(JSON + 1)
27vesn = np.zeros(JSON + 1)
28a = np.zeros((NMAX + 1, 10 + 1))
29aa = np.zeros((NMAX + 1, 10 + 1))
30b = np.zeros(NMAX + 1)
31c = np.zeros(NMAX + 1)
32d = np.zeros(NMAX + 1)
33ewprev = np.zeros(JSON + 1)
34dwit = np.zeros(50 + 1)
35iwit = np.zeros(50 + 1, dtype=int)
36fx1 = np.zeros(JSON + 1)
37qwr = np.zeros(JSON + 1)
38wm = np.zeros(JSON + 1)
39ewit = np.zeros(JSON + 1)
40wm0 = np.zeros(JSON + 1)
41ewit2 = np.zeros(JSON + 1)
42wmp = np.zeros(JSON + 1)
43qwrp = np.zeros(JSON + 1)
44ewt = np.zeros(JSON + 1)
45wminit = np.zeros(JSON + 1)
46qwrinit = np.zeros(JSON + 1)
47qqwcc = np.zeros(JSON + 1)
48
49
50def dadcoeft(dr: float, dt: float, ei: np.ndarray, ew: np.ndarray, ntot: int, wind1: float, wind2: float,
51 dj: np.ndarray, ecod2: np.ndarray, sumdj: float, lfix: bool, lokad: bool) -> tuple[float, float, float,
52 bool]:
53 """Transport angular momentum on the even grid over a step with
54 diffusion and advection: four unknowns per shell (Omega, Omega'',
55 Omega', Omega''') in a band system solved by BANDW, iterated on the
56 Omega-dependent coefficients, rescaled to conserve angular momentum
57 with the wind, in substeps that are halved on failure; then the
58 composition mixing coefficient.
59
60 Translates: dadcoeft.f#DADCOEFT (7be4133)
61
62 Arguments: dr, the grid spacing; dt, the step; ei, the moments of
63 inertia; ew, Omega at the start; ntot, the number of points; wind1,
64 wind2, the wind's change of Omega (start, end); dj, ecod2 (arrays,
65 set in place); sumdj (set only); lfix, a fixed surface Omega; lokad
66 (set only).
67
68 Returns (dt, wind2, sumdj, lokad): dt as passed (changed during the
69 substeps, restored at the end); wind2 as last rescaled; the total
70 change of angular momentum; and convergence (True on return, since
71 failure stops the run).
72
73 """
74
75 d3 = difad3_mod
76 ecod3 = difad_mod.ecod3
77 ecod4 = difad_mod.ecod4
78 eqqcod = egridder_mod.eqqcod
79 eqqqcod = egridder_mod.eqqqcod
80 nml = nmlpar_mod
81 ess = d3.ess
82 egsf = d3.egsf
83
84 # Initial values (Fortran lines 144–148).
85 ncut = 0
86 nstep = 1
87 dt0 = dt
88 wind20 = wind2
89 tiny = 1.0e-30
90
91 # Start-of-step gradients and averaged Omega (Fortran lines 149–154).
92 for i in range(2, ntot + 1):
93 qwr[i] = qchire[i] * (ew[i] - ew[i - 1]) / dr
94 wm0[i] = 0.5 * (ew[i] + ew[i - 1])
95
96 # Suspected bug (see the page): nm must not exceed NMAX; nothing checks
97 # it (Fortran line 155).
98 nm = 4 * ntot - 2
99
100 while True: # label 5: restart with more substeps
101 # Start-of-step values of Omega and J (Fortran lines 156–172).
102 sumdt = 0.0
103 wind2 = wind20
104 sumj = 0.0
105 for i in range(1, ntot + 1):
106 ewprev[i] = ew[i]
107 ewit[i] = ew[i]
108 ewit2[i] = ew[i]
109 ewt[i] = ew[i]
110 sumj = sumj + ew[i] * ei[i]
111 for i in range(2, ntot + 1):
112 wmp[i] = wm0[i]
113 qwrp[i] = qwr[i]
114
115 # The substeps; goto950 stands for GOTO 950 (Fortran lines
116 # 173–176).
117 goto950 = False
118 for nnnn in range(1, nstep + 1): # substeps
119 dt = dt0 / float(nstep)
120 sumdt = sumdt + dt
121 fxx = dt / dt0
122
123 # Outer iteration, meant for the d(theta)/dt term (now zero).
124 # Question (see the page): can this loop go? (Fortran lines
125 # 177–183.)
126 for nnn in range(1, nml.itdif2 + 1):
127 lokad = False
128
129 # Rescale the wind to the current surface Omega (Fortran
130 # lines 184–211).
131 if nnn > 1 and wind2 > 0.0:
132 if nml.lrossby:
133 wsat = nml.wmax * nml.pmmsoltau / ovrtrn_mod.taucz
134 else:
135 wsat = nml.wmax
136 wp = min(ew[ntot], wsat)
137 wn = min(ewprev[ntot], wsat)
138 wind2 = (wind20 * (wn / wp)**(nml.exw - 1.0)
139 * (ewprev[ntot] / ew[ntot]))
140
141 # Inner iteration on the coefficients. In Fortran, nn ends
142 # at itdif2 + 1 when the loop runs out (used in WRITE 100)
143 # (Fortran line 212).
144 nn = 0
145 while nn < nml.itdif2:
146 nn = nn + 1
147
148 # Start values for the coefficients; unused? (read only
149 # in commented-out lines) (Fortran lines 213–225).
150 if nnnn == 1:
151 for i in range(2, ntot + 1):
152 wminit[i] = 0.5 * (ewst[i] + ewst[i - 1])
153 qwrinit[i] = eqwrst[i]
154 else:
155 for i in range(2, ntot + 1):
156 wminit[i] = wmp[i]
157 qwrinit[i] = qwrp[i]
158
159 # Second differences of Omega (Fortran lines 226–231).
160 qqwcc[1] = 0.0
161 for i in range(2, ntot):
162 qqwcc[i] = ewprev[i + 1] - 2.0 * ewprev[i] + ewprev[i - 1]
163 qqwcc[ntot] = 0.0
164
165 # Coefficients from the current Omega. Suspected bug
166 # (see the page): ev0..ev2b, fgeom, ess, egsf and qchire
167 # are set by no routine (Fortran lines 232–271).
168 for i in range(2, ntot + 1):
169 wm[i] = (0.5 * (ewprev[i] + ewprev[i - 1])
170 - 0.125 * (qqwcc[i] - qqwcc[i - 1]))
171 wmi = 0.5 * (ewit2[i] + ewit2[i - 1]) # noqa: F841 (unused in the Fortran too)
172 qwr2 = qchire[i] * (ewprev[i] - ewprev[i - 1]) / dr
173 qwri = qchire[i] * (ewit2[i] - ewit2[i - 1]) / dr # noqa: F841 (unused in the Fortran too)
174 if abs(qwr[i]) > tiny:
175 ess[i] = ess[i] * (qwr2 / qwr[i])**2
176 egsf[i] = egsf[i] * (qwr2 / qwr[i])**2
177 v1 = nml.fw * d3.ev0[i] * wm[i]**2 * (d3.ev1a[i] + wm[i]**2 * d3.ev1b[i])
178 vthn = 0.0
179 vthp = 0.0
180 if nnn == 1:
181 vthn = 0.0
182 vthp = 0.0
183 v2 = nml.fw * d3.ev0[i] * wm[i]**2 * (d3.ev2a[i] + d3.ev2b[i]) + vthn
184 v1 = v1 + vthp
185 # Question (see the page): the factors 0.2 here and
186 # 5 in vesn below.
187 ecod3[i] = 0.2 * v1 * d3.fgeom[i]
188 ecod4[i] = (0.2 * v2 + ess[i] + egsf[i]) * d3.fgeom[i]
189 ecod4[i] = max(0.0, ecod4[i])
190
191 # Correction factors for Omega (Fortran lines 272–277).
192 for i in range(2, ntot + 1):
193 fx1[i] = 2.0 * wm[i] / (ew[i] + ew[i - 1])
194
195 # Right-hand side: Omega, then three zero rows per shell
196 # (Fortran lines 278–289).
197 for i in range(1, ntot + 1):
198 ii = 1 + 4 * (i - 1)
199 b[ii] = ewt[i]
200 b[ii + 1] = 0.0
201 b[ii + 2] = 0.0
202 b[ii + 3] = 0.0
203 d[ii] = ewt[i]
204 d[ii + 1] = 0.0
205 d[ii + 2] = 0.0
206 d[ii + 3] = 0.0
207
208 # The wind's loss of angular momentum in the surface row
209 # (Fortran lines 290–293).
210 delj = -0.5 * (wind1 + wind2) * ei[ntot] * fxx
211 b[4 * ntot - 3] = b[4 * ntot - 3] * (1.0 + delj / ei[ntot] / ewt[ntot])
212 d[4 * ntot - 3] = b[4 * ntot - 3]
213
214 # The band matrix, column 5 the diagonal: factors, zeros
215 # (Fortran lines 294–311).
216 fact0 = dt / dr
217 fact = fact0 / ei[1]
218 facta = 0.5 * dt / ei[1] / dr
219 for i in range(1, nm + 1):
220 for j in range(1, 11):
221 a[i, j] = 0.0
222
223 # The first shell's rows (Fortran lines 312–336).
224 a[1, 5] = 1.0 - facta * ecod3[2]
225 a[1, 9] = -facta * ecod3[2]
226 a[1, 7] = -fact * qchire[2] * ecod4[2]
227 a[1, 10] = -facta * qchire[2] * d3.ecod5[2] * fx1[2]
228 a[1, 8] = fact * qchire[2] * d3.ecod6[2] * fx1[2]
229 a[2, 5] = 1.0
230 a[3, 3] = 1.0 / dr
231 a[3, 5] = 1.0
232 a[3, 7] = -1.0 / dr
233 a[4, 5] = 1.0
234 a[4, 9] = -1.0 / 3.0
235
236 # The interior shells' rows (Fortran lines 337–374).
237 for ii in range(2, ntot):
238 fact = fact0 / ei[ii]
239 facta = 0.5 * dt / ei[ii] / dr
240 i = 1 + (ii - 1) * 4
241 a[i, 1] = facta * ecod3[ii]
242 a[i, 5] = 1.0 + facta * (ecod3[ii] - ecod3[ii + 1])
243 a[i, 9] = -facta * ecod3[ii + 1]
244 a[i, 3] = fact * qchire[ii] * ecod4[ii]
245 a[i, 7] = -fact * qchire[ii + 1] * ecod4[ii + 1]
246 a[i, 2] = facta * qchire[ii] * d3.ecod5[ii] * fx1[ii]
247 a[i, 6] = facta * (d3.ecod5[ii] * qchire[ii] * fx1[ii]
248 - d3.ecod5[ii + 1] * qchire[ii + 1] * fx1[ii + 1])
249 a[i, 10] = -facta * d3.ecod5[ii + 1] * qchire[ii + 1] * fx1[ii + 1]
250 a[i, 4] = fact * d3.ecod6[ii] * qchire[ii] * fx1[ii]
251 a[i, 8] = -fact * d3.ecod6[ii + 1] * qchire[ii + 1] * fx1[ii + 1]
252 a[i + 1, 2] = eqqcod[ii] * qchire[ii] / dr * fx1[ii]
253 a[i + 1, 5] = 1.0
254 a[i + 1, 6] = -eqqcod[ii + 1] * qchire[ii + 1] / dr * fx1[ii + 1]
255 a[i + 2, 3] = 1.0 / dr
256 a[i + 2, 5] = 1.0
257 a[i + 2, 7] = -1.0 / dr
258 a[i + 3, 3] = qchire[ii] * eqqqcod[ii] / dr
259 a[i + 3, 5] = 1.0
260 a[i + 3, 7] = -qchire[ii] * eqqqcod[ii + 1] / dr
261
262 # The last shell's rows (Fortran lines 375–406).
263 fact = fact0 / ei[ntot]
264 facta = 0.5 * dt / ei[ntot] / dr
265 i = 4 * ntot - 3
266 a[i - 4, 10] = 0.0
267 a[5, 2] = 0.0
268 if not lfix:
269 a[i, 1] = facta * ecod3[ntot]
270 a[i, 5] = 1.0 + facta * ecod3[ntot]
271 a[i, 3] = fact * qchire[ntot] * ecod4[ntot]
272 a[i, 2] = facta * qchire[ntot] * d3.ecod5[ntot] * fx1[ntot]
273 a[i, 4] = fact * qchire[ntot] * d3.ecod6[ntot]
274 else:
275 a[i, 5] = 1.0
276 a[i + 1, 5] = 1.0
277
278 # Keep the matrix, and solve (Fortran lines 407–427).
279 for i in range(1, 11):
280 for j in range(1, nm + 1):
281 aa[j, i] = a[j, i]
282 bandw(a, nm, b)
283
284 # Residual check, computed and never used; unused?
285 # (Fortran lines 428–463).
286 for i in range(1, nm + 1):
287 c[i] = 0.0
288 for i in range(5, 11):
289 c[1] = c[1] + aa[1, i] * b[i - 4]
290 for i in range(4, 11):
291 c[2] = c[2] + aa[2, i] * b[i - 3]
292 for i in range(3, 11):
293 c[3] = c[3] + aa[3, i] * b[i - 2]
294 for i in range(2, 11):
295 c[4] = c[4] + aa[4, i] * b[i - 1]
296 for j in range(5, nm - 4):
297 for i in range(1, 11):
298 c[j] = c[j] + aa[j, i] * b[i - 5 + j]
299 for i in range(1, 10):
300 c[nm - 4] = c[nm - 4] + aa[nm - 4, i] * b[i + nm - 9]
301 for i in range(1, 9):
302 c[nm - 3] = c[nm - 3] + aa[nm - 3, i] * b[i + nm - 8]
303 for i in range(1, 8):
304 c[nm - 2] = c[nm - 2] + aa[nm - 2, i] * b[i + nm - 7]
305 for i in range(1, 7):
306 c[nm - 1] = c[nm - 1] + aa[nm - 1, i] * b[i + nm - 6]
307 for i in range(1, 6):
308 c[nm] = c[nm] + aa[nm, i] * b[i + nm - 5]
309
310 # Largest relative changes: from the last iterate, from
311 # the start of the step, from the last outer iterate
312 # (Fortran lines 464–498).
313 sumdj = 0.0
314 sumdj2 = 0.0
315 dwmax = (b[1] - ewprev[1]) / ewprev[1]
316 iwmax = 1
317 dww = (b[1] - ew[1]) / ew[1]
318 iww = 1
319 dwi = (b[1] - ewit[1]) / ewit[1]
320 iwi = 1 # noqa: F841 (unused in the Fortran too)
321 for i in range(1, ntot + 1):
322 ii = 1 + 4 * (i - 1)
323 dj[i] = (b[ii] - ew[i]) * ei[i]
324 sumdj2 = sumdj2 + (b[ii] - ewt[i]) * ei[i]
325 sumdj = sumdj + dj[i]
326 dw = (b[ii] - ewprev[i]) / ewprev[i]
327 dw2 = (b[ii] - ew[i]) / ew[i]
328 dwi2 = (b[ii] - ewit[i]) / ewit[i]
329 if abs(dw) > abs(dwmax):
330 iwmax = i
331 dwmax = dw
332 if abs(dw2) > abs(dww):
333 iww = i
334 dww = dw2
335 if abs(dwi2) > abs(dwi):
336 iwi = i # noqa: F841 (unused in the Fortran too)
337 dwi = dwi2
338
339 # Corrections over 10%: cut the step; the damping FX is
340 # always 1 (Fortran lines 499–512). Question (see the
341 # page): the screen output.
342 if abs(dwmax) > 0.1:
343 print(nnnn, nnn, nn)
344 print(" CORRECTIONS TOO LARGE ", dwmax, iwmax)
345 lokad = False
346 goto950 = True
347 break
348 elif abs(dwmax) < 1.0e-2:
349 fx = 1.0
350 else:
351 fx = 1.0
352
353 # Update, then rescale to conserve angular momentum
354 # (Fortran lines 513–529).
355 sumj2 = 0.0
356 for i in range(1, ntot + 1):
357 ii = 1 + 4 * (i - 1)
358 ewprev[i] = ewprev[i] + fx * (b[ii] - ewprev[i])
359 dj[i] = dj[i] * fx
360 sumj2 = sumj2 + ewprev[i] * ei[i]
361 corr = (sumj + delj) / sumj2
362 print(sumj, delj, sumj2, corr)
363 sumdj = 0.0
364 for i in range(1, ntot + 1):
365 ewprev[i] = ewprev[i] * corr
366 dj[i] = (ewprev[i] - ew[i]) * ei[i]
367 sumdj = sumdj + dj[i]
368 print(sumdj, delj)
369
370 # History, and inner convergence (Fortran lines
371 # 534–540).
372 dwit[nn] = dwmax
373 iwit[nn] = iwmax
374 if abs(dwmax) < nml.djok:
375 lokad = True
376 break # GOTO 900
377 else:
378 nn = nn + 1 # Fortran's DO leaves nn = itdif2 + 1
379 if goto950:
380 break
381
382 # label 900. Suspected bug (see the page): dwit[itdif2 + 1]
383 # is printed unset (Fortran lines 542–546).
384 print(nnnn, nnn, nn)
385 print(f" MAX D(OMEGA)/OMEGA{dww:12.3E} AT PT.{iww:5d} BY ITERATION")
386 items = [f" {dwit[j]:11.3E}{iwit[j]:4d}" for j in range(1, nn + 1)]
387 for k in range(0, len(items), 5):
388 print("".join(items[k:k + 5]))
389
390 # The outer iterate (Fortran lines 547–557).
391 if nnn <= 2:
392 for k in range(1, ntot + 1):
393 ewit[k] = ewprev[k]
394 ewit2[k] = ewprev[k]
395 else:
396 for k in range(1, ntot + 1):
397 ewit[k] = ewprev[k]
398 ewit2[k] = 0.5 * ewit[k] + 0.5 * ewprev[k]
399
400 # Outer convergence. Suspected bugs (see the page): never
401 # with itdif2 = 1; a failed substep is not cut (Fortran
402 # lines 558–562).
403 if abs(dwi) <= nml.djok and nnn >= 2:
404 break # GOTO 9999
405 else:
406 lokad = False
407 if goto950:
408 break
409
410 # label 9999: end of the substep (Fortran lines 564–572).
411 for k in range(1, ntot + 1):
412 ewt[k] = ewprev[k]
413 sumj = sumj + delj
414 for k in range(2, ntot + 1):
415 wmp[k] = 0.5 * (ewprev[k] + ewprev[k - 1])
416 qwrp[k] = qchire[k] * (ewprev[k] - ewprev[k - 1]) / dr
417
418 # label 950: cut the step, at most 5 times (Fortran lines 574–585).
419 if not lokad:
420 ncut = ncut + 1
421 nstep = 2 * nstep
422 if ncut > 5:
423 print(" TIMESTEP CUT MORE THAN 5 TIMES - RUN STOPPED")
424 raise SystemExit("111")
425 else:
426 print(" TIMESTEP CUT #", ncut, " IN DADCOEFT")
427 continue # GOTO 5
428 break
429
430 # Fortran lines 586–587.
431 print(f"{b[1]:12.3E}{ew[1]:12.3E}{b[2]:12.3E}{b[3]:12.3E}{b[4]:12.3E}")
432
433 # Composition mixing from the final solution (Fortran lines 588–610).
434 for i in range(2, ntot + 1):
435 ii = 1 + 4 * (i - 1)
436 wmm = 0.5 * (b[ii] + b[ii - 4])
437 w2m = 0.5 * (b[ii + 1] + b[ii - 3])
438 v0 = ecod3[i] / d3.fgeom[i]
439 v1 = ecod4[i] / d3.fgeom[i] * b[ii - 2] * qchire[i] / wmm
440 v1e = 0.2 * nml.fw * d3.ev0[i] * wmm * qchire[i] * (d3.ev2a[i] + d3.ev2b[i]) * b[ii - 2]
441 if ecod4[i] <= 0.0:
442 v1e = 0.0
443 v2 = d3.ecod5[i] / d3.fgeom[i] * qchire[i] * w2m / wmm
444 v3 = d3.ecod6[i] / d3.fgeom[i] * b[ii - 1] * qchire[i] / wmm
445 vtot = v0 + v1 + v2 + v3
446 vtot2 = v0 + v1e + v2 + v3
447 if i <= 10 or (ntot - i) <= 10:
448 print("".join(f"{v:12.3E}" for v in (
449 b[ii], ew[i], v0, v1, v2, v3, vtot, b[ii + 1], b[ii + 2], b[ii + 3])))
450 vesn[i] = 5.0 * abs(nml.fc * nml.fesc * vtot2 * req[i])
451 dcmix = vesn[i] + nml.fc * nml.fssc * ess[i] + nml.fc * nml.fgsfc * egsf[i]
452 ecod2[i] = dcmix * fgeomix[i]
453
454 # Fortran lines 611–613.
455 dt = dt0
456 delj0 = delj / fxx
457 print(sumdj, delj0)
458 return dt, wind2, sumdj, lokad