Package ca.eandb.jmist.framework.scatter

Source Code of ca.eandb.jmist.framework.scatter.ABMSurfaceScatterer$VariableThicknessAbsorbingSurfaceScatterer

/**
* Java Modular Image Synthesis Toolkit (JMIST)
* Copyright (C) 2008-2013 Bradley W. Kimmel
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package ca.eandb.jmist.framework.scatter;

import java.io.File;
import java.util.UUID;
import java.util.concurrent.Executors;

import javax.swing.JFrame;

import ca.eandb.jdcp.job.ParallelizableJob;
import ca.eandb.jdcp.job.ParallelizableJobRunner;
import ca.eandb.jmist.framework.Function1;
import ca.eandb.jmist.framework.Random;
import ca.eandb.jmist.framework.SurfacePointGeometry;
import ca.eandb.jmist.framework.function.AXpBFunction1;
import ca.eandb.jmist.framework.function.ConstantFunction1;
import ca.eandb.jmist.framework.function.PiecewiseLinearFunction1;
import ca.eandb.jmist.framework.function.ScaledFunction1;
import ca.eandb.jmist.framework.function.SumFunction1;
import ca.eandb.jmist.framework.job.TransferMatrixJob;
import ca.eandb.jmist.framework.job.TransferMatrixJob.ExitantVectorStrategies;
import ca.eandb.jmist.framework.measurement.CollectorSphere;
import ca.eandb.jmist.framework.measurement.UncappedLatLongCollectorSphere;
import ca.eandb.jmist.math.Vector3;
import ca.eandb.jmist.util.ArrayUtil;
import ca.eandb.util.concurrent.BackgroundThreadFactory;
import ca.eandb.util.progress.ProgressPanel;

/**
* A <code>SurfaceScatterer</code> implementing the ABM-U/ABM-B light transport
* models.
* <p>
* The algorithm implemented here is described in:
* <ul>
*   <li>
*     G.V.G. Baranoski,
*     <a href="http://www.npsg.uwaterloo.ca/resources/docs/rse2006.pdf">
*       Modeling the interaction of infrared raditaion (750 to 2500 nm) with
*       bifacial and unifacial plant leaves</a>,
*     Remote Sensing of Environment 100:335-347, 2006.
*   </li>
*   <li>
*     G.V.G. Baranoski, D. Eng,
*     <a href="http://www.npsg.uwaterloo.ca/resources/docs/ieee07-8.pdf">
*       An investigation on sieve and detour effects affecting the interaction
*       of collimated and diffuse infrared radiation (750 to 2500 nm) with
*       plant leaves</a>,
*     IEEE Transactions on Geoscience and Remote Sensing 45(8):2593-2599,
*     August 2007.
*   </li>
* </ul>
*
* @author Brad Kimmel
* @see <a href="http://www.npsg.uwaterloo.ca/models/ABMU.php">Run ABM-U Online</a>
* @see <a href="http://www.npsg.uwaterloo.ca/models/ABMB.php">Run ABM-B Online</a>
*/
public final class ABMSurfaceScatterer implements SurfaceScatterer {

  /** Serialization version ID. */
  private static final long serialVersionUID = 969983861047935903L;

