Skip to content

Commit

Permalink
Merge branch 'devel' into add_Hvec
Browse files Browse the repository at this point in the history
  • Loading branch information
yguclu authored Oct 25, 2023
2 parents 3973ce5 + 4c53ac3 commit edd4cca
Show file tree
Hide file tree
Showing 11 changed files with 377 additions and 136 deletions.
31 changes: 29 additions & 2 deletions psydac/api/tests/test_api_feec_1d.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def update_plot(ax, t, sol_ex, sol_num):
#==============================================================================
def run_maxwell_1d(*, L, eps, ncells, degree, periodic, Cp, nsteps, tend,
splitting_order, plot_interval, diagnostics_interval,
bc_mode, tol, verbose):
bc_mode, tol, verbose, mult=1):

import numpy as np
import matplotlib.pyplot as plt
Expand Down Expand Up @@ -132,7 +132,7 @@ class CollelaMapping1D(Mapping):

# Discrete physical domain and discrete DeRham sequence
domain_h = discretize(domain, ncells=[ncells], periodic=[periodic], comm=MPI.COMM_WORLD)
derham_h = discretize(derham, domain_h, degree=[degree])
derham_h = discretize(derham, domain_h, degree=[degree], multiplicity=[mult])

# Discrete bilinear forms
a0_h = discretize(a0, domain_h, (derham_h.V0, derham_h.V0), backend=PSYDAC_BACKEND_PYTHON)
Expand Down Expand Up @@ -496,6 +496,33 @@ def test_maxwell_1d_periodic():

assert abs(namespace['error_E'] - ref['error_E']) / ref['error_E'] <= TOL
assert abs(namespace['error_B'] - ref['error_B']) / ref['error_B'] <= TOL

def test_maxwell_1d_periodic_mult():

namespace = run_maxwell_1d(
L = 1.0,
eps = 0.5,
ncells = 30,
degree = 3,
periodic = True,
Cp = 0.5,
nsteps = 1,
tend = None,
splitting_order = 2,
plot_interval = 0,
diagnostics_interval = 0,
tol = 1e-6,
bc_mode = None,
verbose = False,
mult = 2
)

TOL = 1e-6
ref = dict(error_E = 4.24689338e-04,
error_B = 4.03195792e-04)

assert abs(namespace['error_E'] - ref['error_E']) / ref['error_E'] <= TOL
assert abs(namespace['error_B'] - ref['error_B']) / ref['error_B'] <= TOL


def test_maxwell_1d_dirichlet_strong():
Expand Down
91 changes: 88 additions & 3 deletions psydac/api/tests/test_api_feec_2d.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ def update_plot(fig, t, x, y, field_h, field_ex):
def run_maxwell_2d_TE(*, use_spline_mapping,
eps, ncells, degree, periodic,
Cp, nsteps, tend,
splitting_order, plot_interval, diagnostics_interval, tol, verbose):
splitting_order, plot_interval, diagnostics_interval, tol, verbose, mult=1):

import os

Expand Down Expand Up @@ -290,7 +290,7 @@ class CollelaMapping2D(Mapping):
#--------------------------------------------------------------------------
if use_spline_mapping:
domain_h = discretize(domain, filename=filename, comm=MPI.COMM_WORLD)
derham_h = discretize(derham, domain_h)
derham_h = discretize(derham, domain_h, multiplicity = [mult,mult])

periodic_list = mapping.get_callable_mapping().space.periodic
degree_list = mapping.get_callable_mapping().space.degree
Expand All @@ -311,7 +311,7 @@ class CollelaMapping2D(Mapping):
else:
# Discrete physical domain and discrete DeRham sequence
domain_h = discretize(domain, ncells=[ncells, ncells], periodic=[periodic, periodic], comm=MPI.COMM_WORLD)
derham_h = discretize(derham, domain_h, degree=[degree, degree])
derham_h = discretize(derham, domain_h, degree=[degree, degree], multiplicity = [mult,mult])

# Discrete bilinear forms
a1_h = discretize(a1, domain_h, (derham_h.V1, derham_h.V1), backend=PSYDAC_BACKEND_GPYCCEL)
Expand Down Expand Up @@ -710,6 +710,91 @@ def test_maxwell_2d_periodic():
assert abs(namespace['error_Ey'] - ref['error_Ey']) / ref['error_Ey'] <= TOL
assert abs(namespace['error_Bz'] - ref['error_Bz']) / ref['error_Bz'] <= TOL

def test_maxwell_2d_multiplicity():

