Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Floquet periodic boundary conditions #314

Draft
wants to merge 53 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
86d6055
Try different ways to compute the affine transformation matrix
simlapointe Oct 25, 2024
31a4a9b
Add periodic boundary operator class for periodic/floquet BCs
simlapointe Oct 29, 2024
6420322
Improve Bloch wave vector specification and fix some bugs
simlapointe Oct 31, 2024
707b32b
Initial implementation of floquet periodicity terms in governing equa…
simlapointe Oct 31, 2024
82d1d61
Update surface normal calculation and add planar boundary check
simlapointe Nov 1, 2024
1de268d
Fix some with floquet operators and their use in eigensolver
simlapointe Nov 1, 2024
95502e2
Remove some prints
simlapointe Nov 1, 2024
6021e8f
Add a new matrix for the mass periodic term
simlapointe Nov 8, 2024
0301a71
Ensure enough mesh elements in the periodic direction
simlapointe Nov 12, 2024
63096b3
Debugging tests
simlapointe Nov 13, 2024
974da2a
Debugging tests
simlapointe Nov 19, 2024
3f6bef0
Allow non-symmetric material properties and merge floquet terms in a …
simlapointe Nov 25, 2024
975a274
Merge floquet periodic terms into one operator
simlapointe Nov 25, 2024
57e6d3a
Remove print
simlapointe Nov 25, 2024
c45ef21
Use CEED Symmetric operator
simlapointe Nov 25, 2024
ff552d2
Merge branch 'main' into simlapointe/periodic-bc
simlapointe Nov 25, 2024
5a4f614
Disable divergence-free projection when using Floquet BCs
simlapointe Nov 26, 2024
447df80
Define vector indices in SetOperator
simlapointe Nov 26, 2024
e2d6e46
Constrain Floquet wave vector components
simlapointe Nov 26, 2024
49b29e4
Update comments since quadrature data is no longer symmetric
simlapointe Nov 26, 2024
e8b0d95
Add floquet periodic mass term to auxiliary operator
simlapointe Dec 2, 2024
3b2700c
Merge main
simlapointe Dec 2, 2024
951d70f
Fix formatting
simlapointe Dec 3, 2024
1557829
Merge branch 'main' into simlapointe/periodic-bc
simlapointe Dec 3, 2024
7dfcccc
Warn against using div-free projection and Floquet BCs
simlapointe Dec 4, 2024
e687ab9
Combine periodic terms in a single helper functions
simlapointe Dec 4, 2024
967c6e6
Test term to help aux space smoother
simlapointe Dec 4, 2024
12ab759
Test Floquet terms in divergence free projection
simlapointe Dec 6, 2024
e713a6f
Clean and reorganize automated periodic boundary matching
simlapointe Dec 6, 2024
b5ef9bd
Remove print
simlapointe Dec 6, 2024
9382889
Use symmetricOperator
simlapointe Dec 6, 2024
6a27333
Add Floquet BC regression test
simlapointe Dec 6, 2024
bebcab6
Allow Floquet wave vector specification for meshes with and without b…
simlapointe Dec 9, 2024
1101ef9
Fix error in VERIFY
simlapointe Dec 10, 2024
0dd577d
Implement B field Floquet correction
simlapointe Dec 10, 2024
00e4b8c
Clean up periodic transform detection
simlapointe Dec 10, 2024
cc6aeca
Undo Floquet divfree test
simlapointe Dec 12, 2024
0a862ec
Use RT-space B field correction
simlapointe Dec 12, 2024
f2288a5
Remove Aux space preconditioner tests
simlapointe Dec 12, 2024
9fbe941
Remove print
simlapointe Dec 12, 2024
b865e9c
Undo Aux space preconditioner tests
simlapointe Dec 12, 2024
18eab19
Remove print
simlapointe Dec 12, 2024
a01573c
Remove unnecessary include
simlapointe Dec 12, 2024
76e325b
Update regression test results
simlapointe Dec 12, 2024
650dce3
Fix formatting
simlapointe Dec 12, 2024
2e2ae18
Update CHANGELOG
simlapointe Dec 13, 2024
102386d
Remove prints
simlapointe Dec 13, 2024
7a1d90e
Initialize Floquet correction solver outside of frequency loop
simlapointe Dec 13, 2024
14c8ce3
Remove unnecessary comments
simlapointe Dec 13, 2024
7259f7c
Update schema for Floquet BCs
simlapointe Dec 13, 2024
4ea97e0
Fix bug assuming symmetric coefficients
simlapointe Dec 13, 2024
d72f40d
Update waveguide example
simlapointe Dec 13, 2024
320b333
Merge branch 'main' into simlapointe/periodic-bc
simlapointe Dec 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ The format of this changelog is based on
- Added adaptive time-stepping capability for transient simulations. The new ODE integrators
rely on the SUNDIALS library and can be specified by setting the
`config["Solver"]["Transient"]["Type"]` option to `"CVODE"` or `"ARKODE"`.
- Added support for Floquet periodic boundary conditions with phase-delay constraints.
The Floquet wave vector can be specified along with periodic boundaries in the
`config["Boundaries"]["Periodic"]` configuration.

## [0.13.0] - 2024-05-20

Expand Down
31 changes: 27 additions & 4 deletions docs/src/config/boundaries.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,10 @@ electrostatic simulations. Entries of the capacitance matrix are extracted corre
each terminal boundary.

`"Periodic"` : Array of objects for configuring periodic boundary conditions for surfaces
with meshes that are identical after a specified translation.
with meshes that are identical after translation and/or rotation.

`"FloquetWaveVector"` : Object for configuring Floquet periodic boundary conditions for
meshes generated with built-in periodicity.

`"Postprocessing"` : Top-level object for configuring boundary postprocessing.

Expand Down Expand Up @@ -527,7 +530,9 @@ boundary.
{
"DonorAttributes": [<int array>],
"ReceiverAttributes": [<int array>],
"Translation": [<float array>]
"Translation": [<float array>],
"AffineTransformation": [<float array>],
"FloquetWaveVector": [<float array>]
},
...
]
Expand All @@ -541,8 +546,26 @@ attributes for this periodic boundary.
`"ReceiverAttributes" [None]` : Integer array of the receiver attributes of the mesh boundary
attributes for this periodic boundary.

`"Translation" [None]` : Defines the distance between the donor and receiver attributes in
mesh units.
`"Translation" [None]` : Optional floating point array defining the distance between the donor
and receiver attributes in mesh units. If neither `"Translation"` or `"AffineTransformation"` are
specified, the transformation between donor and receiver boundaries is automatically detected.

`"AffineTransformation" [None]` : Optional floating point array of size 16 defining the
three-dimensional (4 x 4) affine transformation matrix (in row major format) between the donor
and receiver attributes in mesh units. If neither `"Translation"` or `"AffineTransformation"` are
specified, the transformation between donor and receiver boundaries is automatically detected.

`"FloquetWaveVector" [None]` : Optional floating point array defining the phase delay between
this pair of donor and receiver periodic boundaries in the X/Y/Z directions in radians per mesh
unit. If multiple periodic boundary pairs are used, the Floquet wave vector will be summed over
the periodic boundary pairs.

## `boundaries["FloquetWaveVector"]`

Optional floating point array defining the phase delay between the periodic boundaries in the X/Y/Z
directions in radians per mesh unit, for meshes generated with built-in periodicity. This should not
be used for non-periodic meshes, or for meshes generated without built-in periodicity. In the latter
case, the Floquet wave vector should be specified via `"boundaries["Periodic"]["FloquetWaveVector"]"`.

## `boundaries["Postprocessing"]["SurfaceFlux"]`