  /**
   * An absorbing <code>SurfaceScatterer</code> whose thickness may be
   * varied at runtime on a per-thread basis.  This allows the thickness to
   * be determined randomly for each call to
   * <code>ABMSurfaceScatterer.scatter</code>.
   * @author Brad Kimmel
   */
  private static final class VariableThicknessAbsorbingSurfaceScatterer
      implements SurfaceScatterer {

    /** Serialization version ID. */
    private static final long serialVersionUID = 4413776349916702845L;

    /**
     * The <code>Function1</code> indicating the absorption coefficient
     * (in m<sup>-1</sup>).
     */
    private final Function1 absorptionCoefficient;

    /** The per-thread thickness of the absorbing medium (in meters). */
    private final ThreadLocal<Double> thickness = new ThreadLocal<Double>();

    /**
     * Creates a new
     * <code>VariableThicknessAbsorbingSurfaceScatterer</code>.
     * @param absorptionCoefficient The <code>Function1</code> indicating
     *    the absorption coefficient of the medium (in m<sup>-1</sup>).
     */
    public VariableThicknessAbsorbingSurfaceScatterer(Function1 absorptionCoefficient) {
      this.absorptionCoefficient = absorptionCoefficient;
    }

    /**
     * Sets the thickness of the absorbing medium for the current thread.
     * @param thickness The new thickness of the absorbing medium (in
     *     meters).
     */
    public void setThickness(double thickness) {
      this.thickness.set(thickness);
    }

    /* (non-Javadoc)
     * @see ca.eandb.jmist.framework.scatter.SurfaceScatterer#scatter(ca.eandb.jmist.framework.SurfacePointGeometry, ca.eandb.jmist.math.Vector3, boolean, ca.eandb.jmist.framework.color.WavelengthPacket, ca.eandb.jmist.framework.Random)
     */
    public Vector3 scatter(SurfacePointGeometry x, Vector3 v,
        boolean adjoint, double lambda, Random rnd) {

      double abs = absorptionCoefficient.evaluate(lambda);
      double p = -Math.log(1.0 - rnd.next()) * Math.cos(x.getNormal().dot(v)) / abs;

      return (p > thickness.get()) ? v : null;
    }

  }

  /** Array of wavelengths for the associated with the data to follow. */
  private static final double[] WAVELENGTHS = ArrayUtil.range(400e-9, 700e-9, 61); // m

  /**
   * Specific absorption coefficient for chlorophyll a+b (in
   * m<sup>2</sup> kg<sup>-1</sup>).
   */
  private static final double[] SAC_CHLOROPHYLL_AB_VALUES = { // cm^2/g (to be converted)
    73400, 67700, 62300, 58000, 55600, 53400, 52700, 52200,
    51000, 49400, 46700, 44400, 43500, 43500, 43000, 42600,
    42100, 41300, 40000, 37900, 34800, 30700, 26500, 22100,
    18300, 15400, 13600, 12700, 12200, 12000, 11800, 11800,
    12200, 13000, 14200, 15600, 16800, 17800, 18500, 18900,
    19200, 19800, 20700, 21900, 22900, 23400, 23600, 24000,
    25300, 27400, 29400, 30600, 32700, 36100, 38900, 40500,
    40300, 36900, 28200, 19100, 12600
  };

  /**
   * Specific absorption coefficient for carotenoids (in
   * m<sup>2</sup> kg<sup>-1</sup>).
   */
  private static final double[] SAC_CAROTENOIDS_VALUES = { // cm^2/g (to be converted)
     6535.5069237207.1188158017.1690018559.258518,
     9328.9709699942.106999, 10669.577847, 11562.119164,
    11975.755432, 12370.904604, 12843.907698, 13162.723765,
    13594.276407, 14057.034526, 14381.579285, 14550.187782,
    14490.659508, 14248.260257, 13773.149034, 13667.762322,
    13620.968781, 13177.895459, 12539.340804, 10989.320278,
     8895.3802466936.3258134544.0668503170.884351,
     2333.8832821824.5559711519.7127371309.073662,
     1164.5263201068.5054801011.292774,   958.240154,
      958.240154,   958.240154,   947.933115,   921.314601,
      901.556158,   883.250517,   875.085062,   875.085062,
      873.419624,   867.527208,   861.634792,   855.742376,
      849.849960,   843.957544,   838.065128,   834.592308,
      841.777197,   848.962085,   856.146973,   863.331861,
      870.516749,   881.011273,   897.284130,   913.556987,
      894.049970
  };

