spectralDNS / shenfun

High performance computational platform in Python for the spectral Galerkin method

Home Page:http://shenfun.readthedocs.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Incorrect solution of 1D Poisson equation

yesint opened this issue · comments

I'm struggling to understand why shenfun produces wrong magnitude of solution for simplest 1D Poisson equation. I can't figure out what I'm doing wrong, so any help is deeply appreciated.

Here is the code, which solved 1D Poissin equation first using shenfun and then by naive double integration:

import numpy as np
from shenfun import inner, div, grad, TestFunction, TrialFunction, \
    Array, Function, Basis


# Naive integration
def integrate(vec, dx):
    f = np.zeros(vec.shape)
    for i in range(1,len(vec)):
        f[i] = f[i-1] + (vec[i]+vec[i-1])*0.5*dx
    return f

#--------------------------------------
# Integrate with shenfun
#--------------------------------------

data = np.loadtxt('charge.xvg',comments=('#','@'))
fe = np.array(data[:,1])

# Size of discretization
N = fe.shape[0]

# Domain is set to what we have on X in data file
SD = Basis(N, family='legendre', bc=(0,0), domain=(data[0,0],data[-1,0]))
X = SD.mesh()

u = TrialFunction(SD)
v = TestFunction(SD)

# Get f on quad points
fj = Array(SD, buffer=fe)

# Compute right hand side of Poisson equation
f_hat = Function(SD)
f_hat = inner(v, fj, output_array=f_hat)

# Get left hand side of Poisson equation
A = inner(v, div(grad(u)))

u_hat = Function(SD)
u_hat = A.solve(f_hat, u_hat)
uj = u_hat.backward()
uh = uj.forward()

with open('solution_shen.dat','w') as f:
    for x,v in zip(X,uj):
        f.write(f'{x} {v}\n')
    
#--------------------------------------
# Naive integration
#--------------------------------------
dx = data[1,0]-data[0,0] # step on X
f = integrate(data[:,1],dx) # Integrate once
u = integrate(f,dx)         # Integrade second time
with open('solution_naive.dat','w') as out:
    for i in range(len(u)):
        out.write(f'{data[i,0]} {u[i]}\n')
        

And here is the result:
solution_naive

I can't understand two things here:

  1. Why magnitude of shenfun solution is obviously wrong. I'm using exactly the same data for both methods and the results should be identical.
  2. Why the SD.mesh() returns different X points (see systematic shift of the curves on X) from what we have in data file despite correct number of points and domain?

Could somebody explain me what I'm missing and what should I modify to get the same result as naive integration?

Here is the data file
data.zip

Hi
It seems to me that your charge data are sampled on a uniform mesh, right? The shenfun Array expects the function values on Legendre quadrature points shifted to your domain, i.e., SD.mesh(). You can get the function values over on quadrature points using interpolation. For example

np.interp(X, data[:, 0], data[:, 1])

Hi
It seems to me that your charge data are sampled on a uniform mesh, right? The shenfun Array expects the function values on Legendre quadrature points shifted to your domain, i.e., SD.mesh(). You can get the function values over on quadrature points using interpolation. For example

np.interp(X, data[:, 0], data[:, 1])

Ups, now I understand the problem thank you!
If I understand correctly something like this is needed?

int_points = np.interp(X, data[:, 0], data[:, 1])
fj = Array(SD, buffer=int_points)

Do I also need this if Fourier basis is used?

Do I also need this if Fourier basis is used?

No, Fourier uses a uniform mesh.

Do I also need this if Fourier basis is used?

No, Fourier uses a uniform mesh.

Thanks a lot!