Example #1
0
def test_uniform(modes_all):
    from mitsuba.core.xml import load_dict

    # Instantiate with value only
    s = UniformSpectrum(value=1.0)
    assert s.quantity is PhysicalQuantity.DIMENSIONLESS
    assert s.value == 1.0 * ureg.dimensionless

    # Instantiate with value and quantity
    s = UniformSpectrum(value=1.0,
                        quantity=PhysicalQuantity.COLLISION_COEFFICIENT)
    assert s.value == 1.0 * ureg.m**-1
    UniformSpectrum(value=1.0, quantity="collision_coefficient")
    assert s.quantity == PhysicalQuantity.COLLISION_COEFFICIENT
    assert s.value == 1.0 * ureg.m**-1

    # Instantiate with unsupported quantity
    with pytest.raises(ValueError):
        UniformSpectrum(value=1.0, quantity="speed")

    # Instantiate with all arguments
    s = UniformSpectrum(quantity="collision_coefficient", value=1.0)
    assert s.value == ureg.Quantity(1.0, "m^-1")

    # Raise if units and quantity are inconsistent
    with pytest.raises(pinttr.exceptions.UnitsError):
        UniformSpectrum(quantity="collision_coefficient",
                        value=ureg.Quantity(1.0, ""))

    # Instantiate from factory using dict
    s = spectrum_factory.convert({
        "type": "uniform",
        "quantity": "radiance",
        "value": 1.0,
        "value_units": "W/km^2/sr/nm",
    })

    # Produced kernel dict is valid
    ctx = KernelDictContext()
    assert load_dict(onedict_value(s.kernel_dict(ctx))) is not None

    # Unit scaling is properly applied
    with ucc.override({"radiance": "W/m^2/sr/nm"}):
        s = UniformSpectrum(quantity="radiance", value=1.0)
    with uck.override({"radiance": "kW/m^2/sr/nm"}):
        ctx = KernelDictContext()
        d = s.kernel_dict(ctx)
        assert np.allclose(d["spectrum"]["value"], 1e-3)
Example #2
0
def test_interpolated_kernel_dict(modes_all_mono):
    from mitsuba.core.xml import load_dict

    ctx = KernelDictContext(spectral_ctx=SpectralContext.new(wavelength=550.0))

    spectrum = InterpolatedSpectrum(
        id="spectrum",
        quantity="irradiance",
        wavelengths=[500.0, 600.0],
        values=[0.0, 1.0],
    )

    # Produced kernel dict is valid
    assert load_dict(spectrum.kernel_dict(ctx)["spectrum"]) is not None

    # Unit scaling is properly applied
    with ucc.override({"radiance": "W/m^2/sr/nm"}):
        s = InterpolatedSpectrum(
            quantity="radiance", wavelengths=[500.0, 600.0], values=[0.0, 1.0]
        )
    with uck.override({"radiance": "kW/m^2/sr/nm"}):
        d = s.kernel_dict(ctx)
        assert np.allclose(d["spectrum"]["value"], 5e-4)