  /** Specific absorption coefficient for water (in m<sup>-1</sup>). */
  private static final double[] SAC_WATER_VALUES = { // cm^-1 (to be converted)
    0.000066, 0.000053, 0.000047, 0.000044,
    0.000045, 0.000048, 0.000049, 0.000053,
    0.000063, 0.000075, 0.000092, 0.000096,
    0.000098, 0.000101, 0.000106, 0.000114,
    0.000127, 0.000136, 0.000150, 0.000173,
    0.000204, 0.000256, 0.000325, 0.000396,
    0.000409, 0.000417, 0.000434, 0.000452,
    0.000474, 0.000511, 0.000565, 0.000596,
    0.000619, 0.000642, 0.000695, 0.000772,
    0.000896, 0.001100, 0.001351, 0.001672,
    0.002224, 0.002577, 0.002644, 0.002678,
    0.002755, 0.002834, 0.002916, 0.003012,
    0.003108, 0.003250, 0.003400, 0.003710,
    0.004100, 0.004290, 0.004390, 0.004480,
    0.004650, 0.004860, 0.005160, 0.005590,
    0.006240
  };

  /** The index of refraction for water. */
  public static final double[] IOR_WATER_VALUES = {
    1.346, 1.345, 1.344, 1.343, 1.342, 1.341, 1.340, 1.339,
    1.338, 1.338, 1.337, 1.336, 1.336, 1.335, 1.335, 1.334,
    1.334, 1.334, 1.334, 1.333, 1.333, 1.333, 1.333, 1.333,
    1.333, 1.333, 1.333, 1.333, 1.333, 1.333, 1.333, 1.333,
    1.333, 1.333, 1.333, 1.333, 1.333, 1.333, 1.333, 1.333,
    1.333, 1.333, 1.333, 1.333, 1.333, 1.332, 1.332, 1.332,
    1.332, 1.332, 1.332, 1.332, 1.332, 1.332, 1.332, 1.332,
    1.332, 1.332, 1.332, 1.332, 1.332
  };

  /** The index of refraction for the cuticle. */
  public static final double[] IOR_CUTICLE_VALUES = {
    1.539712, 1.539678, 1.537372, 1.536209,
    1.534937, 1.533561, 1.532009, 1.530511,
    1.529224, 1.528078, 1.527108, 1.526012,
    1.524844, 1.523591, 1.522421, 1.521544,
    1.520067, 1.519138, 1.518554, 1.517828,
    1.517050, 1.516272, 1.515421, 1.514547,
    1.513748, 1.513030, 1.512445, 1.511623,
    1.510911, 1.510230, 1.509549, 1.508952,
    1.508368, 1.507785, 1.507203, 1.506620,
    1.505908, 1.505078, 1.504297, 1.503139,
    1.502896, 1.502662, 1.502248, 1.501666,
    1.501087, 1.500568, 1.500049, 1.499530,
    1.499011, 1.498409, 1.497752, 1.497096,
    1.496439, 1.495974, 1.495609, 1.495244,
    1.494879, 1.494510, 1.494139, 1.493768,
    1.493398
  };

  static {

    // convert everything to base SI units
    for (int i = 0; i < WAVELENGTHS.length; i++) {

      // convert cm^2/g to m^2/kg  (divide by 10)
      SAC_CHLOROPHYLL_AB_VALUES[i] /= 10.0;
      SAC_CAROTENOIDS_VALUES[i] /= 10.0;

      // convert cm^-1 to m^-1  (multiply by 100)
      SAC_WATER_VALUES[i] *= 100.0;

    }

  }

  /**
   * Specific absorption coefficient of chlorophyll a+b (in
   * m<sup>2</sup> kg<sup>-1</sup>).
   */
  private static final Function1 SAC_CHLOROPHYLL_AB = new PiecewiseLinearFunction1(
      WAVELENGTHS, SAC_CHLOROPHYLL_AB_VALUES);

  /**
   * Specific absorption coefficient of carotenoids (in
   * m<sup>2</sup> kg<sup>-1</sup>).
   */
  private static final Function1 SAC_CAROTENOIDS = new PiecewiseLinearFunction1(
      WAVELENGTHS, SAC_CAROTENOIDS_VALUES);

  /** Absorption coefficient of water (in m<sup>-1</sup>). */
  private static final Function1 SAC_WATER = new PiecewiseLinearFunction1(
      WAVELENGTHS, SAC_WATER_VALUES);

  /** Index of refraction for water. */
  private static final Function1 IOR_WATER = new PiecewiseLinearFunction1(
      WAVELENGTHS, IOR_WATER_VALUES);

  /** Index of refraction for the cuticle. */
  private static final Function1 IOR_CUTICLE = new PiecewiseLinearFunction1(
      WAVELENGTHS, IOR_CUTICLE_VALUES);

  /** Index of refraction for air. */
  private static final Function1 IOR_AIR = Function1.ONE;

  /**
   * Specific absorption coefficient for protein (in
   * m<sup>2</sup> kg<sup>-1</sup>).
   */
  private static final double SAC_PROTEIN = 1.992; // m^2/kg

  /**
   * Specific absorption coefficient for cellulose+lignin (in
   * m<sup>2</sup> kg<sup>-1</sup>).
   */
  private static final double SAC_CELLULOSE_LIGNIN = 0.876; // m^2/kg

  /** Aspect ratio of cuticle undulations. */
  private double cuticleUndulationsAspectRatio = 5.0;

  /** Aspect ratio of cell caps. */
  private double epidermisCellCapsAspectRatio = 5.0;

  /** Aspect ratio of palisade mesophyll cell caps. */
  private double palisadeCellCapsAspectRatio = 1.0;

  /** Aspect ratio of spongy mesophyll cell caps. */
  private double spongyCellCapsAspectRatio = 5.0;

  /** Thickness of the whole leaf (in meters). */
  private double wholeLeafThickness = 1.66e-4; // meters

  /** Bulk density of the whole leaf (in kg m<sup>-3</sup>). */
  private double dryBulkDensity = 1.19e-5 / (4.1e-4 * 1.66e-4); // kg/m^3

  private double airVolumeFraction = 0.31;
  private double proteinFraction = 0.0;// 0.3106;
  private double celluloseFraction = 0.0;// 0.1490;
  private double ligninFraction = 0.0;// 0.0424;

  /**
   * A value indicating if the leaf is bifacial.  If so, the ABM-B model is
   * used.  Otherwise, ABM-U is used.
   */
  private boolean bifacial = true;

  private double scattererFractionInAntidermalWall = 0.3872;
  private double scattererFractionInMesophyll = 0.3872;

  private double concChlorophyllAInMesophyll = 3.978; // kg/m^3

  private double concChlorophyllBInMesophyll = 1.161; // kg/m^3

  private double concCarotenoidsInMesophyll = 1.132; // kg/m^3;

  /**
   * Total thickness of the mesophyll layers (in meters).  This value is set
   * internally, rather than directly by the user.
   */
  private double mesophyllThickness;

  /** The upper spongy mesophyll layer used in the ABM-U implementation. */
  private VariableThicknessAbsorbingSurfaceScatterer topSpongyMesophyllLayer;

  /** The lower spongy mesophyll layer used in the ABM-U implementation. */
  private VariableThicknessAbsorbingSurfaceScatterer bottomSpongyMesophyllLayer;

  /** The <code>LayeredSurfaceScatterer</code> representing the ABM model. */
  private final LayeredSurfaceScatterer subsurface = new LayeredSurfaceScatterer();

  /**
   * @return the cuticleUndulationsAspectRatio
   */
  public double getCuticleUndulationsAspectRatio() {
    return cuticleUndulationsAspectRatio;
  }


  /**
   * @param cuticleUndulationsAspectRatio the cuticleUndulationsAspectRatio to set
   */
  public void setCuticleUndulationsAspectRatio(
      double cuticleUndulationsAspectRatio) {
    this.cuticleUndulationsAspectRatio = cuticleUndulationsAspectRatio;
  }


  /**
   * @return the epidermisCellCapsAspectRatio
   */
  public double getEpidermisCellCapsAspectRatio() {
    return epidermisCellCapsAspectRatio;
  }


  /**
   * @param epidermisCellCapsAspectRatio the epidermisCellCapsAspectRatio to set
   */
  public void setEpidermisCellCapsAspectRatio(double epidermisCellCapsAspectRatio) {
    this.epidermisCellCapsAspectRatio = epidermisCellCapsAspectRatio;
  }


  /**
   * @return the palisadeCellCapsAspectRatio
   */
  public double getPalisadeCellCapsAspectRatio() {
    return palisadeCellCapsAspectRatio;
  }


