How to create a GridFunction-based CoefficientFunction that does not follow mesh deformation?

## Problem Description

I am working on a coupled simulation where:

  1. A rotating object (workpiece) is heated by a stationary heat source

  2. The heat source distribution Q is computed from a previous FEM analysis and stored as a GridFunction

  3. The mesh rotates using mesh.SetDeformation() to simulate the rotating workpiece

  4. I want the heat source Q to remain fixed in space (not rotate with the mesh)

## Current Issue

When I use a GridFunction-based CoefficientFunction for the heat source, it rotates with the mesh deformation, which is not the desired behavior.

Expression-based CF (works correctly - does NOT rotate):

theta = atan2(y, x)
Q = mesh.MaterialCF({“work”: 1e8*IfPos(theta, 1, 0) * IfPos(pi/8 - theta, 1, 0)}, default=0)

GridFunction-based CF (problem - DOES rotate):

gfQ = GridFunction(fes)
gfQ.Set(Q_expression)
Q = 1.0 * gfQ  # Convert to CoefficientFunction

## Minimal Example

from ngsolve import *
from netgen.occ import *

# Simple 2D rotating disk geometry
circle = Circle((0,0), 0.1).Face()
geo = OCCGeometry(circle, dim=2)
mesh = Mesh(geo.GenerateMesh(maxh=0.02))

# Define heat source: fixed sector (0 < theta < pi/4)
theta = atan2(y, x)
Q_expr = IfPos(theta, 1, 0) * IfPos(pi/4 - theta, 1, 0)

# Convert to GridFunction
fes_Q = H1(mesh, order=2)
gfQ_fixed = GridFunction(fes_Q)
gfQ_fixed.Set(Q_expr)

# Temperature field on rotating mesh
fes_T = H1(mesh, order=2)
gfT = GridFunction(fes_T)

# Setup deformation
fesdef = VectorH1(mesh, order=3)
deformation = GridFunction(fesdef)
center = CF((0, 0))
pos = CF((x, y))

# Rotate mesh by 45 degrees

angle = pi/4
rotmat = CF((cos(angle), -sin(angle), sin(angle), cos(angle))).Reshape((2,2))
deformation.Set((rotmat - Id(2))*(pos-center))
mesh.SetDeformation(deformation)

# Problem: How to use gfQ_fixed in a way that it does NOT rotate?
# When using gfQ_fixed directly, it rotates with the mesh

# Example: weak form for heat equation

u, v = fes_T.TnT()
a = BilinearForm(fes_T)
a += grad(u) \* grad(v) \* dx
a.Assemble()
f = LinearForm(fes_T)
f += gfQ_fixed * v * dx  # ← This rotates with mesh (NOT desired)
f.Assemble()

## What I Need

I need a way to create a GridFunction-based CoefficientFunction that:

  • Is evaluated in the global (fixed) coordinate system

  • Does NOT follow the mesh deformation

  • Can be used in weak forms like f += Q_fixed * v * dx

In the future, gfQ_fixed will come from a separate FEM analysis, so I cannot use the analytical expression Q_expr directly.

## Attempted Solutions

  1. Copy GridFunction vector before deformation:
mesh.UnsetDeformation()
gfQ_current.vec.data = gfQ_fixed.vec
mesh.SetDeformation(deformation)

This doesn’t work because GridFunction DOFs are defined in reference coordinates.

  1. Apply inverse transformation:

I want to evaluate gfQ_fixed at the inverse-transformed coordinates, but I cannot use:

rotmat_inv = CF((cos(-angle), -sin(-angle), sin(-angle), cos(-angle))).Reshape((2,2))
pos_original = rotmat_inv * pos
Q_at_original = gfQ_fixed(mesh(pos_original\[0\], pos_original\[1\]))  # ← pos_original is CF, not numbers

because gfQ(mesh(x,y,z)) requires real numbers, not CoefficientFunction.

  1. Using Set() or Interpolate():

I need a way to use Set() or .Interpolate() with coordinate transformation, but I’m not sure how.

## Question

What is the correct way to implement a fixed-space heat source using a GridFunction on a deforming mesh in NGSolve?

Any suggestions or examples would be greatly appreciated!

## System Information

- NGSolve version: [6.2.2506]
- Operating System: Windows Python 3.12.10

Overview

I have solved the issue myself. I prepared two meshes, mesh0 and mesh1, and defined GridFunctions on each. mesh1 rotates while mesh0 remains in a stationary coordinate system. This was achieved using the CoefficientFunction associated with the GridFunction on mesh0.

Solution

Basic Approach

  1. Prepare Two Meshes

    • mesh0: Mesh in the stationary (non-rotating) coordinate system
    • mesh1: Mesh in the rotating coordinate system
  2. Define GridFunctions

    • gfQ defined on mesh0: Holds the source data
    • gfT, gfA defined on mesh1: Hold data in the rotating coordinate system
  3. Data Transfer

    • Use the CoefficientFunction associated with gfQ on mesh0
    • After rotating mesh1, transfer values using gfA.Set(gfQ)

Implementation Example

from numpy import *
from ngsolve import *
from ngsolve.webgui import Draw
from netgen.occ import *

# Create geometry and meshes
cyl = Cylinder(Pnt(0, 0, 0), Z, r=2, h=1)
geo = OCCGeometry(cyl)

mesh0 = Mesh(geo.GenerateMesh(maxh=0.3))  # Stationary coordinate system
mesh1 = Mesh(geo.GenerateMesh(maxh=0.3))  # Rotating coordinate system

# GridFunction on mesh0 (source data)
fes0 = H1(mesh0, order=2)
gfQ = GridFunction(fes0)
theta = atan2(y, x)
Q = IfPos(theta, 1, 0) * IfPos(pi/8 - theta, 1, 0)
gfQ.Set(Q)

# GridFunctions on mesh1
fes1 = H1(mesh1, order=2)
gfT = GridFunction(fes1)
gfA = GridFunction(fes1)

# GridFunction for deformation
fesdef = VectorH1(mesh1, order=3)
deformation = GridFunction(fesdef)
center = CF((0.0, 0.0, 0.0))
pos = CF((x, y, z))

# Rotation and value transfer
for n in range(17):
    mesh1.UnsetDeformation()
    gfT.vec.data += gfA.vec.data

    # Define rotation matrix
    angle = pi/8 * n
    rotmat = CF((cos(angle), -sin(angle), 0,
                 sin(angle), cos(angle), 0,
                 0, 0, 1)).Reshape((3, 3))

    # Deform mesh (rotation)
    deformation.Set((rotmat - Id(3)) * (pos - center))
    mesh1.SetDeformation(deformation)

    # Get values from gfQ on mesh0 and set to gfA on mesh1
    gfA.Set(gfQ)

Key Points

  • The CoefficientFunction associated with the GridFunction on mesh0 can reference values in the original coordinate system even when mesh1 is rotated
  • With gfA.Set(gfQ), the value of gfQ in the original coordinate system is evaluated at each point of the rotated mesh1
  • This enables data transfer between rotating and stationary coordinate systems

Applications

This technique can be applied to problems where rotating and stationary parts interact, such as electromagnetic field analysis of rotating machinery.

You can also unset the meshdeformation before assemble f and set it again afterwards