org.jgrasstools.hortonmachine.modules.hydrogeomorphology.insolation.OmsInsolation.java Source code

Java tutorial

Introduction

Here is the source code for org.jgrasstools.hortonmachine.modules.hydrogeomorphology.insolation.OmsInsolation.java

Source

/*
 * This file is part of JGrasstools (http://www.jgrasstools.org)
 * (C) HydroloGIS - www.hydrologis.com 
 * 
 * JGrasstools is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.jgrasstools.hortonmachine.modules.hydrogeomorphology.insolation;

import static org.jgrasstools.gears.libs.modules.ModelsEngine.calcInverseSunVector;
import static org.jgrasstools.gears.libs.modules.ModelsEngine.calcNormalSunVector;
import static org.jgrasstools.gears.libs.modules.ModelsEngine.calculateFactor;
import static org.jgrasstools.gears.libs.modules.ModelsEngine.scalarProduct;
import static org.jgrasstools.hortonmachine.i18n.HortonMessages.OMSINSOLATION_AUTHORCONTACTS;
import static org.jgrasstools.hortonmachine.i18n.HortonMessages.OMSINSOLATION_AUTHORNAMES;
import static org.jgrasstools.hortonmachine.i18n.HortonMessages.OMSINSOLATION_DESCRIPTION;
import static org.jgrasstools.hortonmachine.i18n.HortonMessages.OMSINSOLATION_KEYWORDS;
import static org.jgrasstools.hortonmachine.i18n.HortonMessages.OMSINSOLATION_LABEL;
import static org.jgrasstools.hortonmachine.i18n.HortonMessages.OMSINSOLATION_LICENSE;
import static org.jgrasstools.hortonmachine.i18n.HortonMessages.OMSINSOLATION_NAME;
import static org.jgrasstools.hortonmachine.i18n.HortonMessages.OMSINSOLATION_STATUS;
import static org.jgrasstools.hortonmachine.i18n.HortonMessages.OMSINSOLATION_inElev_DESCRIPTION;
import static org.jgrasstools.hortonmachine.i18n.HortonMessages.OMSINSOLATION_outIns_DESCRIPTION;
import static org.jgrasstools.hortonmachine.i18n.HortonMessages.OMSINSOLATION_tEndDate_DESCRIPTION;
import static org.jgrasstools.hortonmachine.i18n.HortonMessages.OMSINSOLATION_tStartDate_DESCRIPTION;

import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import java.util.HashMap;

import javax.media.jai.RasterFactory;
import javax.media.jai.iterator.RandomIter;
import javax.media.jai.iterator.RandomIterFactory;
import javax.media.jai.iterator.WritableRandomIter;

import oms3.annotations.Author;
import oms3.annotations.Description;
import oms3.annotations.Execute;
import oms3.annotations.In;
import oms3.annotations.Keywords;
import oms3.annotations.Label;
import oms3.annotations.License;
import oms3.annotations.Name;
import oms3.annotations.Out;
import oms3.annotations.Status;

import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.jgrasstools.gears.libs.modules.JGTModel;
import org.jgrasstools.gears.utils.CrsUtilities;
import org.jgrasstools.gears.utils.coverage.CoverageUtilities;
import org.jgrasstools.gears.utils.geometry.GeometryUtilities;
import org.jgrasstools.hortonmachine.i18n.HortonMessageHandler;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Point;

@Description(OMSINSOLATION_DESCRIPTION)
@Author(name = OMSINSOLATION_AUTHORNAMES, contact = OMSINSOLATION_AUTHORCONTACTS)
@Keywords(OMSINSOLATION_KEYWORDS)
@Label(OMSINSOLATION_LABEL)
@Name(OMSINSOLATION_NAME)
@Status(OMSINSOLATION_STATUS)
@License(OMSINSOLATION_LICENSE)
public class OmsInsolation extends JGTModel {

    @Description(OMSINSOLATION_inElev_DESCRIPTION)
    @In
    public GridCoverage2D inElev = null;

    @Description(OMSINSOLATION_tStartDate_DESCRIPTION)
    @In
    public String tStartDate = null;

    @Description(OMSINSOLATION_tEndDate_DESCRIPTION)
    @In
    public String tEndDate = null;

    @Description(OMSINSOLATION_outIns_DESCRIPTION)
    @Out
    public GridCoverage2D outIns;

    private static final double pCmO3 = 0.3;

    private static final double pRH = 0.4;

    private static final double pLapse = -.0065;

    private static final double pVisibility = 60;

    /**
     * The solar constant.
     */
    private static final double SOLARCTE = 1368.0;

    /**
     * The atmosphere pressure.
     */
    private static final double ATM = 1013.25;

    private double lambda;

    private double delta;

    private double omega;

    private HortonMessageHandler msg = HortonMessageHandler.getInstance();

    @Execute
    public void process() throws Exception { // transform the
        checkNull(inElev, tStartDate, tEndDate);
        // extract some attributes of the map
        HashMap<String, Double> attribute = CoverageUtilities.getRegionParamsFromGridCoverage(inElev);
        double dx = attribute.get(CoverageUtilities.XRES);

        /*
         * The models use only one value of the latitude. So I have decided to
         * set it to the center of the raster. Extract the CRS of the
         * GridCoverage and transform the value of a WGS84 latitude.
         */
        CoordinateReferenceSystem sourceCRS = inElev.getCoordinateReferenceSystem2D();
        CoordinateReferenceSystem targetCRS = DefaultGeographicCRS.WGS84;

        double srcPts[] = new double[] { attribute.get(CoverageUtilities.EAST),
                attribute.get(CoverageUtilities.SOUTH) };

        Coordinate source = new Coordinate(srcPts[0], srcPts[1]);
        Point[] so = new Point[] { GeometryUtilities.gf().createPoint(source) };
        CrsUtilities.reproject(sourceCRS, targetCRS, so);
        // the latitude value
        lambda = Math.toRadians(so[0].getY());

        /*
         * transform the start and end date in an int value (the day in the
         * year, from 1 to 365)
         */
        DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd").withZone(DateTimeZone.UTC);
        DateTime currentDatetime = formatter.parseDateTime(tStartDate);
        int startDay = currentDatetime.getDayOfYear();
        currentDatetime = formatter.parseDateTime(tEndDate);
        int endDay = currentDatetime.getDayOfYear();
        CoverageUtilities.getRegionParamsFromGridCoverage(inElev);
        RenderedImage pitTmpRI = inElev.getRenderedImage();
        int width = pitTmpRI.getWidth();
        int height = pitTmpRI.getHeight();
        WritableRaster pitWR = CoverageUtilities.replaceNovalue(pitTmpRI, -9999.0);
        pitTmpRI = null;

        WritableRaster insolationWR = CoverageUtilities.createDoubleWritableRaster(width, height, null,
                pitWR.getSampleModel(), 0.0);
        WritableRandomIter insolationIterator = RandomIterFactory.createWritable(insolationWR, null);

        WritableRaster gradientWR = normalVector(pitWR, dx);

        pm.beginTask(msg.message("insolation.calculating"), endDay - startDay);

        for (int i = startDay; i <= endDay; i++) {
            calcInsolation(lambda, pitWR, gradientWR, insolationWR, i, dx);
            pm.worked(i - startDay);
        }
        pm.done();
        for (int y = 2; y < height - 2; y++) {
            for (int x = 2; x < width - 2; x++) {
                if (pitWR.getSampleDouble(x, y, 0) == -9999.0) {
                    insolationIterator.setSample(x, y, 0, Double.NaN);

                }
            }
        }

        outIns = CoverageUtilities.buildCoverage("insolation", insolationWR, attribute,
                inElev.getCoordinateReferenceSystem());
    }

    /**
     * Evaluate the radiation.
     * 
     * @param lambda
     *            the latitude.
     * @param demWR
     *            the raster of elevation
     * @param gradientWR
     *            the raster of the gradient value of the dem.
     * @param insolationWR
     *            the wr where to store the result.
     * @param the
     *            day in the year.
     * @paradx the resolutiono of the dem.
     */
    private void calcInsolation(double lambda, WritableRaster demWR, WritableRaster gradientWR,
            WritableRaster insolationWR, int day, double dx) {
        // calculating the day angle
        // double dayang = 2 * Math.PI * (day - 1) / 365.0;
        double dayangb = (360 / 365.25) * (day - 79.436);
        dayangb = Math.toRadians(dayangb);
        // Evaluate the declination of the sun.
        delta = getDeclination(dayangb);
        // Evaluate the radiation in this day.
        double ss = Math.acos(-Math.tan(delta) * Math.tan(lambda));
        double hour = -ss + (Math.PI / 48.0);
        while (hour <= ss - (Math.PI / 48)) {
            omega = hour;
            // calculating the vector related to the sun
            double sunVector[] = calcSunVector();
            double zenith = calcZenith(sunVector[2]);
            double[] inverseSunVector = calcInverseSunVector(sunVector);
            double[] normalSunVector = calcNormalSunVector(sunVector);

            int height = demWR.getHeight();
            int width = demWR.getWidth();
            WritableRaster sOmbraWR = calculateFactor(height, width, sunVector, inverseSunVector, normalSunVector,
                    demWR, dx);
            double mr = 1 / (sunVector[2] + 0.15 * Math.pow((93.885 - zenith), (-1.253)));
            for (int j = 0; j < height; j++) {
                for (int i = 0; i < width; i++) {
                    // evaluate the radiation.
                    calcRadiation(i, j, demWR, sOmbraWR, insolationWR, sunVector, gradientWR, mr);
                }
            }
            hour = hour + Math.PI / 24.0;
        }
    }

    /*
     * Evaluate the declination.
     */
    private double getDeclination(double dayangb) {
        double delta = .3723 + 23.2567 * Math.sin(dayangb) - .758 * Math.cos(dayangb)
                + .1149 * Math.sin(2 * dayangb) + .3656 * Math.cos(2 * dayangb) - .1712 * Math.sin(3 * dayangb)
                + .0201 * Math.cos(3 * dayangb);
        return Math.toRadians(delta);
    }

    /*
     * evaluate several component of the radiation and then multiply by the
     * sOmbra factor.
     */
    private void calcRadiation(int i, int j, WritableRaster demWR, WritableRaster sOmbraWR,
            WritableRaster insolationWR, double[] sunVector, WritableRaster gradientWR, double mr) {
        double z = demWR.getSampleDouble(i, j, 0);
        double pressure = ATM * Math.exp(-0.0001184 * z);
        double ma = mr * pressure / ATM;
        double temp = 273 + pLapse * (z - 4000);
        double vap_psat = Math.exp(26.23 - 5416.0 / temp);
        double wPrec = 0.493 * pRH * vap_psat / temp;
        double taur = Math.exp((-.09030 * Math.pow(ma, 0.84)) * (1.0 + ma - Math.pow(ma, 1.01)));
        double d = pCmO3 * mr;
        double tauo = 1 - (0.1611 * d * Math.pow(1.0 + 139.48 * d, -0.3035) - 0.002715 * d)
                / (1.0 + 0.044 * d + 0.0003 * Math.pow(d, 2));
        double taug = Math.exp(-0.0127 * Math.pow(ma, 0.26));
        double tauw = 1 - 2.4959 * (wPrec * mr) / (1.0 + 79.034 * (wPrec * mr) * 0.6828 + 6.385 * (wPrec * mr));
        double taua = Math.pow((0.97 - 1.265 * Math.pow(pVisibility, (-0.66))), Math.pow(ma, 0.9));

        double In = 0.9751 * SOLARCTE * taur * tauo * taug * tauw * taua;

        double cosinc = scalarProduct(sunVector, gradientWR.getPixel(i, j, new double[3]));

        if (cosinc < 0) {
            cosinc = 0;
        }
        double tmp = insolationWR.getSampleDouble(i, j, 0);
        insolationWR.setSample(i, j, 0, In * cosinc * sOmbraWR.getSampleDouble(i, j, 0) / 1000 + tmp);
    }

    protected double[] calcSunVector() {
        double sunVector[] = new double[3];
        sunVector[0] = -Math.sin(omega) * Math.cos(delta);
        sunVector[1] = Math.sin(lambda) * Math.cos(omega) * Math.cos(delta) - Math.cos(lambda) * Math.sin(delta);
        sunVector[2] = Math.cos(lambda) * Math.cos(omega) * Math.cos(delta) + Math.sin(lambda) * Math.sin(delta);

        return sunVector;

    }

    protected WritableRaster normalVector(WritableRaster pitWR, double res) {

        int minX = pitWR.getMinX();
        int minY = pitWR.getMinY();
        int rows = pitWR.getHeight();
        int cols = pitWR.getWidth();

        RandomIter pitIter = RandomIterFactory.create(pitWR, null);
        /*
         * Initializa the Image of the normal vector in the central point of the
         * cells, which have 3 components so the Image have 3 bands..
         */
        SampleModel sm = RasterFactory.createBandedSampleModel(5, cols, rows, 3);
        WritableRaster tmpNormalVectorWR = CoverageUtilities.createDoubleWritableRaster(cols, rows, null, sm, 0.0);
        WritableRandomIter tmpNormalIter = RandomIterFactory.createWritable(tmpNormalVectorWR, null);
        /*
         * apply the corripio's formula (is the formula (3) in the article)
         */
        for (int j = minY; j < minX + rows - 1; j++) {
            for (int i = minX; i < minX + cols - 1; i++) {
                double zij = pitIter.getSampleDouble(i, j, 0);
                double zidxj = pitIter.getSampleDouble(i + 1, j, 0);
                double zijdy = pitIter.getSampleDouble(i, j + 1, 0);
                double zidxjdy = pitIter.getSampleDouble(i + 1, j + 1, 0);
                double firstComponent = res * (zij - zidxj + zijdy - zidxjdy);
                double secondComponent = res * (zij + zidxj - zijdy - zidxjdy);
                double thirthComponent = 2 * (res * res);
                double den = Math.sqrt(firstComponent * firstComponent + secondComponent * secondComponent
                        + thirthComponent * thirthComponent);
                tmpNormalIter.setPixel(i, j,
                        new double[] { firstComponent / den, secondComponent / den, thirthComponent / den });

            }
        }
        pitIter.done();

        return tmpNormalVectorWR;

    }

    private double calcZenith(double sunVector2) {
        return Math.acos(sunVector2);
    }
}