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

Non-orthogonal mesh improvements #166

Open
wants to merge 32 commits into
base: master
Choose a base branch
from
Open

Non-orthogonal mesh improvements #166

wants to merge 32 commits into from

Conversation

bendudson
Copy link
Contributor

@bendudson bendudson commented Jan 27, 2023

I think this is now ready for others to try out.

This PR adds a new way to optimise meshes, to generate non-orthogonal meshes that align to the walls of the domain and have other "nice" properties. The idea is to start with an orthogonal mesh, then generate meshes by shifting points along flux surfaces. To use it first an orthogonal mesh is generated:

from hypnotoad.cases import tokamak
from hypnotoad.core.mesh import BoutMesh

with open("geqdsk", "r") as fh:
    eq = tokamak.read_geqdsk(fh, {})

mesh = BoutMesh(eq, {})  # Default settings

Then we define a measure to optimise. In this case we combine distance to the boundary with orthogonality:

from hypnotoad.core.mesh import BoundaryDistance, Orthogonality
measure = BoundaryDistance(mesh) + Orthogonality()

These are classes that inherit from MeshMeasure, that can be added together and multipled by constant weighting factors. The argument to BoundaryDistance ensures that the boundary intersections with the underlying FineContours are found. We then optimise the mesh using this measure:

opt_mesh = measure.optimise(mesh)

The original mesh isn't modified; this returns a new BoutMesh.

This is implemented in the hypnotoad-geqdsk script: Setting optimise: true in the input YAML file will run the optimiser on the initial grid. Other options control the weights applied to the mesh metrics.

  • Closes #xxxx
  • Tests added
  • Udated manual
  • Updated doc/whats-new.md with a summary of the changes

If both upper_wall and lower_wall are True, `len(contour) // 2` rather
than `len(contour // 2)` should be used.
If a contour starts outside the wall then it can be that no
intersection is found. Handle that case, leaving original contour.
Method to plot single points, for interactive debugging
Attempting to handle cases where no intersection is found
Plots cell corners joined together, and cell centers as points.

Perhaps could use xlow, ylow points to provide a quadratic cell shape?
The idea is to first extend FineContour to the wall, then distort
PsiContour's points along the FineContour curve.

A divide-and-conquer algorithm is used to make finding intersections
with a large number of points efficient.
Move plotting to MeshRegion so individual regions can be plotted.
Mesh plotting methods iterate over and call MeshRegions.
Broke test case TestContour.test_append
FineContour.getPoint is the inverse of getDistance: It returns a
Point2D if given a distance along the FineContour

PsiContour.map takes a function that returns a distance shift, and
returns a new PsiContour that shares the FineContour with the
original. This will be used to perform mesh deformations.
If given, MeshRegion doesn't need to follow radial coordinate lines
and create PsiContours.
Enables mapping of the mesh points using shift functions.
Plots straight-sided cells connecting cell corners.

Added script plotting options to possible options list, so that
an exception isn't raised when they're used.
- Ensure that psi is passed to get_fine_contour
- Handle rounding errors near FineContour edges
Mesh.map() now creates an instance of self.__class__, so subclasses
including BoutMesh can be mapped.
Ensure that final index has ypos=1, to be consistent with upper_shift.
Prevent crossing lines from going off end of FineContour
MeshRegion.setWallIntersections(Equilibrium) calls
FineContour.setWallIntersections to calculate where contours
intsersect walls.

MeshRegion.wallAlignShiftFunction() creates a lambda function that
shifts a MeshRegion to align to the wall. That can map cells to have
zero size, but PsiContour.map prevents cells from crossing.
Change `axis` keyword to `ax` for consistency, return axis.
Use a polynomial basis to represent mesh point shifts within each
MeshRegion.

MeshRegionMapper generates new MeshRegion objects given a list of
polynomial coefficients. The order of the polynomials in X and Y
is set in the constructor.

MeshMapper uses MeshRegionMapper to generate new Mesh objects, using
a combined list of polynomial coefficients.
PsiContours that are shared between MeshRegions will in general
not be mapped in the same way. These PsiContours are averaged
in MeshMapper.generate to produce a consistent boundary between
regions.
Optimises meshes by varying the distortion parameters to minimise a
MeshMeasure. For now only one MeshMeasure: BoundaryDistance combines
distances between the mesh and the wall.
Enables the optimiser to take into account the orthogonality of the
mesh, by minimising tan(Beta) over the mesh, where Beta is the angle
between coordinate lines.
Can be used to disable some parts of Mesh construction in optimiser
loop.
Repeatedly creating regions and meshes, so reduce the amount of text
printed each iteration
- PoloidalSpacing measures the ratio of the poloidal size of
  neighbouring cells, penalising variations
- When PsiContours are merged on region boundaries, re-use the
  FineContour and distances that have already been calculated.
- Add __str__ methods to the MeshMeasure subclasses
- Add automatic optimisation to the `hypnotoad-geqdsk` script
- In optimisation loop only print every 20th iteration
- In hypnotoad-geqdsk script save the plotted cells to file
@bendudson bendudson changed the title WIP: non-orthogonal mesh improvements Non-orthogonal mesh improvements Feb 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant