Skip to content
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
6d52433
Initial plan
Copilot Dec 22, 2025
ba47578
Add 12 hydrometeor variable recipes with diagnostic cloud scheme
Copilot Dec 22, 2025
0005b8d
Rename effective radius variables to match ESM standard names
Copilot Dec 22, 2025
37133bc
Apply code review feedback: update copyright, add Parameters classes,…
Copilot Dec 22, 2025
75aae0e
Use air_pressure_thickness for more accurate mass content calculations
Copilot Dec 22, 2025
69fff83
Update recipes from Smith 1990 to IFS/ERA5 parameterizations
Copilot Dec 22, 2025
2e51e2f
Enforce 100-character line length limit across all recipe files
Copilot Dec 22, 2025
58f505d
Update documentation style: move scientific references to headers, si…
Copilot Dec 23, 2025
335a328
Update documentation to clarify simplified diagnostic approximations
Copilot Dec 23, 2025
880dd09
Refine documentation format: add Martin et al. citation to relationsh…
Copilot Dec 23, 2025
f4ed6c9
Fix variable naming and remove unused code in precipitation recipes
Copilot Dec 23, 2025
6b086cf
Add TotalRelativeHumidity_B recipe using water_vapor_mixing_ratio_wrt…
Copilot Dec 23, 2025
ccc7338
Replace TotalRelativeHumidity_B with RelativeHumidity_B recipe
Copilot Dec 23, 2025
8ce5d17
Add TL/AD implementation for RelativeHumidity_B recipe
Copilot Dec 23, 2025
13da03c
Add SaturationVaporPressure_B and SaturationSpecificHumidity_B with T…
Copilot Dec 23, 2025
765710b
Clean up documentation and simplify variable names per review feedback
Copilot Dec 23, 2025
a7510c2
Replace Wexler (1976) with Murphy & Koop (2005) for saturation vapor …
Copilot Dec 23, 2025
b711fe8
Update variable naming and Parameters class per review feedback
Copilot Dec 23, 2025
54659c6
Extend SaturationVaporPressure_B to handle saturation over ice
Copilot Dec 23, 2025
1ca9701
Update recipes for separation of concerns and use model epsilon
Copilot Dec 23, 2025
915b8dc
Fix variable naming and method signatures per review feedback
Copilot Dec 23, 2025
4160c19
Fix RelativeHumidity_B method signatures to use void instead of bool
Copilot Dec 23, 2025
ec32566
Fix SaturationSpecificHumidity_B and SaturationVaporPressure_B per re…
Copilot Dec 23, 2025
3faf484
Remove trailing whitespace from humidity recipe files
Copilot Dec 23, 2025
9be0399
Fix variable name in SaturationSpecificHumidity_B trajectoryVars and …
Copilot Dec 23, 2025
8ac9492
Fix surface pressure array indexing in all hydrometeor mass content r…
Copilot Dec 23, 2025
1f76595
Change hasTLAD() to inline format and remove standalone implementations
Copilot Dec 23, 2025
5bb88dc
adjusting whitespaces
fabiolrdiniz Dec 23, 2025
793584a
adding a few more recipes
fabiolrdiniz Dec 24, 2025
efcce9f
missing files
fabiolrdiniz Dec 24, 2025
302edae
Align newly added recipes with coding standards (Part 1)
Copilot Dec 24, 2025
7301e6d
Standardize formatting across all newly added recipes (Part 3)
Copilot Dec 24, 2025
2edcf50
Remove extra comments from variable declarations in SaturationSpecifi…
Copilot Dec 24, 2025
a47a534
Standardize adjoint zeroing comments across all recipes
Copilot Dec 24, 2025
5367bd3
Fix missing \brief tags in documentation comments
Copilot Dec 24, 2025
d4ace25
Comprehensive code standardization across all recipes (Part 1)
Copilot Dec 24, 2025
58fa3b4
Comprehensive code standardization across all recipes (Part 2)
Copilot Dec 24, 2025
7380b4b
Fix indentation to 2-space standard in all .cc files
Copilot Dec 25, 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
24 changes: 24 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,30 @@ vader/recipes/TotalWaterMixingRatioWrtWetAir.h
vader/recipes/TotalWaterMixingRatioWrtWetAir_A.cc
vader/recipes/EastwardWindAt10m_A.cc
vader/recipes/EastwardWindAt10m.h
vader/recipes/EffectiveRadiusOfCloudIceParticle.h
vader/recipes/EffectiveRadiusOfCloudIceParticle_A.cc
vader/recipes/EffectiveRadiusOfCloudLiquidWaterParticle.h
vader/recipes/EffectiveRadiusOfCloudLiquidWaterParticle_A.cc
vader/recipes/EffectiveRadiusOfGraupelParticle.h
vader/recipes/EffectiveRadiusOfGraupelParticle_A.cc
vader/recipes/EffectiveRadiusOfHailParticle.h
vader/recipes/EffectiveRadiusOfHailParticle_A.cc
vader/recipes/EffectiveRadiusOfRainParticle.h
vader/recipes/EffectiveRadiusOfRainParticle_A.cc
vader/recipes/EffectiveRadiusOfSnowParticle.h
vader/recipes/EffectiveRadiusOfSnowParticle_A.cc
vader/recipes/MassContentOfCloudIceInAtmosphereLayer.h
vader/recipes/MassContentOfCloudIceInAtmosphereLayer_A.cc
vader/recipes/MassContentOfCloudLiquidWaterInAtmosphereLayer.h
vader/recipes/MassContentOfCloudLiquidWaterInAtmosphereLayer_A.cc
vader/recipes/MassContentOfGraupelInAtmosphereLayer.h
vader/recipes/MassContentOfGraupelInAtmosphereLayer_A.cc
vader/recipes/MassContentOfHailInAtmosphereLayer.h
vader/recipes/MassContentOfHailInAtmosphereLayer_A.cc
vader/recipes/MassContentOfRainInAtmosphereLayer.h
vader/recipes/MassContentOfRainInAtmosphereLayer_A.cc
vader/recipes/MassContentOfSnowInAtmosphereLayer.h
vader/recipes/MassContentOfSnowInAtmosphereLayer_A.cc
vader/recipes/VirtualPotentialTemperature_A.cc
vader/recipes/VirtualPotentialTemperature_B.cc
vader/recipes/VirtualPotentialTemperature.h
Expand Down
38 changes: 37 additions & 1 deletion src/vader/DefaultCookbook.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,19 @@
#include "recipes/DryAirDensity.h"
#include "recipes/DryAirDensityLevelsMinusOne.h"
#include "recipes/EastwardWindAt10m.h"
#include "recipes/EffectiveRadiusOfCloudIceParticle.h"
#include "recipes/EffectiveRadiusOfCloudLiquidWaterParticle.h"
#include "recipes/EffectiveRadiusOfGraupelParticle.h"
#include "recipes/EffectiveRadiusOfHailParticle.h"
#include "recipes/EffectiveRadiusOfRainParticle.h"
#include "recipes/EffectiveRadiusOfSnowParticle.h"
#include "recipes/HydrostaticExnerLevels.h"
#include "recipes/MassContentOfCloudIceInAtmosphereLayer.h"
#include "recipes/MassContentOfCloudLiquidWaterInAtmosphereLayer.h"
#include "recipes/MassContentOfGraupelInAtmosphereLayer.h"
#include "recipes/MassContentOfHailInAtmosphereLayer.h"
#include "recipes/MassContentOfRainInAtmosphereLayer.h"
#include "recipes/MassContentOfSnowInAtmosphereLayer.h"
#include "recipes/NorthwardWindAt10m.h"
#include "recipes/ParticulateMatter2p5.h"
#include "recipes/RainMixingRatio.h"
Expand Down Expand Up @@ -80,7 +92,31 @@ const cookbookConfigType Vader::defaultCookbookDefinition = {
{vwind_at_10m_A::Name}},
{oops::Variable{"mass_density_of_particulate_matter_2p5_in_air"},
{ParticulateMatter2p5_A::Name,
ParticulateMatter2p5_B::Name}}
ParticulateMatter2p5_B::Name}},
{oops::Variable{"mass_content_of_cloud_liquid_water_in_atmosphere_layer"},
{MassContentOfCloudLiquidWaterInAtmosphereLayer_A::Name}},
{oops::Variable{"mass_content_of_cloud_ice_in_atmosphere_layer"},
{MassContentOfCloudIceInAtmosphereLayer_A::Name}},
{oops::Variable{"mass_content_of_rain_in_atmosphere_layer"},
{MassContentOfRainInAtmosphereLayer_A::Name}},
{oops::Variable{"mass_content_of_snow_in_atmosphere_layer"},
{MassContentOfSnowInAtmosphereLayer_A::Name}},
{oops::Variable{"mass_content_of_graupel_in_atmosphere_layer"},
{MassContentOfGraupelInAtmosphereLayer_A::Name}},
{oops::Variable{"mass_content_of_hail_in_atmosphere_layer"},
{MassContentOfHailInAtmosphereLayer_A::Name}},
{oops::Variable{"effective_radius_of_cloud_liquid_water_particle"},
{EffectiveRadiusOfCloudLiquidWaterParticle_A::Name}},
{oops::Variable{"effective_radius_of_cloud_ice_particle"},
{EffectiveRadiusOfCloudIceParticle_A::Name}},
{oops::Variable{"effective_radius_of_rain_particle"},
{EffectiveRadiusOfRainParticle_A::Name}},
{oops::Variable{"effective_radius_of_snow_particle"},
{EffectiveRadiusOfSnowParticle_A::Name}},
{oops::Variable{"effective_radius_of_graupel_particle"},
{EffectiveRadiusOfGraupelParticle_A::Name}},
{oops::Variable{"effective_radius_of_hail_particle"},
{EffectiveRadiusOfHailParticle_A::Name}}
};

} // namespace vader
51 changes: 51 additions & 0 deletions src/vader/recipes/EffectiveRadiusOfCloudIceParticle.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* (C) Crown Copyright 2025 Met Office.
*
* This software is licensed under the terms of the Apache Licence Version 2.0
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
*/

