Stencil(*varargin, **kwargs) | Represents a matrix given a stencil. |
Interpolator(*varargin, **kwargs) | Implements an interpolation/restriction pair along a given dimension. |
Code | Various pieces of C++ code and code generators. |
PoissonBase | Base class for some objects representing derivatives. |
Poisson1D | Some stencils for 1d derivatives. |
Poisson2D | Some stencils for 2d derivatives. |
Poisson3D | Some stencils for 3d derivatives. |
Inheritance diagram for mmf.math.multigrid.stencil:
Stencil Module (mmf.math.multigrid.stencil)
This module provides access to matrices and operators defined by a stencil.
Stencil(*varargin, **kwargs) | Represents a matrix given a stencil. |
Interpolator(*varargin, **kwargs) | Implements an interpolation/restriction pair along a given dimension. |
Various pieces of C++ code and code generators.
Return (support_code, code, libs, dirs) for solving a*x = b.
Parameters : | N : int
a_var : str, optional
b_var : str, optional
|
---|---|
Returns : | support_code : str
pre_code : str
solve_code : str
libs : [str]
dirs : [str]
|
Examples
>>> a = np.array([[1, 2, 3, 4],
... [1, 3, 5, 7],
... [1, -2, 3, -4],
... [1, 2, -3, -4]], dtype=float)
>>> b = np.array([0, 1, 2, 3], dtype=float)
>>> support_code, pre_code, solve_code, libs, dirs = Code.solve(4)
>>> code = r'''
... %(pre_code)s
... int i, j;
... for (i=0;i<4;i++) {
... for (j=0;j<4;j++) {
... A2(i, j) = A_IN2(i, j);
... }
... }
... %(solve_code)s
... ''' % dict(pre_code=pre_code, solve_code=solve_code)
>>> sp.weave.inline(code=code, arg_names=['a_in', 'b'],
... local_dict=dict(a_in=a, b=b),
... support_code=support_code,
... libraries=libs, library_dirs=dirs)
>>> b
array([-3.5, 2.5, 1.5, -1.5])
>> x = np.linalg.solve(a, b) >> y = lu_solve(a, b) >> np.allclose(a, y) True
Bases: mmf.objects.StateVars
Represents a matrix given a stencil.
Stencil(boundary_conditions=periodic,
S=Required)
This class uses a stencil S together with a boundary condition to represent a matrix. With extended index notation, the matrix is:
The motivation behind this was representing the Jacobian of the following system of equations:
where the right-hand side is a local function of the various variables and the stencil represents the operator on the left-hand side. The tensor is
and is a set of scale factors.
Attributes
Bases: mmf.objects.StateVars
Implements an interpolation/restriction pair along a given dimension.
Interpolator(offset=0,
boundary_conditions=periodic)
This class provides two functions I() and R() the provide interpolation and restriction functionality for a multigrid algorithm.
Examples
First we demonstrate periodic boundary conditions with the various offsets and different sized output arrays:
>>> i = Interpolator(offset=0, boundary_conditions='periodic')
>>> f = np.array([1.0, 2.0, 3.0])
>>> i.IR(f, (5, ))
array([ 1. , 1.5, 2. , 2.5, 3. ])
>>> i.IR(f, (6, ))
array([ 1. , 1.5, 2. , 2.5, 3. , 2. ])
>>> i.offset = -1
>>> i.IR(f, (6, ))
array([ 2. , 1. , 1.5, 2. , 2.5, 3. ])
>>> i.offset = 1
>>> i.IR(f, (6, ))
array([ 1.5, 2. , 2.5, 3. , 2. , 1. ])
Now we demonstrate the same with Neumann boundary conditions:
>>> i = Interpolator(offset=0, boundary_conditions='Neumann')
>>> f = np.array([1.0, 2.0, 3.0])
>>> i.IR(f, (5, ))
array([ 1. , 1.5, 2. , 2.5, 3. ])
>>> i.IR(f, (6, ))
array([ 1. , 1.5, 2. , 2.5, 3. , 3. ])
>>> i.offset = -1
>>> i.IR(f, (6, ))
array([ 1. , 1. , 1.5, 2. , 2.5, 3. ])
>>> i.offset = 1
>>> i.IR(f, (6, ))
array([ 1.5, 2. , 2.5, 3. , 3. , 3. ])
The operators are constructed explicitly so that R.T*2 == I:
>>> a = np.zeros((3, 4, 3))
>>> b = np.zeros((3, 8, 3))
>>> I = np.eye(len(b.ravel()), len(a.ravel()))
>>> R = np.eye(len(a.ravel()), len(b.ravel()))
>>> for n in xrange(len(a.ravel())):
... a.flat[n] = 1
... I[:, n] = i.IR(a, b.shape).ravel()
... a.flat[n] = 0
>>> for n in xrange(len(b.ravel())):
... b.flat[n] = 1
... R[:, n] = i.IR(b, a.shape).ravel()
... b.flat[n] = 0
>>> abs(R.T*2 - I).max()
0.0
Attributes
State Variables: | |
|
|
|
This must be the name of one of the boundary condition transformation functions defined in support_code. |
Methods
IR(f, new_shape) | Interpolation/restriction operator. |
IR_mat(shape, new_shape) | Return CSR representation of the interpolation |
I_inline(f_in, f_out[, axis]) | Interpolation operator. |
I_mat(shape, n_new[, axis]) | Return a CSR sparse matrix representing the interpolation |
R_inline(f_in, f_out[, axis]) | Restriction operator. |
R_mat(shape, n_new[, axis]) | Return a CSR sparse matrix representing the restriction matrix. |
all_items() | Return a list [(name, obj)] of (name, object) pairs containing all items available. |
archive(name) | Return a string representation that can be executed to restore the object. |
archive_1([env]) | Return (rep, args, imports). |
initialize(**kwargs) | Calls __init__() passing all assigned attributes. |
items([archive]) | Return a list [(name, obj)] of (name, object) pairs where the |
resume() | Resume calls to __init__() from __setattr__(), |
suspend() | Suspend calls to __init__() from |
This is the initialization routine. It is called after the attributes specified in _state_vars have been assigned.
The user version should perform any after-assignment initializations that need to be performed.
Note
Since all of the initial arguments are listed in kwargs, this can be used as a list of attributes that have “changed” allowing the initialization to be streamlined. The default __setattr__() method will call __init__() with the changed attribute to allow for recalculation.
This recomputing only works for attributes that are assigned, i.e. iff __setattr__() is called. If an attribute is mutated, then __getattr__() is called and there is no (efficient) way to determine if it was mutated.
Computed values with True Computed.save will be passed in through kwargs when objects are restored from an archive. These parameters in general need not be recomputed, but this opens the possibility for an inconsistent state upon construction if a user inadvertently provides these parameters. Note that the parameters still cannot be set directly.
See __init__() Semantics for details.
Methods
IR(f, new_shape) | Interpolation/restriction operator. |
IR_mat(shape, new_shape) | Return CSR representation of the interpolation |
I_inline(f_in, f_out[, axis]) | Interpolation operator. |
I_mat(shape, n_new[, axis]) | Return a CSR sparse matrix representing the interpolation |
R_inline(f_in, f_out[, axis]) | Restriction operator. |
R_mat(shape, n_new[, axis]) | Return a CSR sparse matrix representing the restriction matrix. |
all_items() | Return a list [(name, obj)] of (name, object) pairs containing all items available. |
archive(name) | Return a string representation that can be executed to restore the object. |
archive_1([env]) | Return (rep, args, imports). |
initialize(**kwargs) | Calls __init__() passing all assigned attributes. |
items([archive]) | Return a list [(name, obj)] of (name, object) pairs where the |
resume() | Resume calls to __init__() from __setattr__(), |
suspend() | Suspend calls to __init__() from |
This is the initialization routine. It is called after the attributes specified in _state_vars have been assigned.
The user version should perform any after-assignment initializations that need to be performed.
Note
Since all of the initial arguments are listed in kwargs, this can be used as a list of attributes that have “changed” allowing the initialization to be streamlined. The default __setattr__() method will call __init__() with the changed attribute to allow for recalculation.
This recomputing only works for attributes that are assigned, i.e. iff __setattr__() is called. If an attribute is mutated, then __getattr__() is called and there is no (efficient) way to determine if it was mutated.
Computed values with True Computed.save will be passed in through kwargs when objects are restored from an archive. These parameters in general need not be recomputed, but this opens the possibility for an inconsistent state upon construction if a user inadvertently provides these parameters. Note that the parameters still cannot be set directly.
See __init__() Semantics for details.
Interpolation/restriction operator.
Interpolates (restricts) f_in along the axes where new_shape has more (fewer) elements than the corresponding dimension of f_in.
Return CSR representation of the interpolation (restriction) operator along the axes where new_shape has more (fewer) elements than the corresponding dimension of shape.
Interpolation operator.
Parameters : | f_in, f_out : array
axis : int, optional
|
---|
Notes
This is a bit of generated C++ code that performs the action of I. The code is generated to allow for arbitrary dimensions etc. in an efficient manner. Here is an example of the completed code for a three-dimensional computation with periodic boundary conditions.
std::vector<int> i(3);
std::vector<int> j(3);
std::vector<int> j_(3);
for (i[0]=j[0]=0;i[0]<n_i[0];j[0]=++i[0]) {
for (i[1]=j[1]=0;i[1]<n_i[1];j[1]=++i[1]) {
for (i[2]=j[2]=0;i[2]<n_i[2];j[2]=++i[2]) {
if (0 == (2 + i[axis] + offset)%2) {
// Direct term
j[axis] = (i[axis] + offset)/2;
periodic(j, Nf_in, j_);
F_OUT3(i[0], i[1], i[2]) = F_IN3(j_[0], j_[1], j_[2]);
} else {
// Interpolation terms
j[axis] = (i[axis] + offset - 1)/2;
periodic(j, n_i, j_);
F_OUT3(i[0], i[1], i[2]) = 0.5*F_IN3(j_[0], j_[1], j_[2]);
j[axis] = (i[axis] + offset + 1)/2;
periodic(j, n_i, j_);
F_OUT3(i[0], i[1], i[2]) += 0.5*F_IN3(j_[0], j_[1], j_[2]);
}
}
}
}
Examples
Interpolation should always preserve constant functions:
>>> i = Interpolator(offset=0, boundary_conditions='Neumann')
>>> f_in = np.ones((4, 3, 3, 3), dtype=float)
>>> f_out = np.ones((4, 3, 6, 3), dtype=float)
>>> res = i.I_inline(f_in=f_in, f_out=f_out, axis=2)
>>> abs(res - 1).max()
0.0
Return a CSR sparse matrix representing the interpolation matrix.
Parameters : | shape : array
n : int
axis : int, optional
|
---|
Notes
This is a bit of generated C++ code that performs the action of I. The code is generated to allow for arbitrary dimensions etc. in an efficient manner. Here is an example of the completed code for a three-dimensional computation with periodic boundary conditions.
std::vector<int> i(3);
std::vector<int> j(3);
std::vector<int> j_(3);
std::vector<int> new_shape(&shape[0], &shape[3]);
new_shape[axis] = n;
int ind = 0;
for (i[0]=j[0]=0;i[0]<new_shape[0];j[0]=++i[0]) {
for (i[1]=j[1]=0;i[1]<new_shape[1];j[1]=++i[1]) {
for (i[2]=j[2]=0;i[2]<new_shape[2];j[2]=++i[2]) {
indptr[index(i, new_shape)] = ind;
if (0 == (2 + i[axis] + offset)%2) {
// Direct term
j[axis] = (i[axis] + offset)/2;
periodic(j, Nf_in, j_);
data[ind] = 1.0;
indices[ind++] = index(j_, shape);
} else {
// Interpolation terms
j[axis] = (i[axis] + offset - 1)/2;
periodic(j, n_i, j_);
data[ind] = 0.5;
indices[ind++] = index(j_, shape);
j[axis] = (i[axis] + offset + 1)/2;
periodic(j, n_i, j_);
data[ind] = 0.5;
indices[ind++] = index(j_, shape);
}
}
}
}
indptr[index(i, n_i)] = ind;
Examples
Interpolation should always preserve constant functions:
>>> i = Interpolator(offset=0, boundary_conditions='Neumann')
>>> f_in = np.ones((4, 3, 3, 3), dtype=float)
>>> f_out = np.ones((4, 3, 6, 3), dtype=float)
>>> res = i.I_inline(f_in=f_in, f_out=f_out, axis=2)
>>> abs(res - 1).max()
0.0
Restriction operator. Implements the transpose of I().
Parameters : | f_in, f_out : array
axis : int, optional
|
---|
Notes
The only difference in the code from I() are:
Bases: object
Various pieces of C++ code and code generators.
x.__init__(...) initializes x; see help(type(x)) for signature
Return (support_code, code, libs, dirs) for solving a*x = b.
Parameters : | N : int
a_var : str, optional
b_var : str, optional
|
---|---|
Returns : | support_code : str
pre_code : str
solve_code : str
libs : [str]
dirs : [str]
|
Examples
>>> a = np.array([[1, 2, 3, 4],
... [1, 3, 5, 7],
... [1, -2, 3, -4],
... [1, 2, -3, -4]], dtype=float)
>>> b = np.array([0, 1, 2, 3], dtype=float)
>>> support_code, pre_code, solve_code, libs, dirs = Code.solve(4)
>>> code = r'''
... %(pre_code)s
... int i, j;
... for (i=0;i<4;i++) {
... for (j=0;j<4;j++) {
... A2(i, j) = A_IN2(i, j);
... }
... }
... %(solve_code)s
... ''' % dict(pre_code=pre_code, solve_code=solve_code)
>>> sp.weave.inline(code=code, arg_names=['a_in', 'b'],
... local_dict=dict(a_in=a, b=b),
... support_code=support_code,
... libraries=libs, library_dirs=dirs)
>>> b
array([-3.5, 2.5, 1.5, -1.5])
>> x = np.linalg.solve(a, b) >> y = lu_solve(a, b) >> np.allclose(a, y) True
Bases: object
Base class for some objects representing derivatives.
x.__init__(...) initializes x; see help(type(x)) for signature
Return (A, B) the stencil for the operators
These are used as follows:
Bases: mmf.math.multigrid.stencil.PoissonBase
Some stencils for 1d derivatives.
>>> Poisson1D.Laplacian
array([ 1., -2., 1.])
x.__init__(...) initializes x; see help(type(x)) for signature
Bases: mmf.math.multigrid.stencil.PoissonBase
Some stencils for 2d derivatives.
>>> Poisson2D.Laplacian
array([[ 0., 1., 0.],
[ 1., -4., 1.],
[ 0., 1., 0.]])
# Now check that this is the same in any orthonormal basis >>> np.random.seed(0) >>> d, _R = np.linalg.qr(np.random.random((2,2))) >>> dinv = d.T >>> L = sum(dinv.T[i,j]*Poisson2D.T[j,k].S*dinv[k,i] ... for i in xrange(2) for j in xrange(2) ... for k in xrange(2)) >>> np.allclose(L, Poisson2D.Laplacian) True
x.__init__(...) initializes x; see help(type(x)) for signature
Bases: mmf.math.multigrid.stencil.PoissonBase
Some stencils for 3d derivatives.
>>> Poisson3D.Laplacian
array([[[ 0., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 0.]],
[[ 0., 1., 0.],
[ 1., -6., 1.],
[ 0., 1., 0.]],
[[ 0., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 0.]]])
# Now check that this is the same in any orthonormal basis >>> np.random.seed(0) >>> d, _R = np.linalg.qr(np.random.random((3,3))) >>> dinv = d.T >>> L = sum(dinv.T[i,j]*Poisson3D.T[j,k].S*dinv[k,i] ... for i in xrange(3) for j in xrange(3) ... for k in xrange(3)) >>> np.allclose(L, Poisson3D.Laplacian) True
x.__init__(...) initializes x; see help(type(x)) for signature