namespace = run_maxwell_2d_TE(
use_spline_mapping = False,
eps = 0.5,
ncells = 10,
degree = 5,
periodic = False,
Cp = 0.5,
nsteps = 1,
tend = None,
splitting_order = 2,
plot_interval = 0,
diagnostics_interval = 0,
tol = 1e-6,
verbose = False,
mult = 2
)

TOL = 1e-5
ref = dict(error_l2_Ex = 4.350041934920621e-04,
error_l2_Ey = 4.350041934920621e-04,
error_l2_Bz = 3.76106860e-03)

assert abs(namespace['error_l2_Ex'] - ref['error_l2_Ex']) / ref['error_l2_Ex'] <= TOL
assert abs(namespace['error_l2_Ey'] - ref['error_l2_Ey']) / ref['error_l2_Ey'] <= TOL
assert abs(namespace['error_l2_Bz'] - ref['error_l2_Bz']) / ref['error_l2_Bz'] <= TOL

def test_maxwell_2d_periodic_multiplicity():

namespace = run_maxwell_2d_TE(
use_spline_mapping = False,
eps = 0.5,
ncells = 30,
degree = 3,
periodic = True,
Cp = 0.5,
nsteps = 1,
tend = None,
splitting_order = 2,
plot_interval = 0,
diagnostics_interval = 0,
tol = 1e-6,
verbose = False,
mult =2
)

TOL = 1e-6
ref = dict(error_l2_Ex = 1.78557685e-04,
error_l2_Ey = 1.78557685e-04,
error_l2_Bz = 1.40582413e-04)

assert abs(namespace['error_l2_Ex'] - ref['error_l2_Ex']) / ref['error_l2_Ex'] <= TOL
assert abs(namespace['error_l2_Ey'] - ref['error_l2_Ey']) / ref['error_l2_Ey'] <= TOL
assert abs(namespace['error_l2_Bz'] - ref['error_l2_Bz']) / ref['error_l2_Bz'] <= TOL


def test_maxwell_2d_periodic_multiplicity_equal_deg():

namespace = run_maxwell_2d_TE(
use_spline_mapping = False,
eps = 0.5,
ncells = 10,
degree = 2,
periodic = True,
Cp = 0.5,
nsteps = 1,
tend = None,
splitting_order = 2,
plot_interval = 0,
diagnostics_interval = 0,
tol = 1e-6,
verbose = False,
mult =2
)

TOL = 1e-6
ref = dict(error_l2_Ex = 2.50585008e-02,
error_l2_Ey = 2.50585008e-02,
error_l2_Bz = 1.58438290e-02)

assert abs(namespace['error_l2_Ex'] - ref['error_l2_Ex']) / ref['error_l2_Ex'] <= TOL
assert abs(namespace['error_l2_Ey'] - ref['error_l2_Ey']) / ref['error_l2_Ey'] <= TOL
assert abs(namespace['error_l2_Bz'] - ref['error_l2_Bz']) / ref['error_l2_Bz'] <= TOL


def test_maxwell_2d_dirichlet():

Expand Down
52 changes: 48 additions & 4 deletions psydac/api/tests/test_api_feec_3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def evaluation_all_times(fields, x, y, z):
return ak_value

#==================================================================================
def run_maxwell_3d_scipy(logical_domain, mapping, e_ex, b_ex, ncells, degree, periodic, dt, niter):
def run_maxwell_3d_scipy(logical_domain, mapping, e_ex, b_ex, ncells, degree, periodic, dt, niter, mult=1):

