FieldGridCell.java

  1. /* Copyright 2022-2025 Thales Alenia Space
  2.  * Licensed to CS Communication & Systèmes (CS) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * CS licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *   http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.orekit.models.earth.troposphere.iturp834;

  18. import org.hipparchus.CalculusFieldElement;

  19. /** Holder for one cell of grid data surrounding one point.
  20.  * @param <T> type of the field elements
  21.  * @author Luc Maisonobe
  22.  * @since 13.0
  23.  */
  24. class FieldGridCell<T extends CalculusFieldElement<T>> {

  25.     /** Latitude difference with respect to South cell edge. */
  26.     private final T deltaSouth;

  27.     /** Longitude difference with respect to West cell edge. */
  28.     private final T deltaWest;

  29.     /** Cell size in latitude. */
  30.     private final double sizeLat;

  31.     /** Cell size in longitude. */
  32.     private final double sizeLon;

  33.     /** North-West value. */
  34.     private final T nw;

  35.     /** South-West value. */
  36.     private final T sw;

  37.     /** South-East value. */
  38.     private final T se;

  39.     /** North-East value. */
  40.     private final T ne;

  41.     /**
  42.      * Build a grid cell from corner data.
  43.      *
  44.      * @param deltaSouth point latitude minus South cell edge latitude
  45.      * @param deltaWest  point longitude minus West cell edge longitude
  46.      * @param sizeLat    cell size in latitude
  47.      * @param sizeLon    cell size in longitude
  48.      * @param nw         North-West value
  49.      * @param sw         South-West value
  50.      * @param se         South-East value
  51.      * @param ne         North-East value
  52.      */
  53.     FieldGridCell(final T deltaSouth, final T deltaWest, final double sizeLat, final double sizeLon,
  54.                   final T nw, final T sw, final T se, final T ne) {
  55.         this.deltaSouth = deltaSouth;
  56.         this.deltaWest  = deltaWest;
  57.         this.sizeLat    = sizeLat;
  58.         this.sizeLon    = sizeLon;
  59.         this.nw         = nw;
  60.         this.sw         = sw;
  61.         this.se         = se;
  62.         this.ne         = ne;
  63.     }

  64.     /** Build a grid cell by applying a function to two existing cells.
  65.      * <p>
  66.      * The cells are expected to be consistent (i.e. same locations,
  67.      * same sizes), but no verification is done here. It works in
  68.      * the context of ITR-R P.834 because the grids have similar
  69.      * samplings, it would not work fro general and inconsistent grids.
  70.      * </p>
  71.      * @param function function to apply to all cells corners
  72.      * @param cell1 first cell
  73.      * @param cell2 second cell
  74.      */
  75.     FieldGridCell(final BiFunction<T> function,
  76.                   final FieldGridCell<T> cell1, final FieldGridCell<T> cell2) {
  77.         this.deltaSouth = cell1.deltaSouth;
  78.         this.deltaWest  = cell1.deltaWest;
  79.         this.sizeLat    = cell1.sizeLat;
  80.         this.sizeLon    = cell1.sizeLon;
  81.         this.nw         = function.apply(cell1.nw, cell2.nw);
  82.         this.sw         = function.apply(cell1.sw, cell2.sw);
  83.         this.se         = function.apply(cell1.se, cell2.se);
  84.         this.ne         = function.apply(cell1.ne, cell2.ne);
  85.     }

  86.     /** Build a grid cell by applying a function to three existing cells.
  87.      * <p>
  88.      * The cells are expected to be consistent (i.e. same locations,
  89.      * same sizes), but no verification is done here. It works in
  90.      * the context of ITR-R P.834 because the grids have similar
  91.      * samplings, it would not work fro general and inconsistent grids.
  92.      * </p>
  93.      * @param function function to apply to all cells corners
  94.      * @param cell1 first cell
  95.      * @param cell2 second cell
  96.      * @param cell3 third cell
  97.      */
  98.     FieldGridCell(final TriFunction<T> function,
  99.                   final FieldGridCell<T> cell1, final FieldGridCell<T> cell2, final FieldGridCell<T> cell3) {
  100.         this.deltaSouth = cell1.deltaSouth;
  101.         this.deltaWest  = cell1.deltaWest;
  102.         this.sizeLat    = cell1.sizeLat;
  103.         this.sizeLon    = cell1.sizeLon;
  104.         this.nw         = function.apply(cell1.nw, cell2.nw, cell3.nw);
  105.         this.sw         = function.apply(cell1.sw, cell2.sw, cell3.sw);
  106.         this.se         = function.apply(cell1.se, cell2.se, cell3.se);
  107.         this.ne         = function.apply(cell1.ne, cell2.ne, cell3.ne);
  108.     }

  109.     /** Build a grid cell by applying a function to four existing cells.
  110.      * <p>
  111.      * The cells are expected to be consistent (i.e. same locations,
  112.      * same sizes), but no verification is done here. It works in
  113.      * the context of ITR-R P.834 because the grids have similar
  114.      * samplings, it would not work fro general and inconsistent grids.
  115.      * </p>
  116.      * @param function function to apply to all cells corners
  117.      * @param cell1 first cell
  118.      * @param cell2 second cell
  119.      * @param cell3 third cell
  120.      * @param cell4 fourth cell
  121.      */
  122.     FieldGridCell(final QuarticFunction<T> function,
  123.                   final FieldGridCell<T> cell1, final FieldGridCell<T> cell2,
  124.                   final FieldGridCell<T> cell3, final FieldGridCell<T> cell4) {
  125.         this.deltaSouth = cell1.deltaSouth;
  126.         this.deltaWest  = cell1.deltaWest;
  127.         this.sizeLat    = cell1.sizeLat;
  128.         this.sizeLon    = cell1.sizeLon;
  129.         this.nw         = function.apply(cell1.nw, cell2.nw, cell3.nw, cell4.nw);
  130.         this.sw         = function.apply(cell1.sw, cell2.sw, cell3.sw, cell4.sw);
  131.         this.se         = function.apply(cell1.se, cell2.se, cell3.se, cell4.se);
  132.         this.ne         = function.apply(cell1.ne, cell2.ne, cell3.ne, cell4.ne);
  133.     }

  134.     /** Build a grid cell by applying a function to five existing cells.
  135.      * <p>
  136.      * The cells are expected to be consistent (i.e. same locations,
  137.      * same sizes), but no verification is done here. It works in
  138.      * the context of ITR-R P.834 because the grids have similar
  139.      * samplings, it would not work fro general and inconsistent grids.
  140.      * </p>
  141.      * @param function function to apply to all cells corners
  142.      * @param cell1 first cell
  143.      * @param cell2 second cell
  144.      * @param cell3 third cell
  145.      * @param cell4 fourth cell
  146.      * @param cell5 fifth cell
  147.      */
  148.     FieldGridCell(final QuinticFunction<T> function,
  149.                   final FieldGridCell<T> cell1, final FieldGridCell<T> cell2, final FieldGridCell<T> cell3,
  150.                   final FieldGridCell<T> cell4, final FieldGridCell<T> cell5) {
  151.         this.deltaSouth = cell1.deltaSouth;
  152.         this.deltaWest  = cell1.deltaWest;
  153.         this.sizeLat    = cell1.sizeLat;
  154.         this.sizeLon    = cell1.sizeLon;
  155.         this.nw         = function.apply(cell1.nw, cell2.nw, cell3.nw, cell4.nw, cell5.nw);
  156.         this.sw         = function.apply(cell1.sw, cell2.sw, cell3.sw, cell4.sw, cell5.sw);
  157.         this.se         = function.apply(cell1.se, cell2.se, cell3.se, cell4.se, cell5.se);
  158.         this.ne         = function.apply(cell1.ne, cell2.ne, cell3.ne, cell4.ne, cell5.ne);
  159.     }

  160.     /** Evaluate cell value at point location using bi-linear interpolation.
  161.      * @return cell value at point location
  162.      */
  163.     public T evaluate() {
  164.         final T deltaNorth = deltaSouth.negate().add(sizeLat);
  165.         final T deltaEast  = deltaWest.negate().add(sizeLon);
  166.         return     deltaSouth.multiply(deltaWest.multiply(ne).add(deltaEast.multiply(nw))).
  167.                add(deltaNorth.multiply(deltaWest.multiply(se).add(deltaEast.multiply(sw)))).
  168.                divide(sizeLat * sizeLon);
  169.     }

  170.     /** Interface for function that can be applied to the corners of two cells. */
  171.     @FunctionalInterface
  172.     public interface BiFunction<T extends CalculusFieldElement<T>> {
  173.         /** Apply function to similar corners coming from two cells.
  174.          * @param corner1 value at corner of first cell
  175.          * @param corner2 value at corner of second cell
  176.          * @return function evaluated at similar corners of two cells
  177.          */
  178.         T apply(T corner1, T corner2);
  179.     }

  180.     /** Interface for function that can be applied to the corners of three cells.
  181.      * @param <T> type of the field elements
  182.      */
  183.     @FunctionalInterface
  184.     public interface TriFunction<T extends CalculusFieldElement<T>> {
  185.         /** Apply function to similar corners coming from three cells.
  186.          * @param corner1 value at corner of first cell
  187.          * @param corner2 value at corner of second cell
  188.          * @param corner3 value at corner of third cell
  189.          * @return function evaluated at similar corners of three cells
  190.          */
  191.         T apply(T corner1, T corner2, T corner3);
  192.     }

  193.     /** Interface for function that can be applied to the corners of four cells.
  194.      * @param <T> type of the field elements
  195.      */
  196.     @FunctionalInterface
  197.     public interface QuarticFunction<T extends CalculusFieldElement<T>> {
  198.         /** Apply function to similar corners coming from four cells.
  199.          * @param corner1 value at corner of first cell
  200.          * @param corner2 value at corner of second cell
  201.          * @param corner3 value at corner of third cell
  202.          * @param corner4 value at corner of fourth cell
  203.          * @return function evaluated at similar corners of four cells
  204.          */
  205.         T apply(T corner1, T corner2, T corner3, T corner4);
  206.     }

  207.     /** Interface for function that can be applied to the corners of five cells.
  208.      * @param <T> type of the field elements
  209.      */
  210.     @FunctionalInterface
  211.     public interface QuinticFunction<T extends CalculusFieldElement<T>> {
  212.         /** Apply function to similar corners coming from five cells.
  213.          * @param corner1 value at corner of first cell
  214.          * @param corner2 value at corner of second cell
  215.          * @param corner3 value at corner of third cell
  216.          * @param corner4 value at corner of fourth cell
  217.          * @param corner5 value at corner of fifth cell
  218.          * @return function evaluated at similar corners of five cells
  219.          */
  220.         T apply(T corner1, T corner2, T corner3, T corner4, T corner5);
  221.     }

  222. }