diff --git a/data-raw/input_params.csv b/data-raw/input_params.csv index 798c5e02e..26bfd6354 100644 --- a/data-raw/input_params.csv +++ b/data-raw/input_params.csv @@ -100,10 +100,10 @@ forcing,rho_so2,n,n,y,-7.24E-06,W yr m-2 S Gg-1,IPCC AR6 radiative efficiency SO forcing,rho_nh3,n,n,y,-0.00208,W yr m-2 NH3 Tg-1,IPCC AR6 radiative efficiency NH3 (7.SM.1.3.1 of IPCC AR6) forcing,RF_misc,n,n,n,"""(csv)""",,Miscellaneous radiative forcings default set to 0 forcing,RF_misc,n,n,y,0,,"Miscellaneous radiative forcings default set to 0, or read in from a input table, may be used to read in additional forcings not modeled by Hector (i.e. solar, bc on snow , contrails from)" +forcing,aero_scalar,n,n,y,1,(unitless),scaling factor for aerosol forcing +forcing,vol_scalar,n,n,y,1,(unitless),scaling factor for volcanic forcing temperature,S,n,n,y,3,degC,equilibrium climate sensitivity for 2xCO2 temperature,diff,n,n,y,2.3,cm2 s-1,ocean heat diffusivity -temperature,alpha,n,n,y,1,(unitless),scaling factor for aerosol forcing -temperature,volscl,n,n,y,1,(unitless),scaling factor for volcanic forcing temperature,qco2,n,n,y,3.75,,CO2 RF (7.3.2 of IPCC AR6) temperature,tas_constrain,n,y,n,"""(csv)""",,"Optional global temperature constraint; If supplied, the model will use these data, ignoring what it calculates" bc,BC_emissions,n,y,y,"""(csv)""",, diff --git a/data/inputstable.rda b/data/inputstable.rda index 5c844f667..8d51f4d55 100644 Binary files a/data/inputstable.rda and b/data/inputstable.rda differ diff --git a/data/unitstable.rda b/data/unitstable.rda index 67ee825dd..9039257a8 100644 Binary files a/data/unitstable.rda and b/data/unitstable.rda differ diff --git a/inst/include/component_data.hpp b/inst/include/component_data.hpp index afa24bc02..de2a9efc4 100644 --- a/inst/include/component_data.hpp +++ b/inst/include/component_data.hpp @@ -65,6 +65,8 @@ #define D_RHO_OC "rho_oc" // BC radiative efficiency #define D_RHO_SO2 "rho_so2" // SO2 radiative efficiency #define D_RHO_NH3 "rho_nh3" // NH3 radiative efficiency +#define D_AERO_SCALE "aero_scalar" +#define D_VOLCANIC_SCALE "vol_scalar" // halocarbon components #define D_RF_CF4 D_RF_PREFIX CF4_COMPONENT_BASE @@ -397,8 +399,6 @@ #define D_GMST "gmst" #define D_LO_WARMING_RATIO "lo_warming_ratio" #define D_DIFFUSIVITY "diff" -#define D_AERO_SCALE "alpha" -#define D_VOLCANIC_SCALE "volscl" #define D_FLUX_MIXED "heatflux_mixed" #define D_FLUX_INTERIOR "heatflux_interior" #define D_HEAT_FLUX "heatflux" diff --git a/inst/include/forcing_component.hpp b/inst/include/forcing_component.hpp index be920c26d..ea21395c9 100644 --- a/inst/include/forcing_component.hpp +++ b/inst/include/forcing_component.hpp @@ -118,7 +118,10 @@ class ForcingComponent : public IModelComponent { unitval rho_nh3; // (W yr m–2 Tg–1) IPCC AR6 radiative efficiency SO2 7.SM.1.3.1 - // Aerosol parameters for aerosol-cloud interactions (RFaci) see equation + // Aerosol parameters + unitval alpha; // aerosol forcing factor, unitless + unitval volscl; // volcanic forcing scaling factor, unitless + // Parameters for aerosol-cloud interactions (RFaci) see equation // Equation 7.SM.1.2 of IPCC AR6 double const aci_beta = 2.279759; // Dorheim et al. 2024 double const s_BCOC = 111.05064063; // (Tg C yr-1) IPCC AR6 7.SM.1.3.1 diff --git a/inst/include/temperature_component.hpp b/inst/include/temperature_component.hpp index eeba1f1f2..df6d29946 100644 --- a/inst/include/temperature_component.hpp +++ b/inst/include/temperature_component.hpp @@ -145,8 +145,6 @@ class TemperatureComponent : public IModelComponent { // Model parameters unitval S; //!< climate sensitivity for 2xCO2, deg C unitval diff; //!< ocean heat diffusivity, cm2/s - unitval alpha; //!< aerosol forcing factor, unitless - unitval volscl; //!< volcanic forcing scaling factor, unitless // Model outputs unitval tas; //!< global average air temperature anomaly, deg C diff --git a/inst/input/hector_ssp119.ini b/inst/input/hector_ssp119.ini index 5f28e33a1..2702b101a 100644 --- a/inst/input/hector_ssp119.ini +++ b/inst/input/hector_ssp119.ini @@ -162,6 +162,8 @@ baseyear=1750 ; when to start reporting; by definition, all F=0 in this year ; Optional radiative forcing constraint ;RF_tot_constrain=csv:tables/CONSTRAINT.csv +aero_scalar=1.0 ; (unitless) uncertainty scaling factor for volcanic forcing +vol_scalar=1.0 ; (unitless) uncertainty scaling factor for volcanic forcing delta_co2=0.05 ; (unitless) forcing tropospheric adjustments for CO2 (7.3.2.1 of IPCC AR6) delta_ch4=-.14 ; (unitless) forcing tropospheric adjustments for CH4 (7.3.2.2 of IPCC AR6) delta_n2o=0.07 ; (unitless) forcing tropospheric adjustments for N2O (7.3.2.3 of IPCC AR6) @@ -179,8 +181,6 @@ RF_misc[1750]=0 [temperature] S=3.0 ; equilibrium climate sensitivity for 2xCO2 degC (A.4.4 of IPCC AR6) diff=2.38 ; ocean heat diffusivity, cm2/s calibrated to historical observations Dorheim et al. 2024 for details -alpha=1.0 ; uncertainty scaling factor for aerosol forcing -volscl=1.0 ; uncertainty scaling factor for volcanic forcing qco2=3.75 ; 2×CO2 RF (7.3.2 of IPCC AR6) ; Optional global temperature constraint diff --git a/inst/input/hector_ssp126.ini b/inst/input/hector_ssp126.ini index 5482e89e9..07fab5e48 100644 --- a/inst/input/hector_ssp126.ini +++ b/inst/input/hector_ssp126.ini @@ -162,6 +162,8 @@ baseyear=1750 ; when to start reporting; by definition, all F=0 in this year ; Optional radiative forcing constraint ;RF_tot_constrain=csv:tables/CONSTRAINT.csv +aero_scalar=1.0 ; uncertainty scaling factor for aerosol forcing +vol_scalar=1.0 ; uncertainty scaling factor for volcanic forcing delta_co2=0.05 ; (unitless) forcing tropospheric adjustments for CO2 (7.3.2.1 of IPCC AR6) delta_ch4=-.14 ; (unitless) forcing tropospheric adjustments for CH4 (7.3.2.2 of IPCC AR6) delta_n2o=0.07 ; (unitless) forcing tropospheric adjustments for N2O (7.3.2.3 of IPCC AR6) @@ -179,8 +181,6 @@ RF_misc[1750]=0 [temperature] S=3.0 ; equilibrium climate sensitivity for 2xCO2 degC (A.4.4 of IPCC AR6) diff=2.38 ; ocean heat diffusivity, cm2/s calibrated to historical observations Dorheim et al. 2024 for details -alpha=1.0 ; uncertainty scaling factor for aerosol forcing -volscl=1.0 ; uncertainty scaling factor for volcanic forcing qco2=3.75 ; 2×CO2 RF (7.3.2 of IPCC AR6) ; Optional global temperature constraint diff --git a/inst/input/hector_ssp245.ini b/inst/input/hector_ssp245.ini index d1eaf2b37..d0812152d 100644 --- a/inst/input/hector_ssp245.ini +++ b/inst/input/hector_ssp245.ini @@ -162,6 +162,8 @@ baseyear=1750 ; when to start reporting; by definition, all F=0 in this year ; Optional radiative forcing constraint ;RF_tot_constrain=csv:tables/CONSTRAINT.csv +aero_scalar=1.0 ; (unitless) uncertainty scaling factor for volcanic forcing +vol_scalar=1.0 ; (unitless) uncertainty scaling factor for volcanic forcing delta_co2=0.05 ; (unitless) forcing tropospheric adjustments for CO2 (7.3.2.1 of IPCC AR6) delta_ch4=-.14 ; (unitless) forcing tropospheric adjustments for CH4 (7.3.2.2 of IPCC AR6) delta_n2o=0.07 ; (unitless) forcing tropospheric adjustments for N2O (7.3.2.3 of IPCC AR6) @@ -179,8 +181,6 @@ RF_misc[1750]=0 [temperature] S=3.0 ; equilibrium climate sensitivity for 2xCO2 degC (A.4.4 of IPCC AR6) diff=2.38 ; ocean heat diffusivity, cm2/s calibrated to historical observations Dorheim et al. 2024 for details -alpha=1.0 ; uncertainty scaling factor for aerosol forcing -volscl=1.0 ; uncertainty scaling factor for volcanic forcing qco2=3.75 ; 2×CO2 RF (7.3.2 of IPCC AR6) ; Optional global temperature constraint diff --git a/inst/input/hector_ssp370.ini b/inst/input/hector_ssp370.ini index 58a13243b..c452bf24e 100644 --- a/inst/input/hector_ssp370.ini +++ b/inst/input/hector_ssp370.ini @@ -162,6 +162,8 @@ baseyear=1750 ; when to start reporting; by definition, all F=0 in this year ; Optional radiative forcing constraint ;RF_tot_constrain=csv:tables/CONSTRAINT.csv +aero_scalar=1.0 ; uncertainty scaling factor for aerosol forcing +vol_scalar=1.0 ; uncertainty scaling factor for volcanic forcing delta_co2=0.05 ; (unitless) forcing tropospheric adjustments for CO2 (7.3.2.1 of IPCC AR6) delta_ch4=-.14 ; (unitless) forcing tropospheric adjustments for CH4 (7.3.2.2 of IPCC AR6) delta_n2o=0.07 ; (unitless) forcing tropospheric adjustments for N2O (7.3.2.3 of IPCC AR6) @@ -179,8 +181,6 @@ RF_misc[1750]=0 [temperature] S=3.0 ; equilibrium climate sensitivity for 2xCO2 degC (A.4.4 of IPCC AR6) diff=2.38 ; ocean heat diffusivity, cm2/s calibrated to historical observations Dorheim et al. 2024 for details -alpha=1.0 ; uncertainty scaling factor for aerosol forcing -volscl=1.0 ; uncertainty scaling factor for volcanic forcing qco2=3.75 ; 2×CO2 RF (7.3.2 of IPCC AR6) ; Optional global temperature constraint diff --git a/inst/input/hector_ssp434.ini b/inst/input/hector_ssp434.ini index 217ab12ad..e0c47e36a 100644 --- a/inst/input/hector_ssp434.ini +++ b/inst/input/hector_ssp434.ini @@ -162,6 +162,8 @@ baseyear=1750 ; when to start reporting; by definition, all F=0 in this year ; Optional radiative forcing constraint ;RF_tot_constrain=csv:tables/CONSTRAINT.csv +aero_scalar=1.0 ; uncertainty scaling factor for aerosol forcing +vol_scalar=1.0 ; uncertainty scaling factor for volcanic forcing delta_co2=0.05 ; (unitless) forcing tropospheric adjustments for CO2 (7.3.2.1 of IPCC AR6) delta_ch4=-.14 ; (unitless) forcing tropospheric adjustments for CH4 (7.3.2.2 of IPCC AR6) delta_n2o=0.07 ; (unitless) forcing tropospheric adjustments for N2O (7.3.2.3 of IPCC AR6) @@ -179,8 +181,6 @@ RF_misc[1750]=0 [temperature] S=3.0 ; equilibrium climate sensitivity for 2xCO2 degC (A.4.4 of IPCC AR6) diff=2.38 ; ocean heat diffusivity, cm2/s calibrated to historical observations Dorheim et al. 2024 for details -alpha=1.0 ; uncertainty scaling factor for aerosol forcing -volscl=1.0 ; uncertainty scaling factor for volcanic forcing qco2=3.75 ; 2×CO2 RF (7.3.2 of IPCC AR6) ; Optional global temperature constraint diff --git a/inst/input/hector_ssp460.ini b/inst/input/hector_ssp460.ini index 50f4e2c7d..bdc8de847 100644 --- a/inst/input/hector_ssp460.ini +++ b/inst/input/hector_ssp460.ini @@ -162,6 +162,8 @@ baseyear=1750 ; when to start reporting; by definition, all F=0 in this year ; Optional radiative forcing constraint ;RF_tot_constrain=csv:tables/CONSTRAINT.csv +aero_scalar=1.0 ; uncertainty scaling factor for aerosol forcing +vol_scalar=1.0 ; uncertainty scaling factor for volcanic forcing delta_co2=0.05 ; (unitless) forcing tropospheric adjustments for CO2 (7.3.2.1 of IPCC AR6) delta_ch4=-.14 ; (unitless) forcing tropospheric adjustments for CH4 (7.3.2.2 of IPCC AR6) delta_n2o=0.07 ; (unitless) forcing tropospheric adjustments for N2O (7.3.2.3 of IPCC AR6) @@ -179,8 +181,6 @@ RF_misc[1750]=0 [temperature] S=3.0 ; equilibrium climate sensitivity for 2xCO2 degC (A.4.4 of IPCC AR6) diff=2.38 ; ocean heat diffusivity, cm2/s calibrated to historical observations Dorheim et al. 2024 for details -alpha=1.0 ; uncertainty scaling factor for aerosol forcing -volscl=1.0 ; uncertainty scaling factor for volcanic forcing qco2=3.75 ; 2×CO2 RF (7.3.2 of IPCC AR6) ; Optional global temperature constraint diff --git a/inst/input/hector_ssp534-over.ini b/inst/input/hector_ssp534-over.ini index 8c97b0d23..2729f1738 100644 --- a/inst/input/hector_ssp534-over.ini +++ b/inst/input/hector_ssp534-over.ini @@ -162,6 +162,8 @@ baseyear=1750 ; when to start reporting; by definition, all F=0 in this year ; Optional radiative forcing constraint ;RF_tot_constrain=csv:tables/CONSTRAINT.csv +aero_scalar=1.0 ; uncertainty scaling factor for aerosol forcing +vol_scalar=1.0 ; uncertainty scaling factor for volcanic forcing delta_co2=0.05 ; (unitless) forcing tropospheric adjustments for CO2 (7.3.2.1 of IPCC AR6) delta_ch4=-.14 ; (unitless) forcing tropospheric adjustments for CH4 (7.3.2.2 of IPCC AR6) delta_n2o=0.07 ; (unitless) forcing tropospheric adjustments for N2O (7.3.2.3 of IPCC AR6) @@ -179,8 +181,6 @@ RF_misc[1750]=0 [temperature] S=3.0 ; equilibrium climate sensitivity for 2xCO2 degC (A.4.4 of IPCC AR6) diff=2.38 ; ocean heat diffusivity, cm2/s calibrated to historical observations Dorheim et al. 2024 for details -alpha=1.0 ; uncertainty scaling factor for aerosol forcing -volscl=1.0 ; uncertainty scaling factor for volcanic forcing qco2=3.75 ; 2×CO2 RF (7.3.2 of IPCC AR6) ; Optional global temperature constraint diff --git a/inst/input/hector_ssp585.ini b/inst/input/hector_ssp585.ini index d41fbe7d6..3f70504f9 100644 --- a/inst/input/hector_ssp585.ini +++ b/inst/input/hector_ssp585.ini @@ -162,6 +162,8 @@ baseyear=1750 ; when to start reporting; by definition, all F=0 in this year ; Optional radiative forcing constraint ;RF_tot_constrain=csv:tables/CONSTRAINT.csv +aero_scalar=1.0 ; uncertainty scaling factor for aerosol forcing +vol_scalar=1.0 ; uncertainty scaling factor for volcanic forcing delta_co2=0.05 ; (unitless) forcing tropospheric adjustments for CO2 (7.3.2.1 of IPCC AR6) delta_ch4=-.14 ; (unitless) forcing tropospheric adjustments for CH4 (7.3.2.2 of IPCC AR6) delta_n2o=0.07 ; (unitless) forcing tropospheric adjustments for N2O (7.3.2.3 of IPCC AR6) @@ -179,8 +181,6 @@ RF_misc[1750]=0 [temperature] S=3.0 ; equilibrium climate sensitivity for 2xCO2 degC (A.4.4 of IPCC AR6) diff=2.38 ; ocean heat diffusivity, cm2/s calibrated to historical observations Dorheim et al. 2024 for details -alpha=1.0 ; uncertainty scaling factor for aerosol forcing -volscl=1.0 ; uncertainty scaling factor for volcanic forcing qco2=3.75 ; 2×CO2 RF (7.3.2 of IPCC AR6) ; Optional global temperature constraint diff --git a/project_files/Xcode/hector.xcodeproj/project.pbxproj b/project_files/Xcode/hector.xcodeproj/project.pbxproj index 7324eb645..dfb4d11b3 100644 --- a/project_files/Xcode/hector.xcodeproj/project.pbxproj +++ b/project_files/Xcode/hector.xcodeproj/project.pbxproj @@ -82,9 +82,9 @@ 27B2C270261511C8005DE26D /* spline_forsythe.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27B2C24D261511C8005DE26D /* spline_forsythe.cpp */; }; 27B2C271261511C8005DE26D /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27B2C24E261511C8005DE26D /* main.cpp */; }; 27F2613726B55617004BDD47 /* csv_tracking_visitor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27962904268F237200333AA3 /* csv_tracking_visitor.cpp */; }; - 354045FC2913D50A00CA297D /* test_dependency_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 273FC38F26A3570B00D5303E /* test_dependency_finder.cpp */; }; - 354045FB2913CF6600CA297D /* test_csv_file_reader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 273FC39126A3570B00D5303E /* test_csv_file_reader.cpp */; }; 354045FA2913C0F300CA297D /* test_core.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 273FC38D26A3570B00D5303E /* test_core.cpp */; }; + 354045FB2913CF6600CA297D /* test_csv_file_reader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 273FC39126A3570B00D5303E /* test_csv_file_reader.cpp */; }; + 354045FC2913D50A00CA297D /* test_dependency_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 273FC38F26A3570B00D5303E /* test_dependency_finder.cpp */; }; 35ACB833285E4F4E0025928F /* h_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 275CBFF127AC7CC0009E2AF5 /* h_util.cpp */; }; 954D62AE278E005500840656 /* nh3_component.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 954D62AD278E005500840656 /* nh3_component.cpp */; }; 954D62AF278E005500840656 /* nh3_component.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 954D62AD278E005500840656 /* nh3_component.cpp */; }; @@ -607,7 +607,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - HEADER_SEARCH_PATHS = "${BOOSTROOT}"; + HEADER_SEARCH_PATHS = "${BOOSTINC}"; "HEADER_SEARCH_PATHS[arch=*]" = "${BOOSTROOT}"; LIBRARY_SEARCH_PATHS = "${BOOSTLIB}"; MACOSX_DEPLOYMENT_TARGET = 10.15; @@ -664,7 +664,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - HEADER_SEARCH_PATHS = "${BOOSTROOT}"; + HEADER_SEARCH_PATHS = "${BOOSTINC}"; LIBRARY_SEARCH_PATHS = "${BOOSTLIB}"; MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = NO; @@ -681,6 +681,7 @@ buildSettings = { CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; + HEADER_SEARCH_PATHS = "${BOOSTINC}"; LIBRARY_SEARCH_PATHS = "${BOOSTLIB}"; "OTHER_LDFLAGS[arch=*]" = "$(inherited)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -692,6 +693,7 @@ buildSettings = { CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; + HEADER_SEARCH_PATHS = "${BOOSTINC}"; LIBRARY_SEARCH_PATHS = "${BOOSTLIB}"; PRODUCT_NAME = "$(TARGET_NAME)"; }; diff --git a/src/carbon-cycle-model-74dba680.o.tmp b/src/carbon-cycle-model-74dba680.o.tmp new file mode 100644 index 000000000..e69de29bb diff --git a/src/forcing_component.cpp b/src/forcing_component.cpp index 203a805e4..d90334729 100644 --- a/src/forcing_component.cpp +++ b/src/forcing_component.cpp @@ -132,6 +132,9 @@ void ForcingComponent::init(Core *coreptr) { core->registerCapability(D_RHO_SO2, getComponentName()); core->registerCapability(D_RF_SO2, getComponentName()); core->registerCapability(D_RF_ACI, getComponentName()); + core->registerCapability(D_AERO_SCALE, getComponentName()); + core->registerCapability(D_VOLCANIC_SCALE, getComponentName()); + for (int i = 0; i < N_HALO_FORCINGS; ++i) { core->registerCapability(adjusted_halo_forcings[i], getComponentName()); forcing_name_map[adjusted_halo_forcings[i]] = halo_forcing_names[i]; @@ -183,6 +186,9 @@ void ForcingComponent::init(Core *coreptr) { core->registerInput(D_RHO_NH3, getComponentName()); core->registerInput(D_RF_MISC, getComponentName()); core->registerInput(D_FTOT_CONSTRAIN, getComponentName()); + core->registerInput(D_AERO_SCALE, getComponentName()); + core->registerInput(D_VOLCANIC_SCALE, getComponentName()); + } //------------------------------------------------------------------------------ @@ -237,6 +243,12 @@ void ForcingComponent::setData(const string &varName, } else if (varName == D_RHO_SO2) { H_ASSERT(data.date == Core::undefinedIndex(), "date not allowed"); rho_so2 = data.getUnitval(U_W_M2_GG); + } else if (varName == D_AERO_SCALE) { + H_ASSERT(data.date == Core::undefinedIndex(), "date not allowed"); + alpha = data.getUnitval(U_UNITLESS); + } else if (varName == D_VOLCANIC_SCALE) { + H_ASSERT(data.date == Core::undefinedIndex(), "date not allowed"); + volscl = data.getUnitval(U_UNITLESS); } else if (varName == D_FTOT_CONSTRAIN) { H_ASSERT(data.date != Core::undefinedIndex(), "date required"); Ftot_constrain.set(data.date, data.getUnitval(U_W_M2)); @@ -422,35 +434,37 @@ void ForcingComponent::run(const double runToDate) { double E_BC = core->sendMessage(M_GETDATA, D_EMISSIONS_BC, message_data(runToDate)) .value(U_TG); - double fbc = rho_bc * E_BC; + double fbc = alpha.value(U_UNITLESS) * rho_bc * E_BC; forcings[D_RF_BC].set(fbc, U_W_M2); // ---------- Organic carbon ---------- double E_OC = core->sendMessage(M_GETDATA, D_EMISSIONS_OC, message_data(runToDate)) .value(U_TG); - double foc = rho_oc * E_OC; + double foc = alpha.value(U_UNITLESS) * rho_oc * E_OC; forcings[D_RF_OC].set(foc, U_W_M2); // ---------- Sulphate Aerosols ---------- unitval SO2_emission = core->sendMessage(M_GETDATA, D_EMISSIONS_SO2, message_data(runToDate)); - double fso2 = rho_so2 * SO2_emission.value(U_GG_S); + double fso2 = alpha.value(U_UNITLESS) * rho_so2 * SO2_emission.value(U_GG_S); forcings[D_RF_SO2].set(fso2, U_W_M2); // ---------- NH3 ---------- double E_NH3 = core->sendMessage(M_GETDATA, D_EMISSIONS_NH3, message_data(runToDate)) .value(U_TG); - double fnh3 = rho_nh3 * E_NH3; + double fnh3 = alpha.value(U_UNITLESS) * rho_nh3 * E_NH3; forcings[D_RF_NH3].set(fnh3, U_W_M2); // ---------- RFaci ---------- // ERF from aerosol-cloud interactions (RFaci) // Based on Equation 7.SM.1.2 from IPCC AR6 where - double aci_rf = - -1 * aci_beta * - log(1 + (SO2_emission / s_SO2) + ((E_BC + E_OC) / s_BCOC)); + // The 0.2 value comes from equally distributing the alpha scalar to all 5 + // aerosol RF types. + double aci_rf = + alpha.value(U_UNITLESS) * (-1 * aci_beta * + log(1 + (SO2_emission / s_SO2) + ((E_BC + E_OC) / s_BCOC))); forcings[D_RF_ACI].set(aci_rf, U_W_M2); } @@ -464,6 +478,7 @@ void ForcingComponent::run(const double runToDate) { if (core->checkCapability(D_VOLCANIC_SO2)) { // The volcanic forcings are read in from an ini file. forcings[D_RF_VOL] = + volscl.value(U_UNITLESS) * core->sendMessage(M_GETDATA, D_VOLCANIC_SO2, message_data(runToDate)); } @@ -540,6 +555,10 @@ unitval ForcingComponent::getData(const std::string &varName, returnval = rho_so2; } else if (varName == D_RHO_NH3) { returnval = rho_nh3; + } else if (varName == D_AERO_SCALE) { + returnval = alpha; + } else if (varName == D_VOLCANIC_SCALE) { + returnval = volscl; } else if (varName == D_RF_BASEYEAR) { returnval.set(baseyear, U_UNITLESS); } else { diff --git a/src/temperature_component.cpp b/src/temperature_component.cpp index 790d7ae10..566d300ca 100644 --- a/src/temperature_component.cpp +++ b/src/temperature_component.cpp @@ -126,19 +126,11 @@ void TemperatureComponent::init(Core *coreptr) { // Register our dependencies core->registerDependency(D_RF_TOTAL, getComponentName()); - core->registerDependency(D_RF_BC, getComponentName()); - core->registerDependency(D_RF_OC, getComponentName()); - core->registerDependency(D_RF_NH3, getComponentName()); - core->registerDependency(D_RF_SO2, getComponentName()); - core->registerDependency(D_RF_ACI, getComponentName()); - core->registerDependency(D_RF_VOL, getComponentName()); // Register the inputs we can receive from outside core->registerInput(D_ECS, getComponentName()); core->registerInput(D_QCO2, getComponentName()); core->registerInput(D_DIFFUSIVITY, getComponentName()); - core->registerInput(D_AERO_SCALE, getComponentName()); - core->registerInput(D_VOLCANIC_SCALE, getComponentName()); core->registerInput(D_LO_WARMING_RATIO, getComponentName()); core->registerInput(D_TAS_CONSTRAIN, getComponentName()); } @@ -177,12 +169,6 @@ void TemperatureComponent::setData(const string &varName, } else if (varName == D_DIFFUSIVITY) { H_ASSERT(data.date == Core::undefinedIndex(), "date not allowed"); diff = data.getUnitval(U_CM2_S); - } else if (varName == D_AERO_SCALE) { - H_ASSERT(data.date == Core::undefinedIndex(), "date not allowed"); - alpha = data.getUnitval(U_UNITLESS); - } else if (varName == D_VOLCANIC_SCALE) { - H_ASSERT(data.date == Core::undefinedIndex(), "date not allowed"); - volscl = data.getUnitval(U_UNITLESS); } else if (varName == D_QCO2) { H_ASSERT(data.date == Core::undefinedIndex(), "date not allowed"); qco2 = data.getUnitval(U_UNITLESS).value(U_UNITLESS); @@ -447,32 +433,9 @@ void TemperatureComponent::run(const double runToDate) { // Some needed inputs int tstep = runToDate - core->getStartDate(); + forcing[tstep] = core->sendMessage(M_GETDATA, D_RF_TOTAL, message_data(runToDate)).value(U_W_M2); + - // Calculate the total aresol forcing from aerosol-radiation interactions and - // the aerosol-cloud interactions so that that total aerosol forcing can be - // adjusted by the aerosol forcing scaling factor. - double aero_forcing = - core->sendMessage(M_GETDATA, D_RF_BC, message_data(runToDate)) - .value(U_W_M2) + - core->sendMessage(M_GETDATA, D_RF_OC, message_data(runToDate)) - .value(U_W_M2) + - core->sendMessage(M_GETDATA, D_RF_NH3, message_data(runToDate)) - .value(U_W_M2) + - core->sendMessage(M_GETDATA, D_RF_SO2, message_data(runToDate)) - .value(U_W_M2) + - core->sendMessage(M_GETDATA, D_RF_ACI, message_data(runToDate)) - .value(U_W_M2); - - double volcanic_forcing = - double(core->sendMessage(M_GETDATA, D_RF_VOL, message_data(runToDate))); - - // Adjust total forcing to account for the aerosol and volcanic forcing - // scaling factor - const double ftot = core->sendMessage(M_GETDATA, D_RF_TOTAL, message_data(runToDate)).value(U_W_M2); - forcing[tstep] = - double(ftot) - - (1.0 - alpha) * aero_forcing - (1.0 - volscl) * volcanic_forcing; - // Initialize variables for time-stepping through the model double DQ1 = 0.0; double DQ2 = 0.0; @@ -695,17 +658,9 @@ unitval TemperatureComponent::getData(const std::string &varName, H_ASSERT(date == Core::undefinedIndex(), "Date not allowed for diffusivity"); returnval = diff; - } else if (varName == D_AERO_SCALE) { - H_ASSERT(date == Core::undefinedIndex(), - "Date not allowed for aero scaler"); - returnval = alpha; } else if (varName == D_ECS) { H_ASSERT(date == Core::undefinedIndex(), "Date not allowed for ECS"); returnval = S; - } else if (varName == D_VOLCANIC_SCALE) { - H_ASSERT(date == Core::undefinedIndex(), - "Date not allowed for volcanic scaler"); - returnval = volscl; } else if (varName == D_QCO2) { H_ASSERT(date == Core::undefinedIndex(), "Date not allowed for q2co2"); returnval = unitval(qco2, U_W_M2); diff --git a/tests/testthat/input/luc_pulse.ini b/tests/testthat/input/luc_pulse.ini index 98a3c2e45..18a7fad39 100644 --- a/tests/testthat/input/luc_pulse.ini +++ b/tests/testthat/input/luc_pulse.ini @@ -143,6 +143,8 @@ baseyear=1750 ; when to start reporting; by definition, all F=0 in this year ; Optional radiative forcing constraint ; If supplied, the model will use these data, ignoring what it calculates ;RF_tot_constrain=csv:tables/CONSTRAINT.csv +aero_scalar=1.0 ; uncertainty scaling factor for aerosol forcing +vol_scalar=1.0 ; uncertainty scaling factor for volcanic forcing delta_co2=0.05 ; (unitless) forcing tropospheric adjustments for CO2 (7.3.2.1 of IPCC AR6) delta_ch4=-.14 ; (unitless) forcing tropospheric adjustments for CH4 (7.3.2.2 of IPCC AR6) delta_n2o=0.07 ; (unitless) forcing tropospheric adjustments for N2O (7.3.2.3 of IPCC AR6) @@ -164,8 +166,6 @@ enabled=1 S=2.7 ; equilibrium climate sensitivity for 2xCO2, degC (calibrated to historical) diff=2.4 ; ocean heat diffusivity, cm2/s (calibrated to historical) -alpha=0.5 ; scaling factor for aerosol forcing, calibrated to historical observations -volscl=1.0 ; scaling factor for volcanic forcing qco2=3.75 ; 2×CO2 RF (7.3.2 of IPCC AR6) ; Optional global temperature constraint diff --git a/tests/testthat/test_parameters.R b/tests/testthat/test_parameters.R index 9282fa6ad..a5dba56be 100644 --- a/tests/testthat/test_parameters.R +++ b/tests/testthat/test_parameters.R @@ -6,6 +6,11 @@ sampledir <- system.file("output", package = "hector") testvars <- c(CONCENTRATIONS_CO2(), RF_TOTAL(), GLOBAL_TAS()) dates <- 1750:2100 + +# Limit the test dates to the future, where the historical +# variability won't impact the temp. +tdates <- 2000:2100 + ssp245 <- file.path(inputdir, "hector_ssp245.ini") @@ -87,9 +92,6 @@ test_that("Lowering initial CO2 lowers output CO2", { shutdown(hc) }) -# Limit the test dates to the future, where the historical -# variability won't impact the temp. -tdates <- 2000:2100 test_that("Lowering ECS lowers output Temperature", { @@ -176,7 +178,7 @@ test_that("Lowering diffusivity increases temperature", { test_that("Lowering aerosol forcing scaling factor increases temperature", { # Relevant vars to save and test. - vars <- c(GLOBAL_TAS()) + vars <- c(GLOBAL_TAS(), RF_BC(), RF_OC(), RF_SO2(), RF_NH3(), RF_ACI(), RF_TOTAL()) # Define Hector core. hc <- newcore(ssp245, suppresslogging = TRUE) @@ -193,11 +195,47 @@ test_that("Lowering aerosol forcing scaling factor increases temperature", { setvar(hc, NA, AERO_SCALE(), new_alpha, getunits(AERO_SCALE())) reset(hc, hc$reset_date) run(hc, 2100) - dd2 <- fetchvars(hc, tdates, GLOBAL_TAS()) + dd2 <- fetchvars(hc, tdates, vars) # Check to make sure that the temp and RF have changed. - diff <- dd2$value - dd1$value - expect_gt(min(diff), 0.0) + + # Checking that temperatures increase + temp1 <- dd1[dd1$variable == GLOBAL_TAS(),] + temp2 <- dd2[dd2$variable == GLOBAL_TAS(),] + temp_diff <- temp2$value - temp1$value + expect_gt(min(temp_diff), 0.0) + + # Checking that black carbon RF decreases + bc1 <- dd1[dd1$variable == RF_BC(),] + bc2 <- dd2[dd2$variable == RF_BC(),] + bc_diff <- bc2$value - bc1$value + expect_lt(max(bc_diff), 0.0) + + # Checking organic carbon RF magnitude decreases + oc1 <- dd1[dd1$variable == RF_OC(),] + oc2 <- dd2[dd2$variable == RF_OC(),] + oc_diff <- abs(oc2$value) - abs(oc1$value) + expect_lt(max(oc_diff), 0.0) + + # Checking that NH3 RF increases (becomes less negative) + nh3_1 <- dd1[dd1$variable == RF_NH3(),] + nh3_2 <- dd2[dd2$variable == RF_NH3(),] + nh3_diff <- nh3_2$value - nh3_1$value + expect_gt(min(nh3_diff), 0.0) + + # Checking that SO2 RF increases (becomes less negative) + so2_1 <- dd1[dd1$variable == RF_SO2(),] + so2_2 <- dd2[dd2$variable == RF_SO2(),] + so2_diff <- so2_2$value - so2_1$value + expect_gt(min(so2_diff), 0.0) + + # Checking that ACI RF increases (becomes less negative) + aci1 <- dd1[dd1$variable == RF_ACI(),] + aci2 <- dd2[dd2$variable == RF_ACI(),] + aci_diff <- aci2$value - aci1$value + expect_gt(min(aci_diff), 0.0) + + shutdown(hc) }) @@ -207,7 +245,7 @@ test_that("Increasing volcanic forcing scaling factor increases the effect of vo ## Because the volcanic forcing scaling factor only has an impact during the ## the volcanic events. Only check the temp during those years. tdates <- c(1960, 1965) - vars <- GLOBAL_TAS() + vars <- c(GLOBAL_TAS(), RF_VOL()) # Set up and run Hector hc <- newcore(ssp245, suppresslogging = TRUE) @@ -222,7 +260,18 @@ test_that("Increasing volcanic forcing scaling factor increases the effect of vo run(hc) new_out <- fetchvars(hc, tdates, vars) - expect_true(all(out$value != new_out$value)) + # Getting temperature and RF data + temps <- out[out$variable == GLOBAL_TAS(),] + rfs <- out[out$variable == RF_VOL(),] + + new_temps <- new_out[new_out$variable == GLOBAL_TAS(),] + new_rfs <- new_out[new_out$variable == RF_VOL(),] + + expect_true(all(temps$value != new_temps$value)) + + # Volcanic RF should decrease (become more negative) + rf_diff <- new_rfs$value - rfs$value + expect_lt(max(rf_diff), 0.0) }) test_that("Decreasing vegetation NPP fraction has down stream impacts", {