myhelpers.mac 4.10 KiB
load("eigen");
load("itensor");
load("diag");
assert(condition):=if not condition then error("Assertion violated") else true$
norm_2_squared(v):=v.v;
/* A constant matrix of size n x m */
constmatrix(n,m,c):=genmatrix(lambda ([i,j], c),n,m);
vstack:append;
hstack(a,b):=transpose(append(transpose(a),transpose(b)));
blockmat(a11,a12,a21,a22):=vstack(hstack(a11,a12),hstack(a21,a22))$
crossfunc(f):=makelist(
sum(sum(
levi_civita([i,j,k])*f(j,k),
j,1,3),k,1,3),i,1,3)$
crossprod(a,b):=crossfunc(lambda([j,k], a[j]*b[k]));
subrange(v, start, stop):=makelist(v[i,1],i,start,stop);
extract_diagonal(A):=makelist(A[i][i],i,1,length(A));
make_diagonal_matrix(v):=genmatrix(
lambda([i,j], if i=j then v[i] else 0),
length(v),length(v));
/* ------------------------------------------------------------------------- */
/* Simplification for expressions stemming from hyperbolic systems */
/* ------------------------------------------------------------------------- */
hypsimp(x):=ratsimp(ratsubst(1,n.n,x))$
fullhypsimp(x):=hypsimp(
ratsubst(
last(n)^2,
1-sum(n[i]^2,i,1,length(n)-1),
x)
);
/* ------------------------------------------------------------------------- */
/* diagonalize a given hyperbolic operator A */
/* ------------------------------------------------------------------------- */
hypdiagonalize(A):=block([evA, V, invV,D],
evA:hypsimp(apply(append, eigenvectors(A)[2])),
V:transpose(apply(matrix, evA)),
invV:hypsimp(invert(V)),
assert(hypsimp(V.invV)=ident(length(A))),
D:hypsimp(invV.A.V),
[V, D, invV]);
/* ------------------------------------------------------------------------- */
/* compute upwind flux for a given operator with eigenvalues evs, sorted
* in ascending order.
* Sign assumptions for all variables occurring in evs must be in place.
*/
/* ------------------------------------------------------------------------- */
hyp_upwind_flux(evs, D):=block([evvars, Dp, Dm, n, midstates, states, unknowns],
evvars:listofvars(evs),
add_evvars_suffix(suffix, x):=subst(makelist(v=concat(''v, suffix), v, evvars), x),
evsm:add_evvars_suffix(m, evs),
evsp:add_evvars_suffix(p, evs),
Dm:add_evvars_suffix(m, D),
Dp:add_evvars_suffix(p, D),
midstates:makelist(makelist(concat(s,state,i), i, 1, length(D)),
state, 1, length(evs)-1),
states:append(
[makelist(concat(sm, i), i, 1, length(D))],
midstates,
[makelist(concat(sp,i), i, 1, length(D))]),
unknowns:apply(append, midstates),
result:if member(0, evs) then
block([biasedD, veceqns, eqns, soln],
biasedD:makelist(
if evs[i] = 0 then [Dp,Dm]
else if evs[i] > 0 then [Dp,Dp]
else [Dm,Dm],
i, 1, length(evs)),
veceqns:apply(append, makelist(
-(if evs[i] > 0 then evsp[i] else evsm[i]) *(states[i+1]-states[i])
+(biasedD[i][1].states[i+1]-biasedD[i][2].states[i]),
i,1,length(evs))),
eqns:makelist(veceqns[i,1], i, 1, length(veceqns)),
soln:solve(eqns, unknowns),
assert(length(soln)=1),
for i: 1 thru length(evs) do
if evs[i] = 0 then return(Dp.subst(soln[1], midstates[i]))
)
else
block([straddle_idx, Dstates, veceqns, eqns, soln],
straddle_idx:for i: 1 thru length(evs)-1 do
if (evs[i] < 0) and (evs[i+1] > 0) then return(i),
flux:makelist(concat(flux,i),i,1,length(D)),
unknowns:append(unknowns, flux),
Dstates:append(
[Dm.first(states)],
makelist(
if i = straddle_idx then flux
else if evs[i] > 0 then Dp.midstates[i]
else Dm.midstates[i],
i, 1, length(midstates)),
[Dp.last(states)]),
veceqns:apply(append, makelist(
-(if evs[i] > 0 then evsp[i] else evsm[i]) *(states[i+1]-states[i])
+(Dstates[i+1]-Dstates[i]),
i,1,length(evs))),
eqns:makelist(veceqns[i,1], i, 1, length(veceqns)),
print(covect(eqns)),
soln:solve(eqns, unknowns),
assert(length(soln)=1),
subst(soln[1], flux)
),
subst(
append(
makelist(concat(sm, i)=sm[i,1], i, 1, length(D)),
makelist(concat(sp, i)=sp[i,1], i, 1, length(D))
),
result)
);