Esempio n. 1
0
                            CFL, r, filename = 'file-out.npy') #, init = 'cont.npy') #, init = 'macro_restart.txt') # restart from macroparameters array
t2 = time.time()

log = open('log.txt', 'a')
log.write('Time  = ' + str(t2 - t1) + '\n')
log.close()

fig, ax = plt.subplots(figsize = (20,10))
line, = ax.semilogy(S.frob_norm_iter/S.frob_norm_iter[0])
ax.set(title='$Steps =$' + str(nt))
plt.savefig('norm_iter.png')
plt.close()

data = np.zeros((mesh.nc, 7))
    
data[:, 0] = S.n[:]
data[:, 1] = S.ux[:]
data[:, 2] = S.uy[:]
data[:, 3] = S.uz[:]
data[:, 4] = S.p[:]
data[:, 5] = S.T[:]
data[:, 6] = S.rank[:]

np.savetxt('macroparameters_data.txt', data) # save macroparameters

write_tecplot(mesh, data, 'tec_tt.dat', ('n', 'ux', 'uy', 'uz', 'p', 'T', 'rank'))

log = open('log.txt', 'a')
log.write('Residual = ' + str('{0:5.2e}'.format(S.frob_norm_iter[-1]/S.frob_norm_iter[0])) + '\n')
log.close()
Esempio n. 2
0
def solver_tt(gas_params, problem, mesh, nt, nv, vx_, vx, vy, vz, \
              CFL, tol, filename, init = '0'):
    """Solve Boltzmann equation with model collision integral 
    
    gas_params -- object of class GasParams, contains gas parameters and viscosity law
    
    problem -- object of class Problem, contains list of boundary conditions,
    data for b.c., and function for initial condition
    
    mesh - object of class Mesh
    
    nt -- number of time steps
    
    vmax -- maximum velocity in each direction in velocity mesh
    
    nv -- number of nodes in velocity mesh
    
    CFL -- courant number
    
    filename -- name of output file for f
    
    init - name of restart file
    """
    # Function for LU-SGS
    mydivide = lambda x: x[:, 0] / x[:, 1]
    zero_tt = 0. * tt.ones((nv, nv, nv))
    ones_tt = tt.ones((nv, nv, nv))
    #
    # Initialize main arrays and lists
    #
    vn = [None
          ] * mesh.nf  # list of tensors of normal velocities at each mesh face
    vn_tmp = np.zeros((nv, nv, nv))
    vnm = [None] * mesh.nf  # negative part of vn: 0.5 * (vn - |vn|)
    vnp = [None] * mesh.nf  # positive part of vn: 0.5 * (vn + |vn|)
    vn_abs = [None] * mesh.nf  # approximations of |vn|

    vx_tt = tt.tensor(vx).round(tol)
    vy_tt = tt.tensor(vy).round(tol)
    vz_tt = tt.tensor(vz).round(tol)

    vn_error = 0.
    for jf in range(mesh.nf):
        vn_tmp = mesh.face_normals[jf, 0] * vx + mesh.face_normals[
            jf, 1] * vy + mesh.face_normals[jf, 2] * vz
        vn[jf] = mesh.face_normals[jf, 0] * vx_tt + mesh.face_normals[
            jf, 1] * vy_tt + mesh.face_normals[jf, 2] * vz_tt
        vnp[jf] = tt.tensor(np.where(vn_tmp > 0, vn_tmp, 0.), eps=tol)
        vnm[jf] = tt.tensor(np.where(vn_tmp < 0, vn_tmp, 0.), eps=tol)
        vn_abs[jf] = tt.tensor(np.abs(vn_tmp), rmax=4)
        vn_error = max(
            vn_error,
            np.linalg.norm(vn_abs[jf].full() - np.abs(vn_tmp)) /
            np.linalg.norm(np.abs(vn_tmp)))
    print('max||vn_abs_tt - vn_abs||_F/max||vn_abs||_F = ', vn_error)

    h = np.min(mesh.cell_diam)
    tau = h * CFL / (np.max(vx_) * (3.**0.5))
    v2 = (vx_tt * vx_tt + vy_tt * vy_tt + vz_tt * vz_tt).round(tol)

    diag = [None] * mesh.nc  # part of diagonal coefficient in implicit scheme
    # precompute diag
    diag_full = np.zeros(
        (mesh.nc, nv, nv,
         nv))  # part of diagonal coefficient in implicit scheme
    # precompute diag
    for ic in range(mesh.nc):
        for j in range(6):
            jf = mesh.cell_face_list[ic, j]
            vn_tmp = mesh.face_normals[jf, 0] * vx + mesh.face_normals[
                jf, 1] * vy + mesh.face_normals[jf, 2] * vz
            vnp_full = np.where(
                mesh.cell_face_normal_direction[ic, j] * vn_tmp[:, :, :] > 0,
                mesh.cell_face_normal_direction[ic, j] * vn_tmp[:, :, :], 0.)
            diag_full[ic, :, :, :] += (mesh.face_areas[jf] /
                                       mesh.cell_volumes[ic]) * vnp_full

    for ic in range(mesh.nc):
        diag_temp = np.zeros((nv, nv, nv))
        for j in range(6):
            jf = mesh.cell_face_list[ic, j]
            vn_full = (mesh.face_normals[jf, 0] * vx + mesh.face_normals[jf, 1] * vy \
                       + mesh.face_normals[jf, 2] * vz) * mesh.cell_face_normal_direction[ic, j]
            vnp_full = np.where(vn_full > 0, vn_full, 0.)
            vn_abs_full = np.abs(vn_full)
            diag_temp += (mesh.face_areas[jf] /
                          mesh.cell_volumes[ic]) * vnp_full
