Skip to content
Snippets Groups Projects
myhelpers.mac 4.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • Andreas Klöckner's avatar
    Andreas Klöckner committed
    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.
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
     */
    /* ------------------------------------------------------------------------- */
    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)
      );