  /**
   * @param palisadeCellCapsAspectRatio the palisadeCellCapsAspectRatio to set
   */
  public void setPalisadeCellCapsAspectRatio(double palisadeCellCapsAspectRatio) {
    this.palisadeCellCapsAspectRatio = palisadeCellCapsAspectRatio;
  }


  /**
   * @return the spongyCellCapsAspectRatio
   */
  public double getSpongyCellCapsAspectRatio() {
    return spongyCellCapsAspectRatio;
  }


  /**
   * @param spongyCellCapsAspectRatio the spongyCellCapsAspectRatio to set
   */
  public void setSpongyCellCapsAspectRatio(double spongyCellCapsAspectRatio) {
    this.spongyCellCapsAspectRatio = spongyCellCapsAspectRatio;
  }


  /**
   * @return the wholeLeafThickness
   */
  public double getWholeLeafThickness() {
    return wholeLeafThickness;
  }


  /**
   * @param wholeLeafThickness the wholeLeafThickness to set
   */
  public void setWholeLeafThickness(double wholeLeafThickness) {
    this.wholeLeafThickness = wholeLeafThickness;
  }


  /**
   * @return the dryBulkDensity
   */
  public double getDryBulkDensity() {
    return dryBulkDensity;
  }


  /**
   * @param dryBulkDensity the dryBulkDensity to set
   */
  public void setDryBulkDensity(double dryBulkDensity) {
    this.dryBulkDensity = dryBulkDensity;
  }


  /**
   * @return the airVolumeFraction
   */
  public double getAirVolumeFraction() {
    return airVolumeFraction;
  }


  /**
   * @param airVolumeFraction the airVolumeFraction to set
   */
  public void setAirVolumeFraction(double airVolumeFraction) {
    this.airVolumeFraction = airVolumeFraction;
  }


  /**
   * @return the proteinFraction
   */
  public double getProteinFraction() {
    return proteinFraction;
  }


  /**
   * @param proteinFraction the proteinFraction to set
   */
  public void setProteinFraction(double proteinFraction) {
    this.proteinFraction = proteinFraction;
  }


  /**
   * @return the celluloseFraction
   */
  public double getCelluloseFraction() {
    return celluloseFraction;
  }


  /**
   * @param celluloseFraction the celluloseFraction to set
   */
  public void setCelluloseFraction(double celluloseFraction) {
    this.celluloseFraction = celluloseFraction;
  }


  /**
   * @return the ligninFraction
   */
  public double getLigninFraction() {
    return ligninFraction;
  }


  /**
   * @param ligninFraction the ligninFraction to set
   */
  public void setLigninFraction(double ligninFraction) {
    this.ligninFraction = ligninFraction;
  }


  /**
   * @return the bifacial
   */
  public boolean isBifacial() {
    return bifacial;
  }


  /**
   * @param bifacial the bifacial to set
   */
  public void setBifacial(boolean bifacial) {
    this.bifacial = bifacial;
  }


  /**
   * @return the scattererFractionInAntidermalWall
   */
  public double getScattererFractionInAntidermalWall() {
    return scattererFractionInAntidermalWall;
  }


  /**
   * @param scattererFractionInAntidermalWall the scattererFractionInAntidermalWall to set
   */
  public void setScattererFractionInAntidermalWall(
      double scattererFractionInAntidermalWall) {
    this.scattererFractionInAntidermalWall = scattererFractionInAntidermalWall;
  }


  /**
   * @return the scattererFractionInMesophyll
   */
  public double getScattererFractionInMesophyll() {
    return scattererFractionInMesophyll;
  }


  /**
   * @param scattererFractionInMesophyll the scattererFractionInMesophyll to set
   */
  public void setScattererFractionInMesophyll(double scattererFractionInMesophyll) {
    this.scattererFractionInMesophyll = scattererFractionInMesophyll;
  }


  /**
   * @return the concChlorophyllAInMesophyll
   */
  public double getConcChlorophyllAInMesophyll() {
    return concChlorophyllAInMesophyll;
  }


  /**
   * @param concChlorophyllAInMesophyll the concChlorophyllAInMesophyll to set
   */
  public void setConcChlorophyllAInMesophyll(double concChlorophyllAInMesophyll) {
    this.concChlorophyllAInMesophyll = concChlorophyllAInMesophyll;
  }