#            diag_temp += 0.5 * (mesh.face_areas[jf] / mesh.cell_volumes[ic]) * vn_abs_full
        diag[ic] = tt.tensor(diag_temp)
    # Compute mean rank of diag
    diag_rank = 0.
    for ic in range(mesh.nc):
        diag_rank += 0.5 * (diag[ic].r[1] + diag[ic].r[2])
    diag_rank = diag_rank / ic
    print('diag_rank = ', diag_rank)
    #
    diag_scal = np.zeros(mesh.nc)
    for ic in range(mesh.nc):
        for j in range(6):
            jf = mesh.cell_face_list[ic, j]
            diag_scal[ic] += 0.5 * (mesh.face_areas[jf] /
                                    mesh.cell_volumes[ic])
    diag_scal *= np.max(np.abs(vx_)) * 3**0.5
    # set initial condition
    f = [None] * mesh.nc
    if (init == '0'):
        for i in range(mesh.nc):
            x = mesh.cell_center_coo[i, 0]
            y = mesh.cell_center_coo[i, 1]
            z = mesh.cell_center_coo[i, 2]
            f[i] = problem.f_init(x, y, z, vx, vy, vz)
    else:
        #        restart from distribution function
        #        f = load_tt(init, mesh.nc, nv)
        #        restart form macroparameters array
        init_data = np.loadtxt(init)
        for ic in range(mesh.nc):
            f[ic] = tt.tensor(f_maxwell(vx, vy, vz, init_data[ic, 5], \
             init_data[ic, 0], init_data[ic, 1], init_data[ic, 2], init_data[ic, 3], gas_params.Rg), tol)

    # TODO: may be join f_plus and f_minus in one array
    f_plus = [None] * mesh.nf  # Reconstructed values on the right
    f_minus = [None] * mesh.nf  # reconstructed values on the left
    flux = [None] * mesh.nf  # Flux values
    rhs = [None] * mesh.nc
    df = [None] * mesh.nc

    # Arrays for macroparameters
    n = np.zeros(mesh.nc)
    rho = np.zeros(mesh.nc)
    ux = np.zeros(mesh.nc)
    uy = np.zeros(mesh.nc)
    uz = np.zeros(mesh.nc)
    p = np.zeros(mesh.nc)
    T = np.zeros(mesh.nc)
    nu = np.zeros(mesh.nc)
    rank = np.zeros(mesh.nc)
    data = np.zeros((mesh.nc, 7))

    # Dummy tensor with [1, 1, 1, 1] ranks
    F = tt.rand([nv, nv, nv], 3, [1, 1, 1, 1])
    frob_norm_iter = np.array([])

    it = 0
    while (it < nt):
        it += 1
        # reconstruction for inner faces
        # 1st order
        for ic in range(mesh.nc):
            for j in range(6):
                jf = mesh.cell_face_list[ic, j]
                if (mesh.cell_face_normal_direction[ic, j] == 1):
                    f_minus[jf] = f[ic].copy()
                else:
                    f_plus[jf] = f[ic].copy()

        # boundary condition
        # loop over all boundary faces
        for j in range(mesh.nbf):
            jf = mesh.bound_face_info[j, 0]  # global face index
            bc_num = mesh.bound_face_info[j, 1]
            bc_type = problem.bc_type_list[bc_num]
            bc_data = problem.bc_data[bc_num]
            if (mesh.bound_face_info[j, 2] == 1):
                f_plus[jf] = set_bc_tt(gas_params, bc_type, bc_data,
                                       f_minus[jf], vx, vy, vz, vn[jf],
                                       vnp[jf], vnm[jf], tol)
            else:
                f_minus[jf] = set_bc_tt(gas_params, bc_type, bc_data,
                                        f_plus[jf], vx, vy, vz, -vn[jf],
                                        -vnm[jf], -vnp[jf], tol)

        # riemann solver - compute fluxes
        for jf in range(mesh.nf):
            flux[jf] = 0.5 * mesh.face_areas[jf] *\
            ((f_plus[jf] + f_minus[jf]) * vn[jf]  - (f_plus[jf] - f_minus[jf]) * vn_abs[jf])
            flux[jf] = flux[jf].round(tol)

        # computation of the right-hand side
        for ic in range(mesh.nc):
            rhs[ic] = zero_tt.copy()
            # sum up fluxes from all faces of this cell
            for j in range(6):

                jf = mesh.cell_face_list[ic, j]
                rhs[ic] += -(mesh.cell_face_normal_direction[ic, j]) * (
                    1. / mesh.cell_volumes[ic]) * flux[jf]
                rhs[ic] = rhs[ic].round(tol)
            # Compute macroparameters and collision integral
            J, n[ic], ux[ic], uy[ic], uz[ic], T[ic], nu[ic], rho[ic], p[
                ic] = comp_macro_param_and_j_tt(f[ic], vx_, vx, vy, vz, vx_tt,
                                                vy_tt, vz_tt, v2, gas_params,
                                                tol, F, ones_tt)
            rhs[ic] += J
            rhs[ic] = rhs[ic].round(tol)

        frob_norm_iter = np.append(
            frob_norm_iter,
            np.sqrt(sum([(rhs[ic].norm())**2 for ic in range(mesh.nc)])))
        #
        # update values, expclicit scheme
        #
        for ic in range(mesh.nc):
            f[ic] = (f[ic] + tau * rhs[ic]).round(tol)

        # save rhs norm and tec tile
        if ((it % 100) == 0):
            fig, ax = plt.subplots(figsize=(20, 10))
            line, = ax.semilogy(frob_norm_iter / frob_norm_iter[0])
            ax.set(title='$Steps =$' + str(it))
            plt.savefig('norm_iter.png')
            plt.close()

            data[:, 0] = n[:]
            data[:, 1] = ux[:]
            data[:, 2] = uy[:]
            data[:, 3] = uz[:]
            data[:, 4] = p[:]
            data[:, 5] = T[:]
            data[:, 6] = rank[:]

            write_tecplot(mesh, data, 'tec_tt.dat',
                          ('n', 'ux', 'uy', 'uz', 'p', 'T', 'rank'))

    save_tt(filename, f, mesh.nc, nv)

    Return = namedtuple(
        'Return',
        ['f', 'n', 'ux', 'uy', 'uz', 'T', 'p', 'rank', 'frob_norm_iter'])

    S = Return(f, n, ux, uy, uz, T, p, rank, frob_norm_iter)

    return S
