> Could you possible post your code so I can play around with it? I
> can't think offhand what could be the issue or exactly what the error
> is that you're calculating, it seems like the normalized residual or
> something. 

hi daniel, thanks for your reply. the way i was calculating the residual
is to export the solution on a grid, import that into mathematica,
interpolate in space and time and have mathematica calculate
||lhs-rhs|| / ||lhs|| where ||...|| is the L2 norm. what i saw was that
the relative error was low in the beginning but increased over time,
especially in places where the solution starts to grow exponentially.


i am sure this relative error can be gotten from fipy using
residualVector or some other methods of the terms but i have not been
able to understand the docs well enough to replicate that.

so i am posting pretty much the (streamlined but otherwise unchanged)
example script i am having trouble with below. h5py is needed only for
the export, you can comment that out if you dont export. Lambda3 is the
source term coefficient -- by increasing it's values the solution
becomes more rapidly growing and the errors also increase.

i hope the indentation survives emailing....

cheers, n.



from __future__ import division
import fipy as fp
from fipy import numerix as nx
# the module for the bare numpy functions
# this is essentially numpy!
NX = nx.NUMERIX
from time import sleep


# this is where we are going to write results
import os
datadir = os.path.join(
        os.path.dirname(os.path.realpath(__file__)),
        'pde_test_data/'
        )
datadir = os.path.realpath(datadir)
try: os.mkdir(datadir)
except OSError: pass

# utility
def nsq(v):
    return nx.dot(v, v)

class Domain(object):
    upper = 300.
    lower = 0
    size = upper - lower