  /**
   * @return the concChlorophyllBInMesophyll
   */
  public double getConcChlorophyllBInMesophyll() {
    return concChlorophyllBInMesophyll;
  }


  /**
   * @param concChlorophyllBInMesophyll the concChlorophyllBInMesophyll to set
   */
  public void setConcChlorophyllBInMesophyll(double concChlorophyllBInMesophyll) {
    this.concChlorophyllBInMesophyll = concChlorophyllBInMesophyll;
  }


  /**
   * @return the concCarotenoidsInMesophyll
   */
  public double getConcCarotenoidsInMesophyll() {
    return concCarotenoidsInMesophyll;
  }


  /**
   * @param concCarotenoidsInMesophyll the concCarotenoidsInMesophyll to set
   */
  public void setConcCarotenoidsInMesophyll(double concCarotenoidsInMesophyll) {
    this.concCarotenoidsInMesophyll = concCarotenoidsInMesophyll;
  }

  /**
   * Populates the <code>LayeredSurfaceScatterer</code> according to the ABM
   * model from the model parameters.
   */
  private synchronized void build() {
    subsurface.clear();

//    Function1 iorMesophyll = new AXpBFunction1(
//        (1.0 - scattererFractionInMesophyll),
//        1.5608 * scattererFractionInMesophyll,
//        IOR_WATER);

    Function1 iorMesophyll = new ConstantFunction1(1.415);

    Function1 iorAntidermalWall = new AXpBFunction1(
        (1.0 - scattererFractionInAntidermalWall),
        1.535 * scattererFractionInAntidermalWall,
        IOR_WATER);

    double concDryMatter = dryBulkDensity / (1.0 - airVolumeFraction);

    double concProtein = concDryMatter * proteinFraction;
    double concCellulose = concDryMatter * celluloseFraction;
    double concLignin = concDryMatter * ligninFraction;

    double absProtein = concProtein * SAC_PROTEIN;
    double absCellulose = concCellulose * SAC_CELLULOSE_LIGNIN;
    double absLignin = concLignin * SAC_CELLULOSE_LIGNIN;

    Function1 mesophyllAbsorptionCoefficient = new SumFunction1()
      .addChild(new ScaledFunction1(
          concChlorophyllAInMesophyll + concChlorophyllBInMesophyll,
          SAC_CHLOROPHYLL_AB))
      .addChild(new ScaledFunction1(
          concCarotenoidsInMesophyll,
          SAC_CAROTENOIDS))
      .addChild(new ConstantFunction1(absProtein + absCellulose + absLignin))
      .addChild(SAC_WATER);

//    try {
//      OutputStream file = new FileOutputStream("/Users/brad/mesosac.csv");
//      PrintStream out = new PrintStream(new CompositeOutputStream()
//          .addChild(System.out)
//          .addChild(file));
//      for (int i = 400; i <= 700; i += 5) {
//        out.println(mesophyllAbsorptionCoefficient.evaluate(1e-9 * (double) i));
//      }
//      out.flush();
//      file.close();
//    } catch (IOException e) {
//      e.printStackTrace();
//    }

    double mesophyllFraction = bifacial ? 0.5 : 0.8;
    mesophyllThickness = mesophyllFraction * wholeLeafThickness;

    double lambda = 550e-9;
    System.out.printf("mesophyllAbsorptionCoefficient=%f", mesophyllAbsorptionCoefficient.evaluate(lambda));
    System.out.println();
    System.out.printf("mesophyllThickness=%f", mesophyllThickness);
    System.out.println();
    System.out.printf("mesophyllOpticalDepth=%f", mesophyllAbsorptionCoefficient.evaluate(lambda) * mesophyllThickness);
    System.out.println();
    System.out.printf("nCuticle=%f", IOR_CUTICLE.evaluate(lambda));
    System.out.println();
    System.out.printf("nWater=%f", IOR_WATER.evaluate(lambda));
    System.out.println();
    System.out.printf("sacWater=%f", SAC_WATER.evaluate(lambda));
    System.out.println();
    System.out.printf("nWall=%f", iorAntidermalWall.evaluate(lambda));
    System.out.println();
    System.out.printf("nMesophyll=%f", iorMesophyll.evaluate(lambda));
    System.out.println();
    System.out.printf("dryBulkDensity=%f", dryBulkDensity);
    System.out.println();

    if (bifacial) {
      subsurface
        .addLayerToBottom(new ABMInterfaceSurfaceScatterer(
            IOR_CUTICLE, IOR_AIR,
            cuticleUndulationsAspectRatio,
            epidermisCellCapsAspectRatio,
            Double.POSITIVE_INFINITY,
            epidermisCellCapsAspectRatio))
        .addLayerToBottom(new ABMInterfaceSurfaceScatterer(
            iorMesophyll, IOR_CUTICLE,
            epidermisCellCapsAspectRatio,
            palisadeCellCapsAspectRatio,
            epidermisCellCapsAspectRatio,
            palisadeCellCapsAspectRatio))
        .addLayerToBottom(new ABMSieveAbsorbingSurfaceScatterer(
            mesophyllAbsorptionCoefficient,
            mesophyllThickness))
        .addLayerToBottom(new ABMInterfaceSurfaceScatterer(
            IOR_AIR, iorMesophyll,
            palisadeCellCapsAspectRatio,
            spongyCellCapsAspectRatio,
            palisadeCellCapsAspectRatio,
            spongyCellCapsAspectRatio))
        .addLayerToBottom(new ABMInterfaceSurfaceScatterer(
            iorAntidermalWall, IOR_AIR,
            Double.POSITIVE_INFINITY,
            Double.POSITIVE_INFINITY,
            Double.POSITIVE_INFINITY,
            Double.POSITIVE_INFINITY))
        .addLayerToBottom(new ABMInterfaceSurfaceScatterer(
            IOR_CUTICLE, iorAntidermalWall,
            Double.POSITIVE_INFINITY,
            epidermisCellCapsAspectRatio,
            Double.POSITIVE_INFINITY,
            epidermisCellCapsAspectRatio))
        .addLayerToBottom(new ABMInterfaceSurfaceScatterer(
            IOR_AIR, IOR_CUTICLE,
            epidermisCellCapsAspectRatio,
            Double.POSITIVE_INFINITY,
            epidermisCellCapsAspectRatio,
            cuticleUndulationsAspectRatio));
    } else { // unifacial
      topSpongyMesophyllLayer = new VariableThicknessAbsorbingSurfaceScatterer(
          mesophyllAbsorptionCoefficient);
      bottomSpongyMesophyllLayer = new VariableThicknessAbsorbingSurfaceScatterer(
          mesophyllAbsorptionCoefficient);
      subsurface
        .addLayerToBottom(new ABMInterfaceSurfaceScatterer(
            IOR_CUTICLE, IOR_AIR,
            cuticleUndulationsAspectRatio,  // \/
            epidermisCellCapsAspectRatio,   // \
            Double.POSITIVE_INFINITY,       // /
            epidermisCellCapsAspectRatio    // /\
            ))
        .addLayerToBottom(new ABMInterfaceSurfaceScatterer(
            iorMesophyll, IOR_CUTICLE,
            epidermisCellCapsAspectRatio,
            spongyCellCapsAspectRatio,
            epidermisCellCapsAspectRatio,
            spongyCellCapsAspectRatio))
        .addLayerToBottom(topSpongyMesophyllLayer)
        .addLayerToBottom(new ABMInterfaceSurfaceScatterer(
            IOR_AIR, iorMesophyll,
            spongyCellCapsAspectRatio,
            spongyCellCapsAspectRatio,
            spongyCellCapsAspectRatio,
            spongyCellCapsAspectRatio))
        .addLayerToBottom(new ABMInterfaceSurfaceScatterer(
            iorMesophyll, IOR_AIR,
            spongyCellCapsAspectRatio,
            spongyCellCapsAspectRatio,
            spongyCellCapsAspectRatio,
            spongyCellCapsAspectRatio))
        .addLayerToBottom(bottomSpongyMesophyllLayer)
        .addLayerToBottom(new ABMInterfaceSurfaceScatterer(
            IOR_CUTICLE, iorMesophyll,
            spongyCellCapsAspectRatio,
            epidermisCellCapsAspectRatio,
            spongyCellCapsAspectRatio,
            epidermisCellCapsAspectRatio))
        .addLayerToBottom(new ABMInterfaceSurfaceScatterer(
            IOR_AIR, IOR_CUTICLE,
            epidermisCellCapsAspectRatio,
            Double.POSITIVE_INFINITY,
            epidermisCellCapsAspectRatio,
            cuticleUndulationsAspectRatio));

    }
    //System.exit(1);
  }