#------------------------------------------------------------------------------
# Symbolic objects: SymPDE
Expand All @@ -113,7 +113,7 @@ def run_maxwell_3d_scipy(logical_domain, mapping, e_ex, b_ex, ncells, degree, pe
#------------------------------------------------------------------------------

domain_h = discretize(domain, ncells=ncells, periodic=periodic, comm=MPI.COMM_WORLD)
derham_h = discretize(derham, domain_h, degree=degree)
derham_h = discretize(derham, domain_h, degree=degree, multiplicity = [mult,mult,mult])

a1_h = discretize(a1, domain_h, (derham_h.V1, derham_h.V1), backend=PSYDAC_BACKEND_GPYCCEL)
a2_h = discretize(a2, domain_h, (derham_h.V2, derham_h.V2), backend=PSYDAC_BACKEND_GPYCCEL)
Expand Down Expand Up @@ -181,7 +181,7 @@ def run_maxwell_3d_scipy(logical_domain, mapping, e_ex, b_ex, ncells, degree, pe
return error

#==================================================================================
def run_maxwell_3d_stencil(logical_domain, mapping, e_ex, b_ex, ncells, degree, periodic, dt, niter):
def run_maxwell_3d_stencil(logical_domain, mapping, e_ex, b_ex, ncells, degree, periodic, dt, niter, mult=1):

#------------------------------------------------------------------------------
# Symbolic objects: SymPDE
Expand All @@ -208,7 +208,7 @@ def run_maxwell_3d_stencil(logical_domain, mapping, e_ex, b_ex, ncells, degree,
#------------------------------------------------------------------------------

domain_h = discretize(domain, ncells=ncells, periodic=periodic, comm=MPI.COMM_WORLD)
derham_h = discretize(derham, domain_h, degree=degree)
derham_h = discretize(derham, domain_h, degree=degree, multiplicity = [mult,mult,mult])

a1_h = discretize(a1, domain_h, (derham_h.V1, derham_h.V1), backend=PSYDAC_BACKEND_GPYCCEL)
a2_h = discretize(a2, domain_h, (derham_h.V2, derham_h.V2), backend=PSYDAC_BACKEND_GPYCCEL)
Expand Down Expand Up @@ -356,6 +356,46 @@ class CollelaMapping3D(Mapping):

error = run_maxwell_3d_stencil(logical_domain, M, e_ex, b_ex, ncells, degree, periodic, dt, niter)
assert abs(error - 0.24586986658559362) < 1e-9

#------------------------------------------------------------------------------
def test_maxwell_3d_2_mult():
class CollelaMapping3D(Mapping):

_expressions = {'x': 'k1*(x1 + eps*sin(2.*pi*x1)*sin(2.*pi*x2))',
'y': 'k2*(x2 + eps*sin(2.*pi*x1)*sin(2.*pi*x2))',
'z': 'k3*x3'}

_ldim = 3
_pdim = 3

M = CollelaMapping3D('M', k1=1, k2=1, k3=1, eps=0.1)
logical_domain = Cube('C', bounds1=(0, 1), bounds2=(0, 1), bounds3=(0, 1))

# exact solution
e_ex_0 = lambda t, x, y, z: 0
e_ex_1 = lambda t, x, y, z: -np.cos(2*np.pi*t-2*np.pi*z)
e_ex_2 = lambda t, x, y, z: 0

e_ex = (e_ex_0, e_ex_1, e_ex_2)

b_ex_0 = lambda t, x, y, z : np.cos(2*np.pi*t-2*np.pi*z)
b_ex_1 = lambda t, x, y, z : 0
b_ex_2 = lambda t, x, y, z : 0

b_ex = (b_ex_0, b_ex_1, b_ex_2)

#space parameters
ncells = [7, 7, 7]
degree = [2, 2, 2]
periodic = [True, True, True]

#time parameters
dt = 0.5*1/max(ncells)
niter = 2
T = dt*niter

error = run_maxwell_3d_stencil(logical_domain, M, e_ex, b_ex, ncells, degree, periodic, dt, niter, mult=2)
assert abs(error - 0.24749763720543216) < 1e-9

#==============================================================================
# CLEAN UP SYMPY NAMESPACE
Expand All @@ -368,4 +408,8 @@ def teardown_module():
def teardown_function():
from sympy.core import cache
cache.clear_cache()

if __name__ == '__main__' :
test_maxwell_3d_2_mult()


47 changes: 32 additions & 15 deletions psydac/core/bsplines.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ def basis_funs_all_ders(knots, degree, x, span, n, normalization='B', out=None):
return out

#==============================================================================
def collocation_matrix(knots, degree, periodic, normalization, xgrid, out=None):
def collocation_matrix(knots, degree, periodic, normalization, xgrid, out=None, multiplicity = 1):
"""Computes the collocation matrix
If called with normalization='M', this uses M-splines instead of B-splines.
Expand All @@ -326,6 +326,10 @@ def collocation_matrix(knots, degree, periodic, normalization, xgrid, out=None):
out : array, optional
If provided, the result will be inserted into this array.
It should be of the appropriate shape and dtype.
multiplicity : int
Multiplicity of the knots in the knot sequence, we assume that the same
multiplicity applies to each interior knot.
Returns
-------
Expand All @@ -342,19 +346,20 @@ def collocation_matrix(knots, degree, periodic, normalization, xgrid, out=None):
if out is None:
nb = len(knots) - degree - 1
if periodic:
nb -= degree
nb -= degree + 1 - multiplicity

out = np.zeros((xgrid.shape[0], nb), dtype=float)
else:
assert out.shape == ((xgrid.shape[0], nb)) and out.dtype == np.dtype('float')

bool_normalization = normalization == "M"
multiplicity = int(multiplicity)

collocation_matrix_p(knots, degree, periodic, bool_normalization, xgrid, out)
collocation_matrix_p(knots, degree, periodic, bool_normalization, xgrid, out, multiplicity=multiplicity)
return out

#==============================================================================
def histopolation_matrix(knots, degree, periodic, normalization, xgrid, check_boundary=True, out=None):
def histopolation_matrix(knots, degree, periodic, normalization, xgrid, multiplicity=1, check_boundary=True, out=None):
"""Computes the histopolation matrix.
If called with normalization='M', this uses M-splines instead of B-splines.
Expand All @@ -375,6 +380,10 @@ def histopolation_matrix(knots, degree, periodic, normalization, xgrid, check_bo
xgrid : array_like
Grid points.
multiplicity : int
Multiplicity of the knots in the knot sequence, we assume that the same
multiplicity applies to each interior knot.
check_boundary : bool, default=True
If true and ``periodic``, will check the boundaries of ``xgrid``.
Expand Down Expand Up @@ -418,23 +427,23 @@ def histopolation_matrix(knots, degree, periodic, normalization, xgrid, check_bo

knots = np.ascontiguousarray(knots, dtype=float)
xgrid = np.ascontiguousarray(xgrid, dtype=float)
elevated_knots = elevate_knots(knots, degree, periodic)
elevated_knots = elevate_knots(knots, degree, periodic, multiplicity=multiplicity)

normalization = normalization == "M"

if out is None:
if periodic:
out = np.zeros((len(xgrid), len(knots) - 2 * degree - 1), dtype=float)
out = np.zeros((len(xgrid), len(knots) - 2 * degree - 2 + multiplicity), dtype=float)
else:
out = np.zeros((len(xgrid) - 1, len(elevated_knots) - (degree + 1) - 1 - 1), dtype=float)
else:
if periodic:
assert out.shape == (len(xgrid), len(knots) - 2 * degree - 1)
assert out.shape == (len(xgrid), len(knots) - 2 * degree - 2 + multiplicity)
else:
assert out.shape == (len(xgrid) - 1, len(elevated_knots) - (degree + 1) - 1 - 1)
assert out.dtype == np.dtype('float')

histopolation_matrix_p(knots, degree, periodic, normalization, xgrid, check_boundary, elevated_knots, out)
multiplicity = int(multiplicity)
histopolation_matrix_p(knots, degree, periodic, normalization, xgrid, check_boundary, elevated_knots, out, multiplicity = multiplicity)
return out

#==============================================================================
Expand Down Expand Up @@ -472,7 +481,7 @@ def breakpoints(knots, degree, tol=1e-15, out=None):
return out[:i_final]

#==============================================================================
def greville(knots, degree, periodic, out=None):
def greville(knots, degree, periodic, out=None, multiplicity=1):
"""
Compute coordinates of all Greville points.
Expand All @@ -490,6 +499,10 @@ def greville(knots, degree, periodic, out=None):
out : array, optional
If provided, the result will be inserted into this array.
It should be of the appropriate shape and dtype.
multiplicity : int
Multiplicity of the knots in the knot sequence, we assume that the same
multiplicity applies to each interior knot.
Returns
-------
Expand All @@ -499,9 +512,10 @@ def greville(knots, degree, periodic, out=None):
"""
knots = np.ascontiguousarray(knots, dtype=float)
if out is None:
n = len(knots) - 2 * degree - 1 if periodic else len(knots) - degree - 1
n = len(knots) - 2 * degree - 2 + multiplicity if periodic else len(knots) - degree - 1
out = np.zeros(n)
greville_p(knots, degree, periodic, out)
multiplicity = int(multiplicity)
greville_p(knots, degree, periodic, out, multiplicity)
return out

#===============================================================================
Expand Down Expand Up @@ -560,9 +574,12 @@ def elements_spans(knots, degree, out=None):
def make_knots(breaks, degree, periodic, multiplicity=1, out=None):
"""
Create spline knots from breakpoints, with appropriate boundary conditions.
Let p be spline degree. If domain is periodic, knot sequence is extended
by periodicity so that first p basis functions are identical to last p.
Otherwise, knot sequence is clamped (i.e. endpoints are repeated p times).
If domain is periodic, knot sequence is extended by periodicity to have a
total of (n_cells-1)*mult+2p+2 knots (all break points are repeated mult
time and we add p+1-mult knots by periodicity at each side).
Otherwise, knot sequence is clamped (i.e. endpoints have multiplicity p+1).
Parameters
----------
Expand Down
Loading

0 comments on commit edd4cca

Please sign in to comment.