Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gray vs multigroup #5

Open
wants to merge 26 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
41c4a45
ryan's mean singularity-opac
brryan Dec 18, 2024
acb2cfd
Multiple initialize commands
brryan Dec 18, 2024
86a9111
fix some issues
brryan Dec 18, 2024
a72bded
Sample MG CDF
brryan Dec 18, 2024
da7c6ec
n_nubinsd, emis poison fix, work on transporters
brryan Dec 18, 2024
a4b0491
Fixing little errors
brryan Dec 19, 2024
3ded5a3
Need to fix UpdateDerivedTransportFields
brryan Dec 20, 2024
f9f2a71
multiply Jnu by dnu
brryan Dec 20, 2024
0fc595b
fix cdf integration
brryan Dec 20, 2024
4d38f84
inf example cycles
brryan Dec 20, 2024
3643bc9
Modified inputs... but stepdiff is nan...
brryan Dec 20, 2024
d264ed0
OK stepdiff runs now but the test fails
brryan Dec 20, 2024
57f4fe1
Merge branch 'develop' into brryan/gray_vs_mg
brryan Jan 21, 2025
f026b92
Apply suggestions from code review
RyanWollaeger Jan 21, 2025
8ed3161
Make a few minor updates.
RyanWollaeger Jan 22, 2025
33d68b9
Cancel more exp(log()) occurrences.
RyanWollaeger Jan 22, 2025
5bffda0
Do not divide particle energy weight by frequency.
RyanWollaeger Jan 29, 2025
a11cc40
+ Update singularity-eos submodule for spiner (databox) update.
RyanWollaeger Feb 6, 2025
9a4c1f2
Include generated headers and add_subdirectory for singularity-eos.
RyanWollaeger Feb 6, 2025
9376c83
Attempt to fix grey DDMC.
RyanWollaeger Feb 6, 2025
b3149b0
Merge remote-tracking branch 'origin/develop' into brryan/gray_vs_mg
Feb 11, 2025
52d1d31
Use null initialization about constexpr branching
Feb 11, 2025
cd8a11c
Fix scope issue in tasklist construction
Feb 11, 2025
e641386
Update patch path
Feb 11, 2025
27f5216
Add frequency redistribution from effective scattering to transport.cpp.
RyanWollaeger Feb 12, 2025
116f682
Add 16-group multigroup version of inf.in (infinite medium) input.
RyanWollaeger Feb 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ if(JAYBENNE_STANDALONE_MODE)
set(JAYBENNE_SCATTERING_OPACITY_TYPE
"mcblock::Scattering"
CACHE STRING "Namespace for scattering opacity Singularity type" FORCE)
set(JAYBENNE_ABSORPTION_MEAN_OPACITY_TYPE
"mcblock::MeanOpacity"
CACHE STRING "Namespace for absorption mean opacity Singularity type" FORCE)
set(JAYBENNE_SCATTERING_MEAN_OPACITY_TYPE
"mcblock::MeanScattering"
CACHE STRING "Namespace for scattering mean opacity Singularity type" FORCE)
set(JAYBENNE_HOST_VARIABLE_HEADER
"../mcblock/mcblock_variables.hpp"
CACHE STRING "Path to host code variables header file" FORCE)
Expand Down
111 changes: 89 additions & 22 deletions src/jaybenne/jaybenne.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ TaskCollection RadiationStep(Mesh *pmesh, const Real t_start, const Real dt) {
auto &jb_pkg = pmesh->packages.Get("jaybenne");
const auto &max_transport_iterations = jb_pkg->Param<int>("max_transport_iterations");
const bool &use_ddmc = jb_pkg->Param<bool>("use_ddmc");
const auto &fd = jb_pkg->Param<FrequencyType>("frequency_type");

// MeshData subsets
auto ddmc_field_names = std::vector<std::string>{fj::ddmc_face_prob::name()};
Expand Down Expand Up @@ -102,9 +103,20 @@ TaskCollection RadiationStep(Mesh *pmesh, const Real t_start, const Real dt) {

// prepare for iterative transport loop
auto derived = tl.AddTask(none, UpdateDerivedTransportFields, base.get(), dt);
auto source = tl.AddTask(
derived, jaybenne::SourcePhotons<MeshData<Real>, jaybenne::SourceType::emission>,
base.get(), t_start, dt);
TaskID source = derived;
if (fd == FrequencyType::gray) {
auto source = tl.AddTask(
derived,
jaybenne::SourcePhotons<MeshData<Real>, jaybenne::SourceType::emission,
FrequencyType::gray>,
base.get(), t_start, dt);
} else if (fd == FrequencyType::multigroup) {
auto source = tl.AddTask(
derived,
jaybenne::SourcePhotons<MeshData<Real>, jaybenne::SourceType::emission,
FrequencyType::multigroup>,
base.get(), t_start, dt);
}
auto bcs = use_ddmc ? parthenon::AddBoundaryExchangeTasks(source, tl, md_ddmc,
pmesh->multilevel)
: source;
Expand Down Expand Up @@ -151,12 +163,13 @@ TaskCollection RadiationStep(Mesh *pmesh, const Real t_start, const Real dt) {
}

//----------------------------------------------------------------------------------------
//! \fn StateDescriptor Jaybenne::Initialize
//! \fn StateDescriptor Jaybenne::Initialize_impl
//! \brief Initialize the Jaybenne physics package. This function defines and sets the
//! parameters associated with Jaybenne, and enrolls the data variables associated with
//! this physics package.
std::shared_ptr<StateDescriptor> Initialize(ParameterInput *pin, Opacity &opacity,
Scattering &scattering, EOS &eos) {
//! this physics package, for everything not related to frequency discretization.
std::shared_ptr<StateDescriptor>
Initialize_impl(ParameterInput *pin, EOS &eos,
singularity::RuntimePhysicalConstants units) {
auto pkg = std::make_shared<StateDescriptor>("jaybenne");

// Total number of particles
Expand All @@ -172,16 +185,11 @@ std::shared_ptr<StateDescriptor> Initialize(ParameterInput *pin, Opacity &opacit
"Minimum allowable swarm occupancy must be >= 0 and less than 1");
pkg->AddParam<>("min_swarm_occupancy", min_swarm_occupancy);

// Frequency range
Real numin = pin->GetOrAddReal("jaybenne", "numin", std::numeric_limits<Real>::min());
pkg->AddParam<>("numin", numin);
Real numax = pin->GetOrAddReal("jaybenne", "numax", std::numeric_limits<Real>::max());
pkg->AddParam<>("numax", numax);

// Physical constants
const auto units = opacity.GetRuntimePhysicalConstants();
// const auto units = opacity.GetRuntimePhysicalConstants();
pkg->AddParam<>("speed_of_light", units.c);
pkg->AddParam<>("stefan_boltzmann", units.sb);
pkg->AddParam<>("planck_constant", units.h);

// RNG
bool unique_rank_seeds = pin->GetOrAddBoolean("jaybenne", "unique_rank_seeds", true);
Expand Down Expand Up @@ -226,12 +234,6 @@ std::shared_ptr<StateDescriptor> Initialize(ParameterInput *pin, Opacity &opacit
// Equation of state model
pkg->AddParam<>("eos_d", eos.GetOnDevice());

// Opacity model
pkg->AddParam<>("opacity_d", opacity.GetOnDevice());

// Scattering model
pkg->AddParam<>("scattering_d", scattering.GetOnDevice());

// Swarm and swarm variables
Metadata swarm_metadata({Metadata::Provides, Metadata::None});
pkg->AddSwarm(photons_swarm_name, swarm_metadata);
Expand Down Expand Up @@ -265,6 +267,63 @@ std::shared_ptr<StateDescriptor> Initialize(ParameterInput *pin, Opacity &opacit
return pkg;
}

//----------------------------------------------------------------------------------------
//! \fn StateDescriptor Jaybenne::Initialize
//! \brief Initialize the Jaybenne physics package. This function defines and sets the
//! parameters associated with Jaybenne, and enrolls the data variables associated with
//! this physics package, specific to the gray frequency discretization.
std::shared_ptr<StateDescriptor> Initialize(ParameterInput *pin, MeanOpacity &mopacity,
MeanScattering &mscattering, EOS &eos) {
const auto units = mopacity.GetRuntimePhysicalConstants();

auto pkg = Initialize_impl(pin, eos, units);

pkg->AddParam<>("frequency_type", FrequencyType::multigroup);

// Opacity model
pkg->AddParam<>("mopacity_d", mopacity.GetOnDevice());

// Scattering model
pkg->AddParam<>("mscattering_d", mscattering.GetOnDevice());

return pkg;
}

//----------------------------------------------------------------------------------------
//! \fn StateDescriptor Jaybenne::Initialize
//! \brief Initialize the Jaybenne physics package. This function defines and sets the
//! parameters associated with Jaybenne, and enrolls the data variables associated with
//! this physics package, specific to the multigroup frequency discretization.
std::shared_ptr<StateDescriptor> Initialize(ParameterInput *pin, Opacity &opacity,
Scattering &scattering, EOS &eos) {
const auto units = opacity.GetRuntimePhysicalConstants();

auto pkg = Initialize_impl(pin, eos, units);

// Frequency discretization
auto time = units.time;
Real numin = pin->GetReal("jaybenne", "numin"); // in Hz
pkg->AddParam<>("numin", numin * time); // in code units
Real numax = pin->GetReal("jaybenne", "numax"); // in Hz
pkg->AddParam<>("numax", numax * time); // in code units
int n_nubins = pin->GetInteger("jaybenne", "n_nubins");
pkg->AddParam<>("n_nubins", n_nubins);

pkg->AddParam<>("frequency_type", FrequencyType::multigroup);

// Emission CDF
Metadata m_onecopy({Metadata::Cell, Metadata::OneCopy}, std::vector<int>({n_nubins}));
pkg->AddField(field::jaybenne::emission_cdf::name(), m_onecopy);

// Opacity model
pkg->AddParam<>("opacity_d", opacity.GetOnDevice());

// Scattering model
pkg->AddParam<>("scattering_d", scattering.GetOnDevice());

return pkg;
}

//----------------------------------------------------------------------------------------
//! \fn Real Jaybenne::EstimateTimestepMesh
//! \brief Compute radiation timestep
Expand Down Expand Up @@ -556,9 +615,17 @@ TaskStatus EvaluateRadiationEnergy(T *md) {
//! \brief Initialize radiation based on material temperature and either thermal or
//! zero initial radiation.
void InitializeRadiation(MeshBlockData<Real> *mbd, const bool is_thermal) {
auto &jb_pkg = mbd->GetBlockPointer()->packages.Get("jaybenne");
const auto &fd = jb_pkg->Param<FrequencyType>("frequency_type");

if (is_thermal) {
jaybenne::SourcePhotons<MeshBlockData<Real>, jaybenne::SourceType::thermal>(mbd, 0.0,
0.0);
if (fd == FrequencyType::gray) {
jaybenne::SourcePhotons<MeshBlockData<Real>, jaybenne::SourceType::thermal,
FrequencyType::gray>(mbd, 0.0, 0.0);
} else if (fd == FrequencyType::multigroup) {
jaybenne::SourcePhotons<MeshBlockData<Real>, jaybenne::SourceType::thermal,
FrequencyType::multigroup>(mbd, 0.0, 0.0);
}
}

// Call this so radiation field variables are properly initialized for outputs
Expand Down
7 changes: 6 additions & 1 deletion src/jaybenne/jaybenne.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,22 @@ namespace jaybenne {
std::shared_ptr<parthenon::StateDescriptor> Initialize(parthenon::ParameterInput *pin,
Opacity &opacity,
Scattering &scattering, EOS &eos);
std::shared_ptr<parthenon::StateDescriptor> Initialize(parthenon::ParameterInput *pin,
MeanOpacity &mopacity,
MeanScattering &mscattering,
EOS &eos);

// Model enums
enum class SourceStrategy { uniform, energy };
enum class SourceType { thermal, emission };
enum class FrequencyType { gray, multigroup };

// Tasks
TaskStatus TransportPhotons(MeshData<Real> *md, const Real t_start, const Real dt);
TaskStatus TransportPhotons_DDMC(MeshData<Real> *md, const Real t_start, const Real dt);
TaskStatus SampleDDMCBlockFace(MeshData<Real> *md);
TaskStatus CheckCompletion(MeshData<Real> *md, const Real t_end);
template <typename T, SourceType ST>
template <typename T, SourceType ST, FrequencyType FT>
TaskStatus SourcePhotons(T *md, const Real t_start, const Real dt);
TaskStatus DefragParticles(MeshBlock *pmb);
TaskStatus UpdateDerivedTransportFields(MeshData<Real> *md, const Real dt);
Expand Down
2 changes: 2 additions & 0 deletions src/jaybenne/jaybenne_config.hpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
using @JAYBENNE_EOS_TYPE@;
using @JAYBENNE_ABSORPTION_OPACITY_TYPE@;
using @JAYBENNE_SCATTERING_OPACITY_TYPE@;
using @JAYBENNE_ABSORPTION_MEAN_OPACITY_TYPE@;
using @JAYBENNE_SCATTERING_MEAN_OPACITY_TYPE@;

#include "@JAYBENNE_HOST_VARIABLE_HEADER@"

Expand Down
1 change: 1 addition & 0 deletions src/jaybenne/jaybenne_variables.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ JAYBENNE_FIELD_VARIABLE(field.jaybenne, fleck_factor);
JAYBENNE_FIELD_VARIABLE(field.jaybenne, ddmc_face_prob);
JAYBENNE_FIELD_VARIABLE(field.jaybenne, source_ew_per_cell);
JAYBENNE_FIELD_VARIABLE(field.jaybenne, source_num_per_cell);
JAYBENNE_FIELD_VARIABLE(field.jaybenne, emission_cdf);
JAYBENNE_FIELD_VARIABLE(field.jaybenne, energy_delta);
namespace host {
typedef HOST_DENSITY density;
Expand Down
93 changes: 82 additions & 11 deletions src/jaybenne/sourcing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ namespace jaybenne {
//! \fn TaskStatus SourcePhotons
//! \brief Create photons, either during initialization or during a timestep.
//! TODO(BRR) modify interface so we don't need t_start, dt for initialization
template <typename T, SourceType ST>
template <typename T, SourceType ST, FrequencyType FT>
TaskStatus SourcePhotons(T *md, const Real t_start, const Real dt) {
namespace fj = field::jaybenne;
namespace fjh = field::jaybenne::host;
Expand All @@ -31,8 +31,21 @@ TaskStatus SourcePhotons(T *md, const Real t_start, const Real dt) {
auto pm = md->GetParentPointer();
auto &resolved_pkgs = pm->resolved_packages;
auto &jb_pkg = pm->packages.Get("jaybenne");
const Real h = jb_pkg->template Param<Real>("planck_constant");
auto &eos = jb_pkg->template Param<EOS>("eos_d");
auto &opacity = jb_pkg->template Param<Opacity>("opacity_d");
const MeanOpacity *mopacity = nullptr;
const Opacity *opacity = nullptr;
int n_nubins = -1;
Real numin = -1.;
Real numax = -1.;
if constexpr (FT == FrequencyType::gray) {
mopacity = &(jb_pkg->template Param<MeanOpacity>("mopacity_d"));
} else if constexpr (FT == FrequencyType::multigroup) {
opacity = &(jb_pkg->template Param<Opacity>("opacity_d"));
n_nubins = jb_pkg->template Param<int>("n_nubins");
numin = jb_pkg->template Param<Real>("numin");
numax = jb_pkg->template Param<Real>("numax");
}
RyanWollaeger marked this conversation as resolved.
Show resolved Hide resolved
auto &do_emission = jb_pkg->template Param<bool>("do_emission");
auto &source_strategy = jb_pkg->template Param<SourceStrategy>("source_strategy");
PARTHENON_REQUIRE(source_strategy != SourceStrategy::energy,
Expand All @@ -51,7 +64,8 @@ TaskStatus SourcePhotons(T *md, const Real t_start, const Real dt) {
// Create pack
static auto desc =
MakePackDescriptor<fjh::density, fjh::sie, fj::fleck_factor, fj::source_ew_per_cell,
fj::source_num_per_cell, fj::energy_delta>(resolved_pkgs.get());
fj::source_num_per_cell, fj::emission_cdf, fj::energy_delta>(
resolved_pkgs.get());
auto vmesh = desc.GetPack(md);

// Indexing and dimensionality
Expand Down Expand Up @@ -87,12 +101,37 @@ TaskStatus SourcePhotons(T *md, const Real t_start, const Real dt) {
[[maybe_unused]] const Real &sbd = sb;
[[maybe_unused]] const Real &vvd = vv;
[[maybe_unused]] const Real &dtd = dt;
[[maybe_unused]] auto &opac = opacity;
[[maybe_unused]] auto *opac = opacity;
[[maybe_unused]] auto *mopac = mopacity;
[[maybe_unused]] const auto numind = numin;
[[maybe_unused]] const auto numaxd = numax;
[[maybe_unused]] const auto n_nubinsd = n_nubins;
Real erad = 0.0;
if constexpr (ST == SourceType::thermal) {
erad = (4.0 * sbd / vvd) * std::pow(temp, 4.0) * dv;
} else if constexpr (ST == SourceType::emission) {
const Real emis = opac.Emissivity(rho, temp);
Real emis = -1.;
if constexpr (FT == FrequencyType::gray) {
emis = opac->Emissivity(rho, temp);
} else if constexpr (FT == FrequencyType::multigroup) {
// Construct emission CDF
const Real dlnu = (std::log(numaxd) - std::log(numind)) / n_nubinsd;
vmesh(b, fj::emission_cdf(0), k, j, i) = opac->EmissivityPerNu(
rho, temp, std::exp(std::log(numind) + 0.5 * dlnu));
for (int n = 1; n < n_nubinsd; n++) {
const Real nu = std::exp(std::log(numind) + (n + 0.5) * dlnu);
vmesh(b, fj::emission_cdf(n), k, j, i) =
opac->EmissivityPerNu(rho, temp, nu) +
RyanWollaeger marked this conversation as resolved.
Show resolved Hide resolved
vmesh(b, fj::emission_cdf(n - 1), k, j, i);
}
for (int n = 0; n < n_nubinsd; n++) {
// Get total emissivity
emis += vmesh(b, fj::emission_cdf(n), k, j, i);
brryan marked this conversation as resolved.
Show resolved Hide resolved
// Normalize emission CDF
vmesh(b, fj::emission_cdf(n), k, j, i) /=
vmesh(b, fj::emission_cdf(n_nubins - 1), k, j, i);
RyanWollaeger marked this conversation as resolved.
Show resolved Hide resolved
}
}
erad = vmesh(b, fj::fleck_factor(), k, j, i) * emis * dv * dtd;
}
// Set source_num_per_cell
Expand Down Expand Up @@ -156,6 +195,10 @@ TaskStatus SourcePhotons(T *md, const Real t_start, const Real dt) {
auto rng_gen = rng_pool.get_state();
[[maybe_unused]] const Real &dtd = dt;
[[maybe_unused]] const Real &t_startd = t_start;
[[maybe_unused]] const Real hd = h;
[[maybe_unused]] const Real numaxd = numax;
[[maybe_unused]] const Real numind = numin;
[[maybe_unused]] const int n_nubinsd = n_nubins;

// Starting index and length of particles in this cell
const int &pstart_idx = prefix_sum(b, cell_idx_1d);
Expand Down Expand Up @@ -189,8 +232,23 @@ TaskStatus SourcePhotons(T *md, const Real t_start, const Real dt) {
const Real &rho = vmesh(b, fjh::density(), k, j, i);
const Real &sie = vmesh(b, fjh::sie(), k, j, i);
const Real temp = eos.TemperatureFromDensityInternalEnergy(rho, sie);
ppack_r(b, ph::energy(), n) = sample_Planck_energy(rng_gen, sb, temp);
ppack_r(b, ph::weight(), n) = vmesh(b, fj::source_ew_per_cell(), k, j, i);
if constexpr (FT == FrequencyType::gray) {
ppack_r(b, ph::energy(), n) = sample_Planck_energy(rng_gen, sb, temp);
} else if constexpr (FT == FrequencyType::multigroup) {
// Sample energy from CDF
const Real rand = rng_gen.drand();
int n;
for (n = 0; n < n_nubinsd; n++) {
if (vmesh(b, fj::emission_cdf(n), k, j, i) >= rand) {
break;
}
}
const Real dlnu = (std::log(numaxd) - std::log(numind)) / n_nubinsd;
const Real nu = std::exp(std::log(numind) + (n + 0.5) * dlnu);
ppack_r(b, ph::energy(), n) = hd * nu;
}
ppack_r(b, ph::weight(), n) =
vmesh(b, fj::source_ew_per_cell(), k, j, i) / ppack_r(b, ph::energy(), n);

if constexpr (ST == SourceType::emission) {
dejbn -= ppack_r(b, ph::weight(), n);
Expand All @@ -212,9 +270,22 @@ TaskStatus SourcePhotons(T *md, const Real t_start, const Real dt) {
typedef MeshBlockData<Real> BD;
typedef MeshData<Real> D;
typedef SourceType ST;
template TaskStatus SourcePhotons<BD, ST::thermal>(BD *md, const Real t0, const Real dt);
template TaskStatus SourcePhotons<BD, ST::emission>(BD *md, const Real t0, const Real dt);
template TaskStatus SourcePhotons<D, ST::thermal>(D *md, const Real t0, const Real dt);
template TaskStatus SourcePhotons<D, ST::emission>(D *md, const Real t0, const Real dt);
typedef FrequencyType FT;
template TaskStatus SourcePhotons<BD, ST::thermal, FT::gray>(BD *md, const Real t0,
const Real dt);
template TaskStatus SourcePhotons<BD, ST::emission, FT::gray>(BD *md, const Real t0,
const Real dt);
template TaskStatus SourcePhotons<D, ST::thermal, FT::gray>(D *md, const Real t0,
const Real dt);
template TaskStatus SourcePhotons<D, ST::emission, FT::gray>(D *md, const Real t0,
const Real dt);
template TaskStatus SourcePhotons<BD, ST::thermal, FT::multigroup>(BD *md, const Real t0,
const Real dt);
template TaskStatus SourcePhotons<BD, ST::emission, FT::multigroup>(BD *md, const Real t0,
const Real dt);
template TaskStatus SourcePhotons<D, ST::thermal, FT::multigroup>(D *md, const Real t0,
const Real dt);
template TaskStatus SourcePhotons<D, ST::emission, FT::multigroup>(D *md, const Real t0,
const Real dt);

} // namespace jaybenne
6 changes: 6 additions & 0 deletions src/mcblock/opacity.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#define MCBLOCK_OPACITY_HPP_

// Singularity-opac includes
#include <singularity-opac/photons/mean_opacity_photons.hpp>
#include <singularity-opac/photons/mean_s_opacity_photons.hpp>
#include <singularity-opac/photons/opac_photons.hpp>
#include <singularity-opac/photons/s_opac_photons.hpp>

Expand All @@ -24,11 +26,15 @@ using Opacity = singularity::photons::impl::Variant<
singularity::photons::NonCGSUnits<singularity::photons::Gray>,
singularity::photons::NonCGSUnits<singularity::photons::EPBremss>>;

using MeanOpacity = singularity::photons::MeanOpacity;

// Reduced scattering variant just for jaybenne
using Scattering = singularity::photons::impl::S_Variant<
singularity::photons::NonCGSUnitsS<singularity::photons::GrayS>,
singularity::photons::NonCGSUnitsS<singularity::photons::ThomsonS>>;

using MeanScattering = singularity::photons::MeanSOpacity;

} // namespace mcblock

#endif // MCBLOCK_OPACITY_HPP_