Skip to content

Commit be120da

Browse files
committed
gauge/wflow: gaugeFlow learns 2N RK
1 parent 95b1398 commit be120da

File tree

1 file changed

+190
-1
lines changed

1 file changed

+190
-1
lines changed

src/gauge/wflow.nim

Lines changed: 190 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,106 @@ template gaugeFlow*(g: array|seq, eps: float, measure: untyped) =
6969
gaugeFlow(g, 0, eps):
7070
measure
7171

72+
import ../algorithms/rk
73+
74+
type
75+
GaugeFlowRKOp*[G] = object of RK2NOp[G,G]
76+
f: G
77+
GaugeFlowRKAdaptiveOp*[G] = object of RK2NAdaptiveOp[G,G]
78+
f: G
79+
80+
proc mkGaugeFlowRKOp*[G](g: G): GaugeFlowRKOp[G] =
81+
## the returned op will hold a reference to the input g
82+
var op = GaugeFlowRKOp[G](
83+
y: g,
84+
delta: g[0].l.newGauge,
85+
f: g[0].l.newGauge)
86+
proc adv(base: var type(g), d: var type(g), a: float, b: float) =
87+
const nc = op.y[0][0].nrows.float
88+
op.f.gaugeForce(base)
89+
let u = cast[ptr cArray[type(base[0])]](unsafeAddr(base[0]))
90+
let f = cast[ptr cArray[type(d[0])]](unsafeAddr(d[0]))
91+
let ff = cast[ptr cArray[type(d[0])]](unsafeAddr(op.f[0]))
92+
let n = base.len
93+
if a == 0.0:
94+
threads:
95+
for mu in 0..<n:
96+
for e in u[mu]:
97+
var v {.noinit.}:type(load1(u[0][0]))
98+
v := (-b * nc) * ff[mu][e]
99+
let t = exp(v) * u[mu][e]
100+
f[mu][e] := v
101+
u[mu][e] := t
102+
else:
103+
threads:
104+
for mu in 0..<n:
105+
for e in u[mu]:
106+
var v {.noinit.}:type(load1(u[0][0]))
107+
v := a * f[mu][e] + (-b * nc) * ff[mu][e]
108+
let t = exp(v) * u[mu][e]
109+
f[mu][e] := v
110+
u[mu][e] := t
111+
op.advance = adv
112+
op
113+
114+
proc mkGaugeFlowRKAdaptiveOp*[G](g: G): GaugeFlowRKAdaptiveOp[G] =
115+
## the returned op will hold a reference to the input g
116+
mixin simdMax
117+
var rk = g.mkGaugeFlowRKOp
118+
var op = GaugeFlowRKAdaptiveOp[G](
119+
y: rk.y,
120+
delta: rk.delta,
121+
f: rk.f,
122+
advance: rk.advance,
123+
y0: g[0].l.newGauge,
124+
)
125+
proc assignG(dst: var type(g), src: type(g)) =
126+
let u = cast[ptr cArray[type(dst[0])]](unsafeAddr(dst[0]))
127+
let s = cast[ptr cArray[type(src[0])]](unsafeAddr(src[0]))
128+
let n = dst.len
129+
threads:
130+
for mu in 0..<n:
131+
for e in u[mu]:
132+
u[mu][e] := s[mu][e]
133+
op.assign = assignG
134+
# op.errDelta = proc(d: type(g)): float =
135+
# var r = 0.0
136+
# threads:
137+
# var p2t = 0.0
138+
# for i in 0..<d.len:
139+
# p2t += d[i].norm2
140+
# threadMaster: r = p2t
141+
# const nc = d[0][0].nrows
142+
# sqrt(r / float((nc*nc-1)*d.len*d[0].l.physVol))
143+
op.errDelta = proc(d: type(g)): float =
144+
var res = 0.0
145+
threads:
146+
var r = 0.0
147+
for i in 0..<d.len:
148+
for s in d[i]:
149+
let e = d[i][s].norm2.simdMax
150+
if r<e: r = e
151+
threadRankMax r
152+
threadMaster: res = r
153+
const nc = d[0][0].nrows
154+
sqrt(res/float(nc*nc-1))
155+
op
156+
157+
proc gaugeFlowRK*[G](g: var G, steps: int, eps: float, coeffs: auto, measure: proc(wflowT: float) {.closure.} = nil) =
158+
## Wilson flow using encapsulated 2N RK operator with arbitrary RK2N coefficients.
159+
tic("flowProcRK")
160+
var op = g.mkGaugeFlowRKOp
161+
rk2n(op, coeffs, steps, eps, measureCb=measure)
162+
toc("endRK")
163+
164+
proc gaugeFlowRKAdaptive*[G](g: var G, t: float, h0: float, coeffs: auto, tol: float, safety: float = 0.95, maxSteps:int = 100000, controllerExp: float = 1.0/3.0, measure: proc(wflowT: float) {.closure.} = nil): RKAdaptiveStats =
165+
## Adaptive Wilson flow to total time t using encapsulated 2N RK operator and arbitrary coefficients.
166+
## See comments under rk2nAdaptive for more details.
167+
tic("flowProcAdaptive")
168+
var op = g.mkGaugeFlowRKAdaptiveOp
169+
result = rk2nAdaptive(op, coeffs, t, h0, deltaTol=tol, safety=safety, maxSteps=maxSteps, controllerExp=controllerExp, measureCb=measure)
170+
toc("endAdaptive")
171+
72172
when isMainModule:
73173
import qex, gauge, physics/qcdTypes
74174
import os, sequtils
@@ -96,8 +196,97 @@ when isMainModule:
96196
quit(-1)
97197
g.printPlaq
98198