Esempio n. 3
0
def solver(gas_params, problem, mesh, nt, vmax, nv, CFL, filename, init = '0'):
    """Solve Boltzmann equation with model collision integral 
    
    gas_params -- object of class GasParams, contains gas parameters and viscosity law
    
    problem -- object of class Problem, contains list of boundary conditions,
    data for b.c., and function for initial condition
    
    mesh - object of class Mesh
    
    nt -- number of time steps
    
    vmax -- maximum velocity in each direction in velocity mesh
    
    nv -- number of nodes in velocity mesh
    
    CFL -- courant number
    
    filename -- name of output file for f
    
    init - name of restart file
    """
        
    h = np.min(mesh.cell_diam)
    tau = h * CFL / (vmax * (3.**0.5))
    
    hv = 2. * vmax / nv
    vx_ = np.linspace(-vmax+hv/2, vmax-hv/2, nv) # coordinates of velocity nodes
    
    vx, vy, vz = np.meshgrid(vx_, vx_, vx_, indexing='ij')
    
    # set initial condition 
    f = np.zeros((mesh.nc, nv, nv, nv))
    if (init == '0'):
        for i in range(mesh.nc):
            x = mesh.cell_center_coo[i, 0]
            y = mesh.cell_center_coo[i, 1]
            z = mesh.cell_center_coo[i, 2]
            f[i, :, :, :] = problem.f_init(x, y, z, vx, vy, vz) 
    else:
#        restart from distribution function
        f = np.reshape(np.load(init), (mesh.nc, nv, nv, nv))
#        restart form macroparameters array
#        init_data = np.loadtxt(init)
#        for ic in range(mesh.nc):
#            f[ic, :, :, :] = f_maxwell(vx, vy, vz, init_data[ic, 5], init_data[ic, 0], init_data[ic, 1], init_data[ic, 2], init_data[ic, 3], gas_params.Rg)
    
    # TODO: may be join f_plus and f_minus in one array
    f_plus = np.zeros((mesh.nf, nv, nv, nv)) # Reconstructed values on the right
    f_minus = np.zeros((mesh.nf, nv, nv, nv)) # reconstructed values on the left
    flux = np.zeros((mesh.nf, nv, nv, nv)) # Flux values
    rhs = np.zeros((mesh.nc, nv, nv, nv))
    df = np.zeros((mesh.nc, nv, nv, nv)) # Array for increments \Delta f    
    vn = np.zeros((mesh.nf, nv, nv, nv))
    for jf in range(mesh.nf):
        vn[jf, :, :, :] = mesh.face_normals[jf, 0] * vx + mesh.face_normals[jf, 1] * vy + mesh.face_normals[jf, 2] * vz

    diag = np.zeros((mesh.nc, nv, nv, nv)) # part of diagonal coefficient in implicit scheme
    # precompute diag
    for ic in range(mesh.nc):
        for j in range(6):
            jf = mesh.cell_face_list[ic, j]
            vnp = np.where(mesh.cell_face_normal_direction[ic, j] * vn[jf, :, :, :] > 0,
                                    mesh.cell_face_normal_direction[ic, j] * vn[jf, :, :, :], 0.)
            diag[ic, :, :, :] += (mesh.face_areas[jf] / mesh.cell_volumes[ic]) * vnp
    # Arrays for macroparameters
    n = np.zeros(mesh.nc)
    rho = np.zeros(mesh.nc)
    ux = np.zeros(mesh.nc)
    uy = np.zeros(mesh.nc)
    uz = np.zeros(mesh.nc)
    p =  np.zeros(mesh.nc)
    T = np.zeros(mesh.nc)
    nu = np.zeros(mesh.nc)
    data = np.zeros((mesh.nc, 7))
    
    frob_norm_iter = np.array([])

    it = 0
    while(it < nt):
        it += 1
        # reconstruction for inner faces
        # 1st order
        for ic in range(mesh.nc):
            for j in range(6):
                jf = mesh.cell_face_list[ic, j]
                # TODO: think how do this without 'if'
                if (mesh.cell_face_normal_direction[ic, j] == 1):
                    f_minus[jf, :, :, :] = f[ic, :, :, :]
                else:
                    f_plus[jf, :, :, :] = f[ic, :, :, :]
                      
        # boundary condition
        # loop over all boundary faces
        for j in range(mesh.nbf):
            jf = mesh.bound_face_info[j, 0] # global face index
            bc_num = mesh.bound_face_info[j, 1]
            bc_type = problem.bc_type_list[bc_num]
            bc_data = problem.bc_data[bc_num]
            if (mesh.bound_face_info[j, 2] == 1):
                # TODO: normal velocities vn can be pre-computed one time
                # then we can pass to function p.bc only vn
                f_plus[jf, :, :, :] =  set_bc(gas_params, bc_type, bc_data, f_minus[jf, :, :, :], vx, vy, vz, vn[jf, :, :, :])
            else:
                f_minus[jf, :, :, :] = set_bc(gas_params, bc_type, bc_data, f_plus[jf, :, :, :], vx, vy, vz, -vn[jf, :, :, :])

        # riemann solver - compute fluxes
        for jf in range(mesh.nf):
            # TODO: Pre-compute array of vn[:] ???
            flux[jf, :, :, :] = mesh.face_areas[jf] * vn[jf, :, :, :] * \
            np.where((vn[jf, :, :, :] < 0), f_plus[jf, :, :, :], f_minus[jf, :, :, :])
