1C $$$$$$
2 SUBROUTINE WCZIMP(HD,HJM,HR,HS,HS2,ISTART,IEND,ETA2,HI,OMEGA,
3 * * QIW,R0,M)
4C 10/15/26 MHP via Claude
5C code changed to take JSON from DIMENSIONS_MOD instead of declaring
6C PARAMETER(JSON=5000) here.
7 USE DIMENSIONS_MOD
8C 10/14/26 MHP via Claude
9C code changed to convert COMMON/NMLPAR/ into NMLPAR_MOD.
10 USE NMLPAR_MOD
11C 10/14/26 MHP via Claude
12C code changed to convert COMMON/CONSTANTS/ into CONSTANTS_MOD.
13 USE CONSTANTS_MOD
14C 10/20/26 MHP via Claude
15C code changed to replace implicit typing with IMPLICIT NONE and
16C explicit declarations.
17 IMPLICIT NONE
18 REAL*8 CJNEW,CJTOT,CMTOT,ETA2,HD,HI,HJM,HR,HS,HS2,OMEGA,QIW,R0,W0
19 INTEGER IEND,ISTART,J,JEND,JSTART,M
20
21C 10/12/26 MHP via Claude
22C code changed to extend COMMON/NMLPAR/ to 234 members, adding the
23C namelist variables that the physics routines read from 27 COMMON
24C blocks which also held derived or working members. Those blocks keep
25C only their non-namelist members; five of them -- NEWMX, VMULT,
26C PMMWIND, CCOUT1 and ENVGEN -- had nothing left and are gone.
27C Derivation-only namelist variables from the same blocks went to
28C COMMON/NMLBYPASS/ instead, not here.
29C
30C Declared identically in all 121 files that hold any of these members.
31C Generated from one member list, so every copy is byte-identical; the
32C linker's 'size of symbol changed' warning is the check that they are.
33C 9/25/26 MHP via Claude
34C code changed to merge COMMON/CONST/, COMMON/CONST1/, COMMON/CONST2/,
35C and COMMON/CONST3/ into a single COMMON/CONSTANTS/
36 DIMENSION HD(JSON),HJM(JSON),HR(JSON),HS(JSON),HS2(JSON),
37 * * ETA2(JSON),HI(JSON),OMEGA(JSON),QIW(JSON),R0(JSON)
38 SAVE
39
40C JNT 2025/09/03 copy of 2025/05/14 TO MAKE THE CODE ENFORCE
41C SPECIFIC ROTATION PROFILES
42
43C JNT 2025/09/03 COPY OF 2015/05/07 ADD IEND.LT.M TO ENFORCE SB
44C ROTATION IN CONVECTIVE ZONES THAT ARE NOT THE SURFACE CONVECTIVE
45C ZONE EVEN IF WALPCZ IS TURNED ON (I.E. WALPCZ NOW ONLY AFFECTS
46C SURFACE CONVECTION ZONES)
47C JVS 2026/02/13: REVERTED GT TO GE
48 IF((WALPCZ.GE.0.0D0) .OR. (LSOLID) .OR. (IMPJMOD.EQ.1) .OR. (IEND.LT.M)) THEN
49C SOLID BODY ROTATION IN CONVECTIVE REGIONS.
50 CALL SOLID(HD,HJM,HR,HS,HS2,ISTART,IEND,ETA2,HI,OMEGA,
51 * * QIW,R0,M)
52C JNT 2025/09/03 COPY OF 2015/05/14 ADD OPTION TO MAKE EVERYTHING
53C BELOW THE SURFACE CONVECTION ZONE ROTATE AS A SOLID BODY,
54C DETACHED FROM WHAT IS HAPPENING IN THE CONVECTION ZONE
55 ELSE IF(IMPJMOD.EQ.2)THEN
56 CJTOT = HJM(ISTART)*HS2(ISTART)
57 CMTOT = DEXP(CLN*WALPCZ*HR(ISTART))*HI(ISTART)
58 DO 30 J = ISTART+1,IEND
59 CJTOT = CJTOT + HJM(J)*HS2(J)
60 CMTOT = CMTOT + DEXP(CLN*WALPCZ*HR(J))*HI(J)
61 30 30 CONTINUE
62
63C ASSIGN NEW RUN OF J/M IN THE C.Z. AND FIND THE NEW RUN OF OMEGA.
64 W0 = CJTOT/CMTOT
65 DO 31 J = ISTART,IEND
66 OMEGA(J) = W0*DEXP(CLN*WALPCZ*HR(J))
67 HJM(J) = OMEGA(J)*HI(J)/HS2(J)
68 JSTART = J
69 JEND = J
70 CALL SOLID(HD,HJM,HR,HS,HS2,JSTART,JEND,ETA2,HI,
71 * * OMEGA,QIW,R0,M)
72 31 31 CONTINUE
73 IF (ISTART.GT.1) THEN
74 CALL SOLID(HD,HJM,HR,HS,HS2,1,ISTART-1,ETA2,HI,
75 * * OMEGA,QIW,R0,M)
76 ENDIF
77C JNT 2025/09/04 REPLICATING 2015/05/14 ADD OPTION TO MAKE
78C EVERYTHING BELOW THE SURFACE CONVECTION ZONE ROTATE AS A
79C SOLID BODY AT THE RATE OF THE BASE OF THE CONVECTION ZONE.
80 ELSE IF(IMPJMOD.EQ.3) THEN
81 CJTOT = HJM(1)*HS2(1)
82 CMTOT = DEXP(CLN*WALPCZ*HR(ISTART))*HI(1)
83 IF (ISTART.GT.1) THEN
84 DO 32 J = 2,ISTART
85 CJTOT = CJTOT + HJM(J)*HS2(J)
86 CMTOT = CMTOT + DEXP(CLN*WALPCZ*HR(ISTART))*HI(J)
87 32 32 CONTINUE
88 ENDIF
89 DO 33 J = (ISTART+1),IEND
90 CJTOT = CJTOT + HJM(J)*HS2(J)
91 CMTOT = CMTOT + DEXP(CLN*WALPCZ*HR(J))*HI(J)
92 33 33 CONTINUE
93C ASSIGN NEW RUN OF J/M IN THE C.Z. AND FIND THE NEW RUN OF OMEGA.
94
95 W0 = CJTOT/CMTOT
96 DO 34 J = ISTART,IEND
97 OMEGA(J) = W0*DEXP(CLN*WALPCZ*HR(J))
98 HJM(J) = OMEGA(J)*HI(J)/HS2(J)
99 JSTART = J
100 JEND = J
101 CALL SOLID(HD,HJM,HR,HS,HS2,JSTART,JEND,ETA2,HI,
102 * * OMEGA,QIW,R0,M)
103 34 34 CONTINUE
104 IF (ISTART.GT.1) THEN
105 DO 35 J = 1,(ISTART-1)
106 OMEGA(J) = OMEGA(ISTART)
107 HJM(J) = OMEGA(J)*HI(J)/HS2(J)
108 35 35 CONTINUE
109 CALL SOLID(HD,HJM,HR,HS,HS2,1,ISTART-1,ETA2,HI,
110 * * OMEGA,QIW,R0,M)
111 ENDIF
112
113
114
115 ELSE IF((WALPCZ.LE.-2.0D0) .AND. (IMPJMOD.EQ.0))THEN
116C CONSTANT SPECIFIC ANGULAR MOMENTUM PER UNIT MASS IN THE C.Z.
117C FIND TOTAL MASS AND ANGULAR MOMENTUM OF C.Z.
118 CJTOT = HJM(ISTART)*HS2(ISTART)
119 CMTOT = HS2(ISTART)
120 DO 36 J = ISTART+1,IEND
121 CJTOT = CJTOT + HJM(J)*HS2(J)
122 CMTOT = CMTOT + HS2(J)
123 36 36 CONTINUE
124C ASSIGN NEW RUN OF J/M IN THE C.Z. AND FIND THE NEW RUN OF OMEGA.
125 CJNEW = CJTOT/CMTOT
126 DO 40 J = ISTART,IEND
127 HJM(J) = CJNEW
128 OMEGA(J) = CJNEW*HS2(J)/HI(J)
129 JSTART = J
130 JEND = J
131 CALL SOLID(HD,HJM,HR,HS,HS2,JSTART,JEND,ETA2,HI,
132 * * OMEGA,QIW,R0,M)
133 40 40 CONTINUE
134 ELSE
135C GENERAL LAW FOR OMEGA IN C.Z.: OMEGA = C*R**WALPCZ,WHERE C IS A CONSTANT
136C FOR THE ENTIRE C.Z. IF THIS HOLDS, THE RUN OF J/M CAN BE FOUND BY
137C SOLVING FOR THE CONSTANT BY REQUIRING THAT THE TOTAL J OF THE C.Z. BE
138C CONSERVED AND THEN USING J/M=C*R**WALPCZ*(MOMENT OF INERTIA PER UNIT
139C MASS).
140C FIND TOTAL MASS AND ANGULAR MOMENTUM OF C.Z.
141 CJTOT = HJM(ISTART)*HS2(ISTART)
142 CMTOT = DEXP(CLN*WALPCZ*HR(ISTART))*HI(ISTART)
143 DO 50 J = ISTART+1,IEND
144 CJTOT = CJTOT + HJM(J)*HS2(J)
145 CMTOT = CMTOT + DEXP(CLN*WALPCZ*HR(J))*HI(J)
146 50 50 CONTINUE
147C ASSIGN NEW RUN OF J/M IN THE C.Z. AND FIND THE NEW RUN OF OMEGA.
148 W0 = CJTOT/CMTOT
149 DO 60 J = ISTART,IEND
150 OMEGA(J) = W0*DEXP(CLN*WALPCZ*HR(J))
151 HJM(J) = OMEGA(J)*HI(J)/HS2(J)
152 JSTART = J
153 JEND = J
154 CALL SOLID(HD,HJM,HR,HS,HS2,JSTART,JEND,ETA2,HI,
155 * * OMEGA,QIW,R0,M)
156 60 60 CONTINUE
157 ENDIF
158 RETURN
159 END
1"""Python version of wczimp.f (YREC 7be4133): the rotation of a convection
2zone at fixed angular momentum, with options to impose a rotation profile
3on the interior below the surface convection zone."""
4
5import math
6import numpy as np
7
8from pyrec import constants_mod
9from pyrec import nmlpar_mod
10from pyrec.solid import solid
11
12
13def wczimp(hd: np.ndarray, hjm: np.ndarray, hr: np.ndarray, hs: np.ndarray, hs2: np.ndarray, istart: int, iend: int,
14 eta2: np.ndarray, hi: np.ndarray, omega: np.ndarray, qiw: np.ndarray, r0: np.ndarray, m: int) -> None:
15 """Set the rotation of the convection zone istart..iend at fixed total
16 angular momentum: solid body, constant specific angular momentum, or
17 Omega = W0 * r**WALPCZ; IMPJMOD = 2 or 3 also makes the interior below
18 the surface zone a solid body, decoupled from or coupled to the zone.
19
20 Translates: wczimp.f#WCZIMP (7be4133)
21
22 Arguments: the model's arrays hd, hjm (specific angular momentum), hr
23 (log radius), hs, hs2 (shell masses), eta2, hi (moments of inertia),
24 omega, qiw, r0; the zone's first and last shells istart, iend; the
25 number of shells m. hjm, omega, hi, qiw, eta2 and r0 are updated in
26 place (through solid). Nothing is returned.
27
28 """
29
30 n = nmlpar_mod
31 cln = constants_mod.cln
32 walpcz = n.walpcz
33
34 # GE, not GT: WALPCZ = 0 is solid-body rotation (JVS 2026/02/13)
35 # (Fortran lines 47–51).
36 # Question (see the page): IMPJMOD = 2 and 3 are reached only when
37 # WALPCZ < 0, since this test comes first.
38 if walpcz >= 0.0 or n.lsolid or n.impjmod == 1 or iend < m:
39 # Solid-body rotation in convective regions.
40 solid(hd, hjm, hr, hs, hs2, istart, iend, eta2, hi, omega, qiw,
41 r0, m)
42
43 elif n.impjmod == 2:
44 # The interior below the surface zone rotates as a solid body,
45 # detached from the convection zone (Fortran lines 52–76).
46 # Question (see the page): the interior's moments of inertia are
47 # those on entry.
48 cjtot = hjm[istart] * hs2[istart]
49 cmtot = math.exp(cln * walpcz * hr[istart]) * hi[istart]
50 for j in range(istart + 1, iend + 1): # label 30
51 cjtot = cjtot + hjm[j] * hs2[j]
52 cmtot = cmtot + math.exp(cln * walpcz * hr[j]) * hi[j]
53 w0 = cjtot / cmtot
54 for j in range(istart, iend + 1): # label 31
55 omega[j] = w0 * math.exp(cln * walpcz * hr[j])
56 hjm[j] = omega[j] * hi[j] / hs2[j]
57 solid(hd, hjm, hr, hs, hs2, j, j, eta2, hi, omega, qiw, r0, m)
58 if istart > 1:
59 solid(hd, hjm, hr, hs, hs2, 1, istart - 1, eta2, hi, omega,
60 qiw, r0, m)
61
62 elif n.impjmod == 3:
63 # The interior rotates as a solid body at the rate of the zone's
64 # base, sharing one angular-momentum budget with the zone (Fortran
65 # lines 77–111).
66 rbase = math.exp(cln * walpcz * hr[istart])
67 cjtot = hjm[1] * hs2[1]
68 cmtot = rbase * hi[1]
69 if istart > 1:
70 for j in range(2, istart + 1): # label 32
71 cjtot = cjtot + hjm[j] * hs2[j]
72 cmtot = cmtot + rbase * hi[j]
73 for j in range(istart + 1, iend + 1): # label 33
74 cjtot = cjtot + hjm[j] * hs2[j]
75 cmtot = cmtot + math.exp(cln * walpcz * hr[j]) * hi[j]
76 w0 = cjtot / cmtot
77 for j in range(istart, iend + 1): # label 34
78 omega[j] = w0 * math.exp(cln * walpcz * hr[j])
79 hjm[j] = omega[j] * hi[j] / hs2[j]
80 solid(hd, hjm, hr, hs, hs2, j, j, eta2, hi, omega, qiw, r0, m)
81 if istart > 1:
82 for j in range(1, istart): # label 35
83 omega[j] = omega[istart]
84 hjm[j] = omega[j] * hi[j] / hs2[j]
85 # Question (see the page): SOLID may change the interior's
86 # Omega again.
87 solid(hd, hjm, hr, hs, hs2, 1, istart - 1, eta2, hi, omega,
88 qiw, r0, m)
89
90 elif walpcz <= -2.0 and n.impjmod == 0:
91 # Constant specific angular momentum in the convection zone
92 # (Fortran lines 115–133).
93 cjtot = hjm[istart] * hs2[istart]
94 cmtot = hs2[istart]
95 for j in range(istart + 1, iend + 1): # label 36
96 cjtot = cjtot + hjm[j] * hs2[j]
97 cmtot = cmtot + hs2[j]
98 cjnew = cjtot / cmtot
99 for j in range(istart, iend + 1): # label 40
100 hjm[j] = cjnew
101 omega[j] = cjnew * hs2[j] / hi[j]
102 solid(hd, hjm, hr, hs, hs2, j, j, eta2, hi, omega, qiw, r0, m)
103
104 else:
105 # General law Omega = W0 * r**WALPCZ in the convection zone, W0 set
106 # by conserving the zone's total angular momentum (Fortran lines
107 # 134–156).
108 cjtot = hjm[istart] * hs2[istart]
109 cmtot = math.exp(cln * walpcz * hr[istart]) * hi[istart]
110 for j in range(istart + 1, iend + 1): # label 50
111 cjtot = cjtot + hjm[j] * hs2[j]
112 cmtot = cmtot + math.exp(cln * walpcz * hr[j]) * hi[j]
113 w0 = cjtot / cmtot
114 for j in range(istart, iend + 1): # label 60
115 omega[j] = w0 * math.exp(cln * walpcz * hr[j])
116 hjm[j] = omega[j] * hi[j] / hs2[j]
117 solid(hd, hjm, hr, hs, hs2, j, j, eta2, hi, omega, qiw, r0, m)