Computes the differential advection term using the differentiation Scheme indicated by `order`, ´implicit´ and `upwind`. For a velocity field u, the advection term as it appears on the right-hand-side of a PDE is -u·∇u, including the negative sign. For unstructured meshes, computes -1
(u: Field,
velocity: Field,
density: float = 1.,
order=2,
implicit: Solve = None,
upwind=True)
| 76 | |
| 77 | |
| 78 | def differential(u: Field, |
| 79 | velocity: Field, |
| 80 | density: float = 1., |
| 81 | order=2, |
| 82 | implicit: Solve = None, |
| 83 | upwind=True) -> Field: |
| 84 | """ |
| 85 | Computes the differential advection term using the differentiation Scheme indicated by `order`, ´implicit´ and `upwind`. |
| 86 | |
| 87 | For a velocity field u, the advection term as it appears on the right-hand-side of a PDE is -u·∇u, including the negative sign. |
| 88 | |
| 89 | For unstructured meshes, computes -1/V ∑_f (n·u_prev) u ρ A |
| 90 | |
| 91 | Args: |
| 92 | u: Scalar or vector-valued `Field` sampled on a `CenteredGrid`, `StaggeredGrid` or `Mesh`. |
| 93 | velocity: `Field` that can be sampled at the elements of `u`. |
| 94 | For FVM, the advection term is typically linearized by setting `velocity = previous_velocity`. |
| 95 | Passing `velocity=u` yields non-linear terms which cannot be traced inside linear functions. |
| 96 | order: Spatial order of accuracy. |
| 97 | Higher orders entail larger stencils and more computation time but result in more accurate results assuming a large enough resolution. |
| 98 | Supported for grids: 2 explicit, 4 explicit, 6 implicit (inherited from `phi.field.spatial_gradient()` and resampling). |
| 99 | Passing order=4 currently uses 2nd-order resampling. This is work-in-progress. |
| 100 | For FVM, the order is used when interpolating centroid values to faces if needed. |
| 101 | implicit: When a `Solve` object is passed, performs an implicit operation with the specified solver and tolerances. |
| 102 | Otherwise, an explicit stencil is used. |
| 103 | upwind: Whether to use upwind interpolation. Only supported for FVM at the moment. |
| 104 | |
| 105 | Returns: |
| 106 | Differential convection term as `Field` on the same geometry. |
| 107 | """ |
| 108 | if u.is_grid and u.is_staggered: |
| 109 | grad_list = [spatial_gradient(field_component, stack_dim=channel('grad_dim'), order=order, implicit=implicit) for field_component in u.vector] |
| 110 | grad_grid = u.with_values(math.stack([component.values for component in grad_list], channel(velocity).as_dual())) |
| 111 | if order == 4: |
| 112 | amounts = [grad * vel.at(grad, order=2) for grad, vel in zip(grad_grid.grad_dim, velocity.vector)] # ToDo resampling does not yet support order=4 |
| 113 | else: |
| 114 | amounts = [grad * vel.at(grad, order=order, implicit=implicit) for grad, vel in zip(grad_grid.grad_dim, velocity.vector)] |
| 115 | amount = sum(amounts) |
| 116 | return u.with_values(- amount) |
| 117 | elif u.is_grid and u.is_centered: |
| 118 | grad_tensor = math.stack( |
| 119 | [spatial_gradient(component, stack_dim=channel('gradient'), order=order, implicit=implicit).values for |
| 120 | component in u.vector], dim=channel('vector')) |
| 121 | velocity_tensor = math.stack(math.unstack(velocity.values, dim='vector'), dim=channel('gradient')) |
| 122 | amounts = velocity_tensor * grad_tensor |
| 123 | amount = sum(amounts.gradient) |
| 124 | return velocity.with_values(- amount) |
| 125 | elif u.is_mesh: |
| 126 | u = u.at_faces(boundary=NONE, order=order, upwind=velocity if upwind is True else upwind) |
| 127 | velocity = velocity.at_faces(boundary=NONE, order=order, upwind=velocity if upwind is True else upwind) |
| 128 | conv = density * u.mesh.integrate_surface(u.values * (velocity.values.vector @ velocity.face_normals.vector)) / u.mesh.volume |
| 129 | return Field(u.geometry, -conv, 0) |
| 130 | raise NotImplementedError(u) |
| 131 | |
| 132 | |
| 133 | finite_difference = differential |
nothing calls this directly
no test coverage detected