|
| 1 | +""" |
| 2 | + get_element_vertices(space::SpectralElementSpace2D) |
| 3 | +
|
| 4 | +Returns a vector of vectors, each containing the coordinates of the vertices |
| 5 | +of an element. The vertices are in clockwise order for each element, and the |
| 6 | +first coordinate pair is repeated at the end. |
| 7 | +
|
| 8 | +Also performs a check for zero area polygons, and throws an error if any are found. |
| 9 | +
|
| 10 | +This is the format expected by ConservativeRegridding.jl to construct a |
| 11 | +Regridder object. |
| 12 | +""" |
| 13 | +function get_element_vertices(space) |
| 14 | + # Get the indices of the vertices of the elements, in clockwise order for each element |
| 15 | + Nh = Meshes.nelements(space.grid.topology.mesh) |
| 16 | + Nq = Quadratures.degrees_of_freedom(Spaces.quadrature_style(space)) |
| 17 | + vertex_inds = [ |
| 18 | + CartesianIndex(i, j, 1, 1, e) # f and v are 1 for SpectralElementSpace2D |
| 19 | + for e in 1:Nh |
| 20 | + for (i, j) in [(1, 1), (1, Nq), (Nq, Nq), (Nq, 1), (1, 1)] |
| 21 | + ] # repeat the first coordinate pair at the end |
| 22 | + |
| 23 | + # Get the lat and lon at each vertex index |
| 24 | + coords = Fields.coordinate_field(space) |
| 25 | + vertex_coords = [ |
| 26 | + (Fields.field_values(coords.lat)[ind], Fields.field_values(coords.long)[ind]) |
| 27 | + for ind in vertex_inds |
| 28 | + ] |
| 29 | + |
| 30 | + # Put each polygon into a vector, with the first coordinate pair repeated at the end |
| 31 | + vertices = collect(Iterators.partition(vertex_coords, 5)) |
| 32 | + |
| 33 | + # Check for zero area polygons |
| 34 | + for polygon in vertices |
| 35 | + if allequal(first.(polygon)) || allequal(last.(polygon)) |
| 36 | + @error "Zero area polygon found in vertices" polygon |
| 37 | + end |
| 38 | + end |
| 39 | + return vertices |
| 40 | +end |
| 41 | + |
| 42 | +### These functions are used to facilitate storing a single value per element on a field |
| 43 | +### rather than one value per node. |
| 44 | +""" |
| 45 | + integrate_each_element(field) |
| 46 | +
|
| 47 | +Integrate the field over each element of the space. |
| 48 | +Returns a vector with length equal to the number of elements in the space, |
| 49 | +containing the integrated value over the nodes of each element. |
| 50 | +""" |
| 51 | +function integrate_each_element(field) |
| 52 | + space = axes(field) |
| 53 | + weighted_values = |
| 54 | + RecursiveApply.rmul.( |
| 55 | + Spaces.weighted_jacobian(space), |
| 56 | + Fields.todata(field), |
| 57 | + ) |
| 58 | + |
| 59 | + Nh = Meshes.nelements(space.grid.topology.mesh) |
| 60 | + integral_each_element = zeros(Float64, Nh) |
| 61 | + Nq = Quadratures.degrees_of_freedom(Spaces.quadrature_style(space)) |
| 62 | + for e in 1:Nh # loop over each element |
| 63 | + for i in 1:Nq |
| 64 | + for j in 1:Nq |
| 65 | + integral_each_element[e] += weighted_values[CartesianIndex(i, j, 1, 1, e)] |
| 66 | + end |
| 67 | + end |
| 68 | + end |
| 69 | + return integral_each_element |
| 70 | +end |
| 71 | + |
| 72 | +""" |
| 73 | + get_value_per_element(field, ones_field) |
| 74 | +
|
| 75 | +Get one value per element of a field by integrating over the nodes of |
| 76 | +each element and dividing by the area of the element. |
| 77 | +
|
| 78 | +Here `ones_field` is a field on the same space as `field` with all |
| 79 | +values set to 1. |
| 80 | +""" |
| 81 | +function get_value_per_element(field, ones_field) |
| 82 | + integral_each_element = integrate_each_element(field) |
| 83 | + area_each_element = integrate_each_element(ones_field) |
| 84 | + return integral_each_element ./ area_each_element |
| 85 | +end |
| 86 | + |
| 87 | +""" |
| 88 | + set_value_per_element!(field, value_per_element) |
| 89 | +
|
| 90 | +Set the values of a field with the provided values in each element. |
| 91 | +Each node within an element will have the same value. |
| 92 | +
|
| 93 | +The input vector is expected to be of length equal to the number of elements in |
| 94 | +the space. |
| 95 | +""" |
| 96 | +function set_value_per_element!(field, value_per_element) |
| 97 | + space = axes(field) |
| 98 | + Nh = Meshes.nelements(space.grid.topology.mesh) |
| 99 | + Nq = Quadratures.degrees_of_freedom(Spaces.quadrature_style(space)) |
| 100 | + |
| 101 | + @assert length(value_per_element) == Nh "Length of value_per_element must be equal to the number of elements in the space" |
| 102 | + |
| 103 | + # Set the value in each node of each element to the value per element |
| 104 | + for e in 1:Nh |
| 105 | + for i in 1:Nq |
| 106 | + for j in 1:Nq |
| 107 | + Fields.field_values(field)[CartesianIndex(i, j, 1, 1, e)] = |
| 108 | + value_per_element[e] |
| 109 | + end |
| 110 | + end |
| 111 | + end |
| 112 | + return field |
| 113 | +end |
0 commit comments