class Mesh(Domain):
    def __init__(self):
        delta = 1.5
        Lx, Ly = (self.size,) * 2
        dx, dy = (delta,) * 2
        nx, ny = (self.size // delta,) * 2
        self.mesh = fp.Grid2D(dx=dx, dy=dx, nx=nx, ny=ny, Lx=Lx, Ly=Ly)

# from Mma, the last iteration of the potential was this:

class Phi(object):
    scale = 100.
    x1, y1 = [100., 100]
    x2, y2 = [180., 180]
    s1 = 4.
    s2 = 12.
    dp = 3.
    strength = 30.
    sharpness_a = 120.
    # the following should act on the position field x
    # this should be a cell varable in fipy.
    @classmethod
    def itp(cls, z):
        t = nx.tanh(z/cls.sharpness_a**2) + 1
        return 0.5 * t
    @classmethod
    def scalephi(cls, x, y):
        [d1, d2] = [(x-cls.x1)**2 + (y-cls.y1)**2,
                (x-cls.x2)**2 + (y-cls.y2)**2]
        [f2, f1] = [cls.itp(d1 - d2), cls.itp(d2 - d1)]
        p1 = 0.5 * cls.s1 * d1 / cls.scale**2
        p2 = 0.5 * cls.s2 * d2 / cls.scale**2 - cls.dp
        return f1 * p1 + f2 * p2
    @classmethod
    def __call__(cls, x, y):
        return cls.strength * cls.scalephi(x, y)

class Lambda3(object):
    def __init__(self, curvature=None, direction=None, start=None):
        if curvature is None: curvature = 0.2 / Domain.size**2
        if direction is None: direction = nx.array([1, 1.])
        direction /= nx.sqrt(nsq(nx.array(direction)))
        if start is None: start = nx.array([0.,0])
        max_pos = 0.5 * nx.sqrt(2) * Domain.size
        max_ht = 1./2 * max_pos**2 * curvature # for 0 at the origin
        max_ht = 0.1 * max_ht # tame the beast
        (self.curvature, self.direction, self.max_pos, self.max_ht,
                self.start) = (
                curvature, direction, max_pos, max_ht, start)
    def __call__(self, x, y):
        distance2 = (NX.dot(self.direction,
            (nx.array([x, y]).T - self.start).T) - self.max_pos)**2
        lam = self.max_ht - 1./2 * self.curvature * distance2
        return lam

class InitialRho(object):
    '''Gaussian-like initial condition'''
    c = [[100], [100]]
    covm = NX.eye(2) * 30**2  # bare numpy
    stm = NX.linalg.inv(covm)
    Z = (2. * NX.linalg.det(covm))**(1./2)
    @classmethod
    def __call__(cls, x, y):
        p = NX.array([x,y])
        return  1. / cls.Z * NX.exp(-1./2 * NX.diag(
            cls.stm.dot(p - cls.c).T.dot(p - cls.c)))

mesh = Mesh().mesh
x, y = mesh.cellCenters
x1d, y1d = x[:mesh.nx], y[::mesh.ny] # yes!


# diffusion
Dtensor = nx.eye(2) * 10.
# constant diff coeff fields
Dtensor = fp.CellVariable(mesh, 'dtensor', Dtensor)

# make the input fields
phi = fp.CellVariable(name=r'$\phi$', mesh=mesh, value=Phi()(x, y))
v = - phi.grad  # on the cells, not the faces.

lambda_ = fp.CellVariable(name=r'$\lambda$', mesh=mesh,
        value=Lambda3(curvature=1./Domain.size**2, direction=[1.,-1],
start=[0.,Domain.size])(x, y))


# terms
def diff(DD):
    # Correction actually needed? in any case it seems to work.
    # list of diffusion coefficients of different orders
    return fp.DiffusionTermCorrection(coeff=[DD,])
def drift(v):
    return - fp.PowerLawConvectionTerm(coeff=v)
def prolif(lambda_):
    # implicit = multiplies the var
    return fp.ImplicitSourceTerm(coeff=lambda_)
def lhs():
    return fp.TransientTerm()

# construct the density
rho = fp.CellVariable(name=r'$\rho$', mesh=mesh, hasOld=True)

# boundary conditions
border = mesh.exteriorFaces
bc = 'dirichlet'
bc = 'no-flux'
# Dirichlet bc
if bc == 'dirichlet':
    rho.constrain(0., where=border)
# no-flux: set convection and diffusion 0
elif bc == 'no-flux':
    pass # no flux is standard b.c. in fipy.
else: raise ValueError("invalid bc type")

eq_diffprolif = lhs() == diff(Dtensor) + drift(v) + prolif(lambda_)

# initial condition
ic = fp.CellVariable(name=r'$\rho_0$', mesh=mesh, value=InitialRho()(x,y))

variants = { 'diffprolif': (eq_diffprolif, Dtensor, phi, lambda_, ic) }

# set up visualization for it
viewer = fp.Viewer(rho, datamax = 3. * ic.max(), datamin = -0.1 * ic.max())

# solver parameters
class Solve(object):
    sampling = 5
    step = sampling / 5
    # T = 10
    T = 80
    sample_t = NX.arange(0, T + sampling / 2., sampling)
    sweeps = 0.01
    # customSolver = fp.LinearCGSSolver()
    customSolver = None
    assert NX.isclose(0, NX.modf(sampling / step)[0])


# do it for all the equations of interest:
snapshots, residuals = {}, {}
eq, _, _, _, ic_ = variants['diffprolif']
# initialize
rho.setValue(ic_.value)
snapshots = []
residuals = []
# first
snapshots.append(rho.value.copy())
viewer.plot()
for (st, stnext) in zip(Solve.sample_t, Solve.sample_t[1:]):
    for tt in nx.arange(st, stnext, Solve.step):
        rho.updateOld()
        res = 1.
        while res > Solve.sweeps:
            res = eq.sweep(var=rho, dt=Solve.step,
solver=Solve.customSolver)
        residuals.append(res)
    snapshots.append(rho.value.copy())
    sleep(0.1)
    viewer.plot()

# Now finally we have to export this. Use hdf5 as from Mma to reproduce
the output.

# sampling for export
sampling_delta = 1.5
ex_x1, ex_y1 = NX.arange(1., 280, sampling_delta), NX.arange(1., 280,
sampling_delta)
ex_x, ex_y = NX.meshgrid(ex_x1, ex_y1)

# interpolate the intermediates at these values!
def sample_field(cellvar, value=None, xs=None, ys=None, normalize=False):
    from scipy.interpolate import RectBivariateSpline
    val = cellvar.value if value is None else value
    f = val.reshape(cellvar.mesh.nx, -1)
    x1 = cellvar.mesh.x[:cellvar.mesh.nx]
    y1 = cellvar.mesh.y[::cellvar.mesh.ny]  # sic.
    field = RectBivariateSpline(x1, y1, f,
            bbox=[Domain.lower, Domain.upper] * 2, s=0)
    xs = ex_x1 if xs is None else xs
    ys = ex_y1 if ys is None else ys
    sf = field(xs, ys)
    area_el = (xs[1]-xs[0]) * (ys[1]-ys[0])
    int_ = sf.sum() * area_el
    return (sf / int_, int_) if normalize else sf

# write to HDF5 file
import h5py as h5
outfile = os.path.join(datadir, 'twohump.h5')
eq, Dtens, ph, lam, ic_ = variants['diffprolif']
Dt = Dtens[:,:,0] # get back constant array from cell variable
with h5.File(name=outfile, mode='w') as f:
    f['phi'] = sample_field(ph)
    f['lambda'] = sample_field(lam)
    dNs = [sample_field(rho, value=snap, normalize=True)
             for snap in snapshots]
    f['density'] = NX.array([dn[0] for dn in dNs])
    f['Nt'] = NX.array([dn[1] for dn in dNs])
    f['diffcoeff'] = NX.diag(Dt)
    f['timeline'] = Solve.sample_t
    assert f['density'].shape[0] == f['timeline'].shape[0]
    f['xs'], f['ys'] = ex_x1, ex_y1


Attachment: 0xF0A5C638.asc
Description: application/pgp-keys

_______________________________________________
fipy mailing list
fipy@nist.gov
http://www.ctcms.nist.gov/fipy
  [ NIST internal ONLY: https://email.nist.gov/mailman/listinfo/fipy ]

Reply via email to