199+
# Compare plaquettes
200+
proc relDiff(a, b: auto): float =
201+
let pa = a.plaq
202+
let pb = b.plaq
203+
zip(pa, pb).foldl(a + abs(b[0] - b[1]), 0.0) / max(1e-30, pa.sum)
204+
205+
var gRef = g.newGauge
206+
gRef.gaugeFlowRK(120, 0.0005, RK64_2N, (proc(t:float) =
207+
var nt {.global.} = 0.01
208+
if t < (1.0-1.0e-12)*nt:
209+
return
210+
nt += 0.01
211+
echo "WFLOW RK64 ref ", t
212+
gRef.printPlaq))
213+
214+
template runFlow(coeff:auto) =
215+
echo "gauge flow ",astToStr(coeff)
216+
var d = newseq[float](0)
217+
for (steps, eps) in [(6,0.01), (12,0.005)]:
218+
var gRK = g.newGauge
219+
gRK.gaugeFlowRK(steps, eps, coeff)
220+
d.add relDiff(gRef, gRK)
221+
echo " steps = ",steps," eps = ",eps," rel plaq diff = ",d[^1]
222+
echo " error scaling: ",(ln(d[0]/d[1])/ln(2.0))," per stage coeff: ",d[^1]/pow(0.005/coeff.beta.len,ln(d[0]/d[1])/ln(2.0))
223+
runFlow(RK3W6_2N)
224+
runFlow(RK3W7_2N)
225+
runFlow(RK43_1_2N)
226+
runFlow(RK43_2_2N)
227+
runFlow(RK43_3_2N)
228+
runFlow(RK43_4_2N)
229+
runFlow(RK53_1_2N)
230+
runFlow(RK53_2_2N)
231+
runFlow(RK53_3_2N)
232+
runFlow(RK53_4_2N)
233+
runFlow(RK4CK_2N)
234+
runFlow(RK4BBB_2N)
235+
runFlow(RK64_2N)
236+
237+
template runFlowAd(tol) =
238+
block:
239+
var gRK = g.newGauge
240+
let res = gRK.gaugeFlowRKAdaptive(6*0.01, 0.01, RK53_4_2N, tol)
241+
echo "gauge flow adaptive RK53_4 rel plaq diff = ",relDiff(gRef, gRK), " steps=", res.steps, " acc=", res.accepts, " rej=", res.rejects, " h∈[", res.minH, ", ", res.maxH, "]"
242+
runFlowAd(1e-5)
243+
runFlowAd(1e-7)
244+
runFlowAd(1e-9)
245+
runFlowAd(1e-11)
246+
247+
# Forward/backward gauge flow tests (fixed-step)
248+
template runFlowRev(coeff:auto) =
249+
echo "Fwd/Back Fixed ",astToStr(coeff)
250+
var d = newseq[float](0)
251+
for (steps, eps) in [(10,0.01), (20,0.005)]:
252+
var gr = g.newGauge
253+
var op = gr.mkGaugeFlowRKOp
254+
op.rk2n(coeff, steps, eps)
255+
op.rk2n(coeff, steps, -eps)
256+
d.add relDiff(g, gr)
257+
echo " steps = ",steps," eps = ",eps," rel plaq diff = ",d[^1]
258+
echo " error scaling: ",(ln(d[0]/d[1])/ln(2.0))," per stage coeff: ",d[^1]/pow(0.005/coeff.beta.len,ln(d[0]/d[1])/ln(2.0))
259+
runFlowRev(RK3W6_2N)
260+
runFlowRev(RK3W7_2N)
261+
runFlowRev(RK43_1_2N)
262+
runFlowRev(RK43_2_2N)
263+
runFlowRev(RK43_3_2N)
264+
runFlowRev(RK43_4_2N)
265+
runFlowRev(RK53_1_2N)
266+
runFlowRev(RK53_2_2N)
267+
runFlowRev(RK53_3_2N)
268+
runFlowRev(RK53_4_2N)
269+
runFlowRev(RK4CK_2N)
270+
runFlowRev(RK4BBB_2N)
271+
runFlowRev(RK64_2N)
272+
273+
template runFlowAdRev(tol) =
274+
block:
275+
var gRK = g.newGauge
276+
var op = gRK.mkGaugeFlowRKAdaptiveOp
277+
let resF = rk2nAdaptive(op, RK53_4_2N, 0.1, 0.01, tol)
278+
let resB = rk2nAdaptive(op, RK53_4_2N, -0.1, 0.01, tol)
279+
echo "Fwd/Back adaptive RK53_4 rel plaq diff = ",relDiff(g, gRK)
280+
echo " Fwd steps=", resF.steps, " acc=", resF.accepts, " rej=", resF.rejects, " h∈[", resF.minH, ", ", resF.maxH, "]"
281+
echo " Bwd steps=", resB.steps, " acc=", resB.accepts, " rej=", resB.rejects, " h∈[", resB.minH, ", ", resB.maxH, "]"
282+
runFlowAdRev(1e-5)
283+
runFlowAdRev(1e-7)
284+
runFlowAdRev(1e-9)
285+
runFlowAdRev(1e-11)
286+
287+
# Default flow (original 3-stage wrapper)
99288
g.gaugeFlow(6, 0.01):
100-
echo "WFLOW ",wflowT
289+
echo "WFLOW default ", wflowT
101290
g.printPlaq
102291

103292
when g[0][0].nrows == 1 or g[0][0].nrows == 3:

0 commit comments

Comments
 (0)