#pragma once

#include <string>
#include <vector>

#include "atlas/field/FieldSet.h"
#include "atlas/functionspace/FunctionSpace.h"
#include "vader/RecipeBase.h"

namespace vader
{

// -------------------------------------------------------------------------------------------------

/*! \brief The class 'EffectiveRadiusOfCloudIceParticle_A' defines a recipe for
* effective radius of ice particle
*
* \details This instantiation of RecipeBase produces effective radius
* using temperature-dependent relationship.
* Inputs: air_temperature
* Output units: m
*/
class EffectiveRadiusOfCloudIceParticle_A : public RecipeBase
{
public:
static const char Name[];

typedef EmptyRecipeParameters Parameters_;

EffectiveRadiusOfCloudIceParticle_A(const Parameters_ &,
const VaderConfigVars &);

std::string name() const override;
oops::Variable product() const override;
oops::Variables ingredients() const override;
size_t productLevels(const atlas::FieldSet &) const override;
atlas::FunctionSpace productFunctionSpace(const atlas::FieldSet &) const override;

void executeNL(atlas::FieldSet &) override;
};

// -------------------------------------------------------------------------------------------------

} // namespace vader
106 changes: 106 additions & 0 deletions src/vader/recipes/EffectiveRadiusOfCloudIceParticle_A.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* (C) Crown Copyright 2025 Met Office.
*
* This software is licensed under the terms of the Apache Licence Version 2.0
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
*/

