/// <summary> /// Construct a field updated for the given surface. /// </summary> /// <param name="surface"></param> /// <param name="options"></param> public PrognosticFieldsUpdater(IPolyhedron surface, IModelParameters options) { _options = options; _coriolisField = SimulationUtilities.CoriolisField(surface, _options.RotationFrequency); _faceNormalsField = SimulationUtilities.FaceNormalsField(surface); _vertexNormalsField = SimulationUtilities.VertexNormalsField(surface); _operators = new VectorFieldOperators(surface); _gravity = options.Gravity; }
/// <summary> /// The discrete gradient, as described in Randall & Ringler 2001. /// </summary> public VectorField <Vertex> Gradient(ScalarField <Face> A) { var numberOfVertices = _polyhedron.Vertices.Count; var results = new Vector[numberOfVertices]; foreach (var vertex in Enumerable.Range(0, numberOfVertices)) { results[vertex] = GradientAtVertex(vertex, A); } return(new VectorField <Vertex>(_polyhedron.IndexOf, results)); }
/// <summary> /// The vertex averaging operator, as described in Randall & Ringler 2001 (p16) /// </summary> public ScalarField <Vertex> VertexAverages(ScalarField <Face> F) { var numberOfVertices = _polyhedron.Vertices.Count; var averages = new double[numberOfVertices]; for (int vertex = 0; vertex < numberOfVertices; vertex++) { averages[vertex] = VertexAverage(vertex, F); } return(new ScalarField <Vertex>(_polyhedron.IndexOf, averages)); }
private Vector GradientAtVertex(int vertex, ScalarField <Face> A) { var faces = _faces[vertex]; var coefficients = _gradientCoefficients[vertex]; var result = Vector.Zeros(3); for (int j = 0; j < faces.Length; j++) { result += A[faces[j]] * coefficients[j]; } return(result / _vertexAreas[vertex]); }
/// <summary> /// The discrete divergence, as described in Randall & Ringler 2001 (p7) /// </summary> public ScalarField <Face> FluxDivergence(VectorField <Vertex> V, ScalarField <Face> F) { var numberOfFaces = _polyhedron.Faces.Count; var fluxes = FluxesAcrossHalfEdges(V); var results = new double[numberOfFaces]; for (int face = 0; face < numberOfFaces; face++) { results[face] = DivergenceAtFace(face, fluxes, F); } return(new ScalarField <Face>(_polyhedron.IndexOf, results)); }
private double VertexAverage(int vertex, ScalarField <Face> F) { var faces = _faces[vertex]; var areaPerFace = _areaInEachFace[vertex]; var weightedSum = 0.0; var totalArea = 0.0; for (int index = 0; index < faces.Length; index++) { weightedSum += F[faces[index]] * areaPerFace[index]; totalArea += areaPerFace[index]; } return(weightedSum / totalArea); }
private double DivergenceAtFace(int face, double[][] fluxes, ScalarField <Face> F) { var vertices = _vertices[face]; var faceInFacesOfVertices = _faceInFacesOfVertices[face]; var result = 0.0; for (int j = 0; j < faceInFacesOfVertices.Length; j++) { var vertex = vertices[j]; var faceInFacesOfVertex = faceInFacesOfVertices[j]; result += ContributionOfVertexToFluxAtFace(vertex, faceInFacesOfVertex, fluxes, F); } return(result / _faceAreas[face]); }
private ScalarField <Face> DerivativeOfHeight(VectorField <Vertex> velocity, ScalarField <Face> height) { return(-_operators.FluxDivergence(velocity, height)); }
private VectorField <Vertex> DerivativeOfVelocity(VectorField <Vertex> velocity, ScalarField <Face> height) { var absoluteVorticity = _operators.VertexAverages(AbsoluteVorticity(velocity)); var curlOfVelocity = VectorField <Vertex> .CrossProduct(_vertexNormalsField, velocity); var kineticEnergyGradient = _operators.Gradient(_operators.KineticEnergy(velocity)); var potentialEnergyGradient = _operators.Gradient(_gravity * height); return((-absoluteVorticity) * curlOfVelocity - kineticEnergyGradient - potentialEnergyGradient); }
private double ContributionOfVertexToFluxAtFace(int vertex, int faceInFacesOfVertex, double[][] fluxes, ScalarField <Face> F) { var facesOfVertex = _faces[vertex]; var indexOfThisFace = facesOfVertex.AtCyclicIndex(faceInFacesOfVertex); var valueAtThisFace = F[indexOfThisFace]; var indexOfNextFace = facesOfVertex.AtCyclicIndex(faceInFacesOfVertex + 1); var valueAtNextFace = F[indexOfNextFace]; var valueAtNextHalfEdge = (valueAtNextFace + valueAtThisFace) / 2; var fluxAtNextHalfEdge = fluxes[vertex][faceInFacesOfVertex]; var fieldFluxAtNextHalfEdge = valueAtNextHalfEdge * fluxAtNextHalfEdge; var indexOfPreviousFace = facesOfVertex.AtCyclicIndex(faceInFacesOfVertex - 1); var valueAtPreviousFace = F[indexOfPreviousFace]; var valueAtPreviousHalfEdge = (valueAtThisFace + valueAtPreviousFace) / 2; var fluxAtPreviousHalfEdge = -fluxes[vertex].AtCyclicIndex(faceInFacesOfVertex - 1); var fieldFluxAtPreviousHalfEdge = valueAtPreviousHalfEdge * fluxAtPreviousHalfEdge; return(fieldFluxAtNextHalfEdge + fieldFluxAtPreviousHalfEdge); }