Expand Down
11 changes: 7 additions & 4 deletions docs/src/examples/cylinder.md
Original file line number Diff line number Diff line change
Expand Up @@ -254,15 +254,18 @@ such modes to higher frequencies. The relevant modes are tabulated as

For this problem, we use curved tetrahedral elements from the mesh file
[`mesh/cavity_tet.msh`](https://github.com/awslabs/palace/blob/main/examples/cylinder/mesh/cavity_tet.msh),
and the configuration file
[`waveguide.json`](https://github.com/awslabs/palace/blob/main/examples/cylinder/waveguide.json).
and the configuration files
[`waveguide.json`](https://github.com/awslabs/palace/blob/main/examples/cylinder/waveguide.json) and
[`floquet.json`](https://github.com/awslabs/palace/blob/main/examples/cylinder/floquet.json).

The main difference between this configuration file and those used in the cavity example is
The main difference between these configuration files and those used in the cavity example is
in the `"Boundaries"` object: `waveguide.json` specifies a perfect electric conductor
(`"PEC"`) boundary condition for the exterior surface and a periodic boundary condition
(`"Periodic"`) on the cross-sections of the cylinder (in the $z-$ direction). The periodic
attribute pairs are defined by `"DonorAttributes"` and `"ReceiverAttributes"`, and the
distance between them is given by the `"Translation"` vector in mesh units.
distance between them is given by the `"Translation"` vector in mesh units. In `floquet.json`,
an additional `"FloquetWaveVector"` specifies the phase delay between the donor and receiver
boundaries in the X/Y/Z directions.

The file `postpro/waveguide/eig.csv` contains information about the computed eigenfrequencies and
associated quality factors:
Expand Down
2 changes: 1 addition & 1 deletion docs/src/guide/boundaries.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ Periodic boundary conditions on an existing mesh can be specified using the
["Periodic"](../config/boundaries.md#boundaries%5B%22Periodic%22%5D) boundary keyword. This
boundary condition enforces that the solution on the specified boundaries be exactly equal,
and requires that the surface meshes on the donor and receiver boundaries be identical up to
translation. Periodicity in *Palace* is also supported through meshes generated
translation or rotation. Periodicity in *Palace* is also supported through meshes generated
incorporating periodicity as part of the meshing process.

## Lumped and wave port excitation
Expand Down
69 changes: 69 additions & 0 deletions examples/cylinder/floquet.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
{
"Problem":
{
"Type": "Eigenmode",
"Verbose": 2,
"Output": "postpro/floquet"
},
"Model":
{
"Mesh": "mesh/cylinder_tet.msh",
"L0": 1.0e-2, // cm
},
"Domains":
{
"Materials":
[
{
"Attributes": [1],
"Permeability": 1.0,
"Permittivity": 2.08,
"LossTan": 0.0004
}
],
"Postprocessing":
{
"Energy":
[
{
"Index": 1,
"Attributes": [1]
}
]
}
},
"Boundaries":
{
"Periodic":
[
{
"DonorAttributes": [2],
"ReceiverAttributes": [3],
"FloquetWaveVector": [0.0, 0.0, 0.2]
}
],
"PEC":
{
"Attributes": [4]
}
},
"Solver":
{
"Order": 4,
"Device": "CPU",
"Eigenmode":
{
"N": 15,
"Tol": 1.0e-8,
"Target": 2.0, // TE f111 ~ 2.9 GHz
"Save": 15
},
"Linear":
{
"Type": "Default",
"KSPType": "GMRES",
"Tol": 1.0e-8,
"MaxIts": 100
}
}
}
2 changes: 1 addition & 1 deletion examples/cylinder/waveguide.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
{
"DonorAttributes": [2],
"ReceiverAttributes": [3],
"Translation": [0.0, 0.0, 5.48] // in L0 units
"Translation": [0.0, 0.0, -5.48] // in L0 units
}
],
"PEC":
Expand Down
22 changes: 19 additions & 3 deletions palace/drivers/drivensolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "fem/errorindicator.hpp"
#include "fem/mesh.hpp"
#include "linalg/errorestimator.hpp"
#include "linalg/floquetcorrection.hpp"
#include "linalg/ksp.hpp"
#include "linalg/operator.hpp"
#include "linalg/vector.hpp"
Expand Down Expand Up @@ -117,17 +118,17 @@ ErrorIndicator DrivenSolver::SweepUniform(SpaceOperator &space_op, PostOperator
auto C = space_op.GetDampingMatrix<ComplexOperator>(Operator::DIAG_ZERO);
auto M = space_op.GetMassMatrix<ComplexOperator>(Operator::DIAG_ZERO);
auto A2 = space_op.GetExtraSystemMatrix<ComplexOperator>(omega0, Operator::DIAG_ZERO);
auto FP = space_op.GetFloquetMatrix<ComplexOperator>(Operator::DIAG_ZERO);
const auto &Curl = space_op.GetCurlMatrix();

// Set up the linear solver and set operators for the first frequency step. The
// preconditioner for the complex linear system is constructed from a real approximation
// to the complex system matrix.
auto A = space_op.GetSystemMatrix(std::complex<double>(1.0, 0.0), 1i * omega0,
std::complex<double>(-omega0 * omega0, 0.0), K.get(),
C.get(), M.get(), A2.get());
C.get(), M.get(), A2.get(), FP.get());
auto P = space_op.GetPreconditionerMatrix<ComplexOperator>(1.0, omega0, -omega0 * omega0,
omega0);

ComplexKspSolver ksp(iodata, space_op.GetNDSpaces(), &space_op.GetH1Spaces());
ksp.SetOperators(*A, *P);

Expand All @@ -147,6 +148,15 @@ ErrorIndicator DrivenSolver::SweepUniform(SpaceOperator &space_op, PostOperator
iodata.solver.linear.estimator_mg);
ErrorIndicator indicator;

// If using Floquet BCs, a correction term (kp x E) needs to be added to the B field.
std::unique_ptr<FloquetCorrSolver<ComplexVector>> floquet_corr;
if (FP)
{
floquet_corr = std::make_unique<FloquetCorrSolver<ComplexVector>>(
space_op.GetMaterialOp(), space_op.GetPeriodicOp(), space_op.GetNDSpace(),
space_op.GetRTSpace(), iodata.solver.linear.tol, iodata.solver.linear.max_it, 0);
}

// Main frequency sweep loop.
int step = step0;
double omega = omega0;
Expand All @@ -164,7 +174,7 @@ ErrorIndicator DrivenSolver::SweepUniform(SpaceOperator &space_op, PostOperator
A2 = space_op.GetExtraSystemMatrix<ComplexOperator>(omega, Operator::DIAG_ZERO);
A = space_op.GetSystemMatrix(std::complex<double>(1.0, 0.0), 1i * omega,
std::complex<double>(-omega * omega, 0.0), K.get(),
C.get(), M.get(), A2.get());
C.get(), M.get(), A2.get(), FP.get());
P = space_op.GetPreconditionerMatrix<ComplexOperator>(1.0, omega, -omega * omega,
omega);
ksp.SetOperators(*A, *P);
Expand All @@ -179,6 +189,12 @@ ErrorIndicator DrivenSolver::SweepUniform(SpaceOperator &space_op, PostOperator
Curl.Mult(E.Real(), B.Real());
Curl.Mult(E.Imag(), B.Imag());
B *= -1.0 / (1i * omega);
if (FP)
{
// Calculate B field correction for Floquet BCs.
// B = -1/(iω) ∇ x E - 1/ω kp x E
floquet_corr->AddMult(E, B, -1.0 / omega);
}
post_op.SetEGridFunction(E);
post_op.SetBGridFunction(B);
post_op.UpdatePorts(space_op.GetLumpedPortOp(), space_op.GetWavePortOp(), omega);
Expand Down
42 changes: 38 additions & 4 deletions palace/drivers/eigensolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "linalg/arpack.hpp"
#include "linalg/divfree.hpp"
#include "linalg/errorestimator.hpp"
#include "linalg/floquetcorrection.hpp"
#include "linalg/ksp.hpp"
#include "linalg/operator.hpp"
#include "linalg/slepc.hpp"
Expand Down Expand Up @@ -36,6 +37,10 @@ EigenSolver::Solve(const std::vector<std::unique_ptr<Mesh>> &mesh) const
auto K = space_op.GetStiffnessMatrix<ComplexOperator>(Operator::DIAG_ONE);
auto C = space_op.GetDampingMatrix<ComplexOperator>(Operator::DIAG_ZERO);
auto M = space_op.GetMassMatrix<ComplexOperator>(Operator::DIAG_ZERO);
auto FP = space_op.GetFloquetMatrix<ComplexOperator>(Operator::DIAG_ZERO);
auto A2 = space_op.GetExtraSystemMatrix<ComplexOperator>(1.0, Operator::DIAG_ZERO);
A2 = nullptr;

const auto &Curl = space_op.GetCurlMatrix();
SaveMetadata(space_op.GetNDSpaces());

Expand Down Expand Up @@ -124,11 +129,25 @@ EigenSolver::Solve(const std::vector<std::unique_ptr<Mesh>> &mesh) const
: EigenvalueSolver::ScaleType::NONE;
if (C)
{
eigen->SetOperators(*K, *C, *M, scale);
if (FP)
{
eigen->SetOperators(*K, *C, *M, *FP, scale);
}
else
{
eigen->SetOperators(*K, *C, *M, scale);
}
}
else
{
eigen->SetOperators(*K, *M, scale);
if (FP)
{
eigen->SetOperators(*K, *M, *FP, scale);
}
else
{
eigen->SetOperators(*K, *M, scale);
}
}
eigen->SetNumModes(iodata.solver.eigenmode.n, iodata.solver.eigenmode.max_size);
eigen->SetTol(iodata.solver.eigenmode.tol);
Expand All @@ -154,7 +173,7 @@ EigenSolver::Solve(const std::vector<std::unique_ptr<Mesh>> &mesh) const
// Construct a divergence-free projector so the eigenvalue solve is performed in the space
// orthogonal to the zero eigenvalues of the stiffness matrix.
std::unique_ptr<DivFreeSolver<ComplexVector>> divfree;
if (iodata.solver.linear.divfree_max_it > 0)
if (iodata.solver.linear.divfree_max_it > 0 && !FP)
{
Mpi::Print(" Configuring divergence-free projection\n");
constexpr int divfree_verbose = 0;
Expand All @@ -165,6 +184,15 @@ EigenSolver::Solve(const std::vector<std::unique_ptr<Mesh>> &mesh) const
eigen->SetDivFreeProjector(*divfree);
}

// If using Floquet BCs, a correction term (kp x E) needs to be added to the B field.
std::unique_ptr<FloquetCorrSolver<ComplexVector>> floquet_corr;
if (FP)
{
floquet_corr = std::make_unique<FloquetCorrSolver<ComplexVector>>(
space_op.GetMaterialOp(), space_op.GetPeriodicOp(), space_op.GetNDSpace(),
space_op.GetRTSpace(), iodata.solver.linear.tol, iodata.solver.linear.max_it, 0);
}

// Set up the initial space for the eigenvalue solve. Satisfies boundary conditions and is
// projected appropriately.
if (iodata.solver.eigenmode.init_v0)
Expand Down Expand Up @@ -242,7 +270,7 @@ EigenSolver::Solve(const std::vector<std::unique_ptr<Mesh>> &mesh) const
// to the complex system matrix.
auto A = space_op.GetSystemMatrix(std::complex<double>(1.0, 0.0), 1i * target,
std::complex<double>(-target * target, 0.0), K.get(),
C.get(), M.get());
C.get(), M.get(), A2.get(), FP.get());
auto P = space_op.GetPreconditionerMatrix<ComplexOperator>(1.0, target, -target * target,
target);
auto ksp = std::make_unique<ComplexKspSolver>(iodata, space_op.GetNDSpaces(),
Expand Down Expand Up @@ -306,6 +334,12 @@ EigenSolver::Solve(const std::vector<std::unique_ptr<Mesh>> &mesh) const
Curl.Mult(E.Real(), B.Real());
Curl.Mult(E.Imag(), B.Imag());
B *= -1.0 / (1i * omega);
if (FP)
{
// Calculate B field correction for Floquet BCs.
// B = -1/(iω) ∇ x E - 1/ω kp x E.
floquet_corr->AddMult(E, B, -1.0 / omega);
}
post_op.SetEGridFunction(E);
post_op.SetBGridFunction(B);
post_op.UpdatePorts(space_op.GetLumpedPortOp(), omega.real());
Expand Down
11 changes: 5 additions & 6 deletions palace/fem/libceed/coefficient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace

inline auto CoeffDim(int dim)
{
return dim * (dim + 1) / 2;
return dim * dim;
}

inline void MakeDiagonalCoefficient(int dim, CeedIntScalar *mat_coeff, CeedScalar a,
Expand All @@ -30,7 +30,7 @@ inline void MakeDiagonalCoefficient(int dim, CeedIntScalar *mat_coeff, CeedScala
}
for (int di = 0; di < dim; ++di)
{
const int idx = (di * dim) - (((di - 1) * di) / 2);
const int idx = di * (dim + 1);
mat_coeff[coeff_dim * k + idx].second = a;
}
}
Expand Down Expand Up @@ -86,8 +86,7 @@ PopulateCoefficientContext(int dim, const MaterialPropertyCoefficient *Q, double
AttrMat(ctx.data())[i].first = (k < 0) ? zero_mat : k;
}

// Copy material properties: Matrix-valued material properties are always assumed to be
// symmetric and we store only the lower triangular part.
// Copy material properties
ctx[1 + attr_mat.Size()].first = mat_coeff.SizeK() + 1;
for (int k = 0; k < mat_coeff.SizeK(); k++)
{
Expand All @@ -100,10 +99,10 @@ PopulateCoefficientContext(int dim, const MaterialPropertyCoefficient *Q, double
{
for (int dj = 0; dj < dim; ++dj)
{
for (int di = dj; di < dim; ++di)
for (int di = 0; di < dim; ++di)
{
// Column-major ordering.
const int idx = (dj * dim) - (((dj - 1) * dj) / 2) + di - dj;
const int idx = (dj * dim) + di;
MatCoeff(ctx.data())[coeff_dim * k + idx].second = a * mat_coeff(di, dj, k);
}
}
Expand Down
2 changes: 1 addition & 1 deletion palace/fem/libceed/integrator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ std::vector<CeedInt> QuadratureDataSetup(unsigned int ops, Ceed ceed,
PalaceCeedCall(ceed, CeedBasisGetNumQuadraturePoints(basis, &num_qpts));
for (auto size : active_input_sizes)
{
q_data_size += size * (size + 1) / 2;
q_data_size += size * size;
}

PalaceCeedCall(
Expand Down
3 changes: 3 additions & 0 deletions palace/fem/libceed/operator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ class Operator : public palace::Operator
~Operator() override;

CeedOperator operator[](std::size_t i) const { return op[i]; }

CeedOperator GetTranspose(std::size_t i) const { return op_t[i]; }

auto Size() const { return op.size(); }

void AddSubOperator(CeedOperator sub_op, CeedOperator sub_op_t = nullptr);
Expand Down
Loading
Loading