#include <cmath>
#include <iostream>
#include <vector>

#include "atlas/array.h"
#include "atlas/field/Field.h"
#include "oops/util/Logger.h"
#include "vader/recipes/EffectiveRadiusOfCloudIceParticle.h"

namespace vader {

// -------------------------------------------------------------------------------------------------
// Static attribute initialization
const char EffectiveRadiusOfCloudIceParticle_A::Name[] =
"EffectiveRadiusOfCloudIceParticle_A";

// Register the maker
static RecipeMaker<EffectiveRadiusOfCloudIceParticle_A>
makerEffectiveRadiusOfCloudIceParticle_A_(
EffectiveRadiusOfCloudIceParticle_A::Name);

// -------------------------------------------------------------------------------------------------

EffectiveRadiusOfCloudIceParticle_A::
EffectiveRadiusOfCloudIceParticle_A(
const Parameters_ & params,
const VaderConfigVars & configVariables) {
oops::Log::trace() << "EffectiveRadiusOfCloudIceParticle_A::"
<< "EffectiveRadiusOfCloudIceParticle_A" << std::endl;
}

std::string EffectiveRadiusOfCloudIceParticle_A::name() const {
return EffectiveRadiusOfCloudIceParticle_A::Name;
}

oops::Variable EffectiveRadiusOfCloudIceParticle_A::product() const {
return oops::Variable{"effective_radius_of_cloud_ice_particle"};
}

oops::Variables EffectiveRadiusOfCloudIceParticle_A::ingredients() const {
return oops::Variables{std::vector<std::string>{"air_temperature"}};
}

size_t EffectiveRadiusOfCloudIceParticle_A::productLevels(
const atlas::FieldSet & afieldset) const {
return afieldset.field("air_temperature").shape(1);
}

atlas::FunctionSpace EffectiveRadiusOfCloudIceParticle_A::productFunctionSpace(
const atlas::FieldSet & afieldset) const {
return afieldset.field("air_temperature").functionspace();
}

void EffectiveRadiusOfCloudIceParticle_A::executeNL(
atlas::FieldSet & afieldset) {
oops::Log::trace() << "EffectiveRadiusOfCloudIceParticle_A::"
<< "executeNL starting" << std::endl;

// Get input field
auto temp = atlas::array::make_view<double, 2>(afieldset.field("air_temperature"));

// Create output field
auto reff_field = afieldset.field(
"effective_radius_of_cloud_ice_particle");
auto reff = atlas::array::make_view<double, 2>(reff_field);

const size_t npoints = temp.shape(0);
const size_t nlevels = temp.shape(1);

// Temperature-dependent effective radius for ice particles
// Typical range: 20-100 micrometers
// Colder temperatures -> smaller crystals
const double T_freeze = 273.15; // K
const double T_cold = 233.15; // -40C
const double r_min = 20.0e-6; // minimum radius (m)
const double r_max = 100.0e-6; // maximum radius (m)

for (size_t jn = 0; jn < npoints; ++jn) {
for (size_t jl = 0; jl < nlevels; ++jl) {
const double T = temp(jn, jl);

if (T < T_freeze) {
// Warmer ice clouds have larger particles due to aggregation
const double temp_factor = (T - T_cold) / (T_freeze - T_cold);
reff(jn, jl) = r_min + (r_max - r_min) * std::max(0.0, std::min(1.0, temp_factor));
} else {
// Above freezing, use minimum value
reff(jn, jl) = r_min;
}
}
}

oops::Log::trace() << "EffectiveRadiusOfCloudIceParticle_A::"
<< "executeNL done" << std::endl;
}

// -------------------------------------------------------------------------------------------------

} // namespace vader
51 changes: 51 additions & 0 deletions src/vader/recipes/EffectiveRadiusOfCloudLiquidWaterParticle.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* (C) Crown Copyright 2025 Met Office.
*
* This software is licensed under the terms of the Apache Licence Version 2.0
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
*/

#pragma once

#include <string>
#include <vector>

#include "atlas/field/FieldSet.h"
#include "atlas/functionspace/FunctionSpace.h"
#include "vader/RecipeBase.h"

namespace vader
{

// -------------------------------------------------------------------------------------------------

/*! \brief The class 'EffectiveRadiusOfCloudLiquidWaterParticle_A' defines a recipe for
* effective radius of cloud liquid water particle
*
* \details This instantiation of RecipeBase produces effective radius
* using temperature-dependent relationship (Martin et al. 1994).
* Inputs: air_temperature
* Output units: m
*/
class EffectiveRadiusOfCloudLiquidWaterParticle_A : public RecipeBase
{
public:
static const char Name[];

typedef EmptyRecipeParameters Parameters_;

EffectiveRadiusOfCloudLiquidWaterParticle_A(const Parameters_ &,
const VaderConfigVars &);

std::string name() const override;
oops::Variable product() const override;
oops::Variables ingredients() const override;
size_t productLevels(const atlas::FieldSet &) const override;
atlas::FunctionSpace productFunctionSpace(const atlas::FieldSet &) const override;

void executeNL(atlas::FieldSet &) override;
};

// -------------------------------------------------------------------------------------------------

} // namespace vader
Loading