#            flux[jf] = (1. / 2.) * mesh.face_areas[jf] * ((vn * (f_plus[jf, :, :, :] + f_minus[jf, :, :, :])) - (vn_abs * (f_plus[jf, :, :, :] - f_minus[jf, :, :, :])))
                
        # computation of the right-hand side
        rhs[:] = 0.
        for ic in range(mesh.nc):
            # sum up fluxes from all faces of this cell
            for j in range(6):
                jf = mesh.cell_face_list[ic, j]
                rhs[ic, :, :, :] += - (mesh.cell_face_normal_direction[ic, j]) * (1. / mesh.cell_volumes[ic]) * flux[jf, :, :, :]
            # Compute macroparameters and collision integral
            J, n[ic], ux[ic], uy[ic], uz[ic], T[ic], nu[ic], rho[ic], p[ic] = comp_macro_param_and_j(f[ic, :, :, :], vx, vy, vz, gas_params)
            rhs[ic, :, :, :] += J
        
        frob_norm_iter = np.append(frob_norm_iter, np.linalg.norm(rhs))
        #     
        # update values - explicit scheme
        #
#        f += tau * rhs
        '''
        LU-SGS iteration
        '''
        #
        # Backward sweep 
        #
        for ic in range(mesh.nc - 1, -1, -1):
            df[ic, :, :, :] = rhs[ic, :, :, :]
            # loop over neighbors of cell ic
            for j in range(6):
                jf = mesh.cell_face_list[ic, j]
                icn = mesh.cell_neighbors_list[ic, j] # index of neighbor
                vnm = np.where(mesh.cell_face_normal_direction[ic, j] * vn[jf, :, :, :] < 0,
                                    mesh.cell_face_normal_direction[ic, j] * vn[jf, :, :, :], 0.)
                if (icn >= 0 ) and (icn > ic):
                    df[ic, :, :, :] += -(mesh.face_areas[jf] / mesh.cell_volumes[ic]) \
                    * vnm * df[icn, : , :, :] 
            # divide by diagonal coefficient
            df[ic, :, :, :] = df[ic, :, :, :] / (np.ones((nv, nv, nv)) * (1/tau + nu[ic]) + diag[ic])
        #
        # Forward sweep
        # 
        for ic in range(mesh.nc):
            # loop over neighbors of cell ic
            incr = np.zeros((nv, nv, nv))
            for j in range(6):
                jf = mesh.cell_face_list[ic, j]
                icn = mesh.cell_neighbors_list[ic, j] # index of neighbor
                vnm = np.where(mesh.cell_face_normal_direction[ic, j] * vn[jf, :, :, :] < 0,
                                    mesh.cell_face_normal_direction[ic, j] * vn[jf, :, :, :], 0.)
                if (icn >= 0 ) and (icn < ic):
                    incr+= -(mesh.face_areas[jf] /  mesh.cell_volumes[ic]) \
                    * vnm * df[icn, : , :, :] 
            # divide by diagonal coefficient
            df[ic, :, :, :] += incr / (np.ones((nv, nv, nv)) * (1./tau + nu[ic]) + diag[ic])
        f += df
        '''
        end of LU-SGS iteration
        '''
        
        if ((it % 50) == 0):     
            fig, ax = plt.subplots(figsize = (20,10))
            line, = ax.semilogy(frob_norm_iter/frob_norm_iter[0])
            ax.set(title='$Steps =$' + str(it))
            plt.grid(True)
            plt.savefig('norm_iter.png')
            plt.close()
                            
            data[:, 0] = n[:]
            data[:, 1] = ux[:]
            data[:, 2] = uy[:]
            data[:, 3] = uz[:]
            data[:, 4] = p[:]
            data[:, 5] = T[:]
            data[:, 6] = np.zeros(mesh.nc)
            
            write_tecplot(mesh, data, 'tec.dat', ('n', 'ux', 'uy', 'uz', 'p', 'T', 'rank'))
            np.save(filename, np.ravel(f))
    
    Return = namedtuple('Return', ['f', 'n', 'ux', 'uy', 'uz', 'T', 'p', 'frob_norm_iter'])
    
    S = Return(f, n, ux, uy, uz, T, p, frob_norm_iter)
  
    return S