def test_1050(reflectance, artefact_dir):
    r"""
    Results consistency between `mono_double` and `ckd_double` modes
    ================================================================

    This test checks the results consistency between mono_double and ckd_double
    modes in the [1049.5, 1050.5] nm wavelength bin.

    Rationale
    ---------

    * Sensor: Distant measure covering a plane (11 angular points,
      10000 sample per pixel) and targeting (0, 0, 0).
    * Illumination: Directional illumination with a zenith angle
      :math:`\theta = 50.0°`.
    * Surface: a square surface with a Lambertian BRDF with reflectance
      parameter in :math:`\rho \in [0.0, 0.5, 1.0]`.
    * Atmosphere: a molecular atmosphere derived from the AFGL (1986)
      thermophysical properties `us_standard` model, with both scattering and
      absorption enabled.
    * Integrator: volumetric path tracer.

    Expected behaviour
    ------------------

    The [1049.5, 1050.5] nm - integrated BRF results obtained with the
    `mono_double` and `ckd_double` modes should agree within 5 %.

    The `mono_double` BRF results are spectrally averaged according to the
    following formula:

    .. math::

       \hat{q} = \frac{
          \int_{
             \lambda_{\mathrm{min}}
          }^{
             \lambda_{\mathrm{max}}
          }
          q(\lambda) \, \mathrm{d} \lambda
       }{
          \int_{
             \lambda_{\mathrm{min}}
          }^{
             \lambda_{\mathrm{max}}
          }
          \mathrm{d} \lambda
       }

    where

    * :math:`q` is some spectral quantity (e.g. the BRF)
    * :math:`\lambda` denotes the wavelength
    * :math:`[\lambda_{\mathrm{min}},\, \lambda_{\mathrm{max}}]` is the
      wavelength bin

    Results
    -------

    Note: :math:`\mathrm{RAD}(x, y) = \left| \dfrac{x - y}{x} \right|`

    .. image:: generated/plots/test_onedim_ckd_vs_mono_1050_0.0.png
       :width: 95%
    .. image:: generated/plots/test_onedim_ckd_vs_mono_1050_0.5.png
       :width: 95%
    .. image:: generated/plots/test_onedim_ckd_vs_mono_1050_1.0.png
       :width: 95%
    """
    # Settings
    zeniths = np.linspace(-75, 75, 11)
    spp = 1e4
    wavelength_min = 1049.5 * ureg.nm
    wavelength_max = 1050.5 * ureg.nm
    wavenumbers = np.linspace(1 / wavelength_max, 1 / wavelength_min, 1001)
    wavelengths = 1 / wavenumbers  # mono mode setting
    bin_set = "1nm"  # ckd mode setting
    bins = "1050"  # ckd mode setting

    # Determine artefact filename
    outdir = os.path.join(artefact_dir, "plots")
    os.makedirs(outdir, exist_ok=True)
    fname_plot = os.path.join(
        outdir, f"test_onedim_ckd_vs_mono_{bins}_{reflectance}.png")

    # Skip if data is missing, but still create an artefact
    for dataset_id in [
            "H2O-spectra-9400_9500",
            "H2O-spectra-9500_9600",
            "CO2-spectra-9400_9500",
            "CO2-spectra-9500_9600",
            "N2O-spectra-9400_9500",
            "N2O-spectra-9500_9600",
            "CO-spectra-9400_9500",
            "CO-spectra-9500_9600",
            "CH4-spectra-9400_9500",
            "CH4-spectra-9500_9600",
            "O2-spectra-9400_9500",
            "O2-spectra-9500_9600",
    ]:
        test_tools.skipif_data_not_found(
            "absorption_spectrum",
            dataset_id,
            action=lambda: test_tools.missing_artefact(fname_plot),
        )

    # Monochromatic experiment
    mono_exp = init_mono_experiment(
        wavelengths=wavelengths,
        spp=spp,
        reflectance=reflectance,
        zeniths=zeniths,
    )
    with uck.override(
            length="km"):  # this is a temporary workaround the 'batman' issue
        mono_exp.run()
    mono_results = mono_exp.results["measure"]

    wavelength_bin_width = (wavelengths.max() - wavelengths.min()).m_as(
        mono_results.w.attrs["units"])
    mono_results_averaged = mono_results.integrate(
        coord="w") / wavelength_bin_width

    # CKD experiment
    ckd_exp = init_ckd_experiment(
        bin_set=bin_set,
        bins=bins,
        spp=spp,
        reflectance=reflectance,
        zeniths=zeniths,
    )
    ckd_exp.run()
    ckd_results = ckd_exp.results["measure"]

    # Make figure
    make_figure(
        ckd_results=ckd_results,
        mono_results_averaged=mono_results_averaged,
        fname_plot=fname_plot,
        wavelength_bin="[1049.5, 1050.5] nm",
        reflectance=reflectance,
    )

    # Assert averaged mono results are consistent with ckd results within 5 %
    mono_brf = mono_results_averaged.brf.squeeze().values
    ckd_brf = ckd_results.brf.squeeze().values
    assert np.allclose(mono_brf, ckd_brf, rtol=0.05)
Example #4
0
def test_target_origin(modes_all):
    from mitsuba.core import Point3f

    # TargetPoint: basic constructor
    with ucc.override({"length": "km"}):
        t = TargetPoint([0, 0, 0])
        assert t.xyz.units == ureg.km

    with pytest.raises(ValueError):
        TargetPoint(0)

    # TargetPoint: check kernel item
    with ucc.override({"length": "km"}), uck.override({"length": "m"}):
        t = TargetPoint([1, 2, 0])
        assert ek.allclose(t.kernel_item(), [1000, 2000, 0])

    # TargetRectangle: basic constructor
    with ucc.override({"length": "km"}):
        t = TargetRectangle(0, 1, 0, 1)
        assert t.xmin == 0.0 * ureg.km
        assert t.xmax == 1.0 * ureg.km
        assert t.ymin == 0.0 * ureg.km
        assert t.ymax == 1.0 * ureg.km

    with ucc.override({"length": "m"}):
        t = TargetRectangle(0, 1, 0, 1)
        assert t.xmin == 0.0 * ureg.m
        assert t.xmax == 1.0 * ureg.m
        assert t.ymin == 0.0 * ureg.m
        assert t.ymax == 1.0 * ureg.m

    with pytest.raises(ValueError):
        TargetRectangle(0, 1, "a", 1)

    with pytest.raises(ValueError):
        TargetRectangle(0, 1, 1, -1)

    # TargetRectangle: check kernel item
    t = TargetRectangle(-1, 1, -1, 1)

    with uck.override({"length":
                       "mm"}):  # Tricky: we can't compare transforms directly
        kernel_item = t.kernel_item()["to_world"]
        assert ek.allclose(kernel_item.transform_point(Point3f(-1, -1, 0)),
                           [-1000, -1000, 0])
        assert ek.allclose(kernel_item.transform_point(Point3f(1, 1, 0)),
                           [1000, 1000, 0])
        assert ek.allclose(kernel_item.transform_point(Point3f(1, 1, 42)),
                           [1000, 1000, 42])

    # Factory: basic test
    with ucc.override({"length": "m"}):
        t = Target.new("point", xyz=[1, 1, 0])
        assert isinstance(t, TargetPoint)
        assert np.allclose(t.xyz, ureg.Quantity([1, 1, 0], ureg.m))

        t = Target.new("rectangle", 0, 1, 0, 1)
        assert isinstance(t, TargetRectangle)

    # Converter: basic test
    with ucc.override({"length": "m"}):
        t = Target.convert({"type": "point", "xyz": [1, 1, 0]})
        assert isinstance(t, TargetPoint)
        assert np.allclose(t.xyz, ureg.Quantity([1, 1, 0], ureg.m))

        t = Target.convert([1, 1, 0])
        assert isinstance(t, TargetPoint)
        assert np.allclose(t.xyz, ureg.Quantity([1, 1, 0], ureg.m))

        with pytest.raises(ValueError):
            Target.convert({"xyz": [1, 1, 0]})