  /**
   * Checks if the layers have been created yet.  Creates them if they have
   * not been.
   */
  private synchronized void checkBuild() {
    if (subsurface.getNumLayers() == 0) {
      build();
    }
  }

  /* (non-Javadoc)
   * @see ca.eandb.jmist.framework.scatter.SurfaceScatterer#scatter(ca.eandb.jmist.framework.SurfacePoint, ca.eandb.jmist.math.Vector3, boolean, ca.eandb.jmist.framework.color.WavelengthPacket, ca.eandb.jmist.framework.Random)
   */
  public Vector3 scatter(SurfacePointGeometry x, Vector3 v, boolean adjoint,
      double lambda, Random rnd) {

    if (subsurface.getNumLayers() == 0) { // check once before proceeding to
                                        // avoid unnecessary synchronization.
      checkBuild();
    }

    if (!bifacial) {
      double split = rnd.next();
      topSpongyMesophyllLayer.setThickness(split * mesophyllThickness);
      bottomSpongyMesophyllLayer.setThickness((1.0 - split) * mesophyllThickness);
    }

    return subsurface.scatter(x, v, adjoint, lambda, rnd);
  }


  public static void main(String[] args) {


//    public TransferMatrixJob(SurfaceScatterer[] specimens, double[] wavelengths,
//        long samplesPerMeasurement, long samplesPerTask, CollectorSphere collector) {

    double[] stacks = ArrayUtil.range(0.0, Math.PI, 181);
    double[] slices = new double[]{ 0.0, 2.0 * Math.PI };
    CollectorSphere collector = new UncappedLatLongCollectorSphere(stacks, slices);
//    CollectorSphere collector = new EqualPolarAnglesCollectorSphere(90, 1, true, true);
    double wavelength = 550e-9;

    ABMSurfaceScatterer abm = new ABMSurfaceScatterer();
    abm.build();

//    SurfaceScatterer[] specimens = new SurfaceScatterer[]{
////        new LambertianSurfaceScatterer()
////        SurfaceScatterer.TRANSMIT
//        new AbsorbingSurfaceScatterer(new ConstantFunction1(0.1), 1.0)
////        SurfaceScatterer.REFLECT
////        new FresnelSurfaceScatterer(1.0, 1.5)
//    };
    int N = 100000000;

    ParallelizableJob job = new TransferMatrixJob.Builder()
        .addSpecimens(abm.subsurface.getLayers())
        .addWavelength(wavelength)
        .setCollectorSphere(collector)
        .setSamplesPerMeasurement(N)
        .setTasksPerMeasurement(8)
        .build();

    int threads = Runtime.getRuntime().availableProcessors();

    ProgressPanel panel = new ProgressPanel();
    JFrame frame = new JFrame();
    frame.add(panel);
    frame.pack();
    frame.setVisible(true);

    File base = new File("C:\\Users\\Brad\\My Documents\\jmist");
    UUID id = UUID.randomUUID();
    File dir = new File(base, id.toString());

    Runnable runner = new ParallelizableJobRunner(job, dir, Executors.newFixedThreadPool(threads, new BackgroundThreadFactory()), threads, panel, panel.createProgressMonitor("Rendering Cornell Box"));//Runtime.getRuntime().availableProcessors());
    runner.run();

  }

}
TOP

Related Classes of ca.eandb.jmist.framework.scatter.ABMSurfaceScatterer$VariableThicknessAbsorbingSurfaceScatterer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.