├── scripts └── simple_met_input │ ├── src │ ├── __init__.py │ ├── thermo.py │ └── moist.py │ ├── moist_region_parametrisation.png │ ├── main.py │ └── README.txt ├── Code.v05-00 ├── include │ ├── EPM │ │ ├── Models │ │ │ ├── Original │ │ │ │ ├── Integrate.hpp │ │ │ │ ├── Indexes.hpp │ │ │ │ ├── StateObserver.hpp │ │ │ │ └── RHS.hpp │ │ │ ├── External.hpp │ │ │ ├── NewPhysics.hpp │ │ │ ├── Original.hpp │ │ │ └── Base.hpp │ │ ├── EPM.hpp │ │ ├── Utils │ │ │ └── Physics.hpp │ │ └── Solution.hpp │ ├── APCEMM.h.in │ ├── Util │ │ ├── YamlUtils.hpp │ │ ├── PlumeModelUtils.hpp │ │ ├── Error.hpp │ │ ├── VectorUtils.hpp │ │ ├── MC_Rand.hpp │ │ ├── ForwardDecl.hpp │ │ ├── MolarWeights.hpp │ │ ├── MetFunction.hpp │ │ └── PhysConstant.hpp │ ├── FVM_ANDS │ │ ├── FVM_ANDS_HelperFunctions.hpp │ │ ├── FVM_ANDS_enums.hpp │ │ ├── BoundaryCondition.hpp │ │ └── FVM_Solver.hpp │ ├── Core │ │ ├── Monitor.hpp │ │ ├── Status.hpp │ │ ├── ReadJRates.hpp │ │ ├── Util.hpp │ │ ├── Ring.hpp │ │ ├── Fuel.hpp │ │ ├── Cluster.hpp │ │ ├── SZA.hpp │ │ ├── Species.hpp │ │ ├── Diag_Mod.hpp │ │ ├── LiquidAer.hpp │ │ ├── Interface.hpp │ │ ├── Emission.hpp │ │ ├── Mesh.hpp │ │ ├── Engine.hpp │ │ ├── TimestepVarsWrapper.hpp │ │ ├── MPMSimVarsWrapper.hpp │ │ ├── Aircraft.hpp │ │ ├── Parameters.hpp │ │ └── LAGRIDPlumeModel.hpp │ ├── AIM │ │ ├── Settling.hpp │ │ ├── Nucleation.hpp │ │ ├── Coagulation.hpp │ │ └── buildKernel.hpp │ ├── LAGRID │ │ ├── FreeCoordBoxGrid.hpp │ │ └── RemappingFunctions.hpp │ └── KPP │ │ ├── KPP_Global.h │ │ ├── KPP.hpp │ │ └── KPP_Sparse.h ├── tests │ ├── testmain.cpp │ ├── test_meteorology_metfile.nc │ ├── test2.yaml │ ├── CMakeLists.txt │ ├── test_integrate.cpp │ ├── test_aircraft.cpp │ ├── test_solver_helpfunctions.hpp │ ├── test_nucleation.cpp │ └── test_LAGRID.cpp ├── src │ ├── YamlInputReader │ │ └── CMakeLists.txt │ ├── Util │ │ ├── CMakeLists.txt │ │ ├── YamlUtils.cpp │ │ ├── Error.cpp │ │ └── MC_Rand.cpp │ ├── LAGRID │ │ ├── CMakeLists.txt │ │ └── FreeCoordBoxGrid.cpp │ ├── AIM │ │ └── CMakeLists.txt │ ├── FVM_ANDS │ │ ├── CMakeLists.txt │ │ ├── BoundaryCondition.cpp │ │ └── FVM_ANDS_HelperFunctions.cpp │ ├── CMakeLists.txt │ ├── EPM │ │ ├── CMakeLists.txt │ │ ├── Models │ │ │ ├── External.cpp │ │ │ └── Original │ │ │ │ └── Model.cpp │ │ └── EPM.cpp │ ├── KPP │ │ ├── CMakeLists.txt │ │ └── UCX.def │ └── Core │ │ ├── CMakeLists.txt │ │ ├── Input_Mod.cpp │ │ ├── MPMSimVarsWrapper.cpp │ │ ├── Util.cpp │ │ ├── TimestepVarsWrapper.cpp │ │ ├── Ring.cpp │ │ ├── SZA.cpp │ │ └── Fuel.cpp ├── vcpkg.json └── vcpkg-configuration.json ├── examples ├── issl_rhi140 │ ├── example_met_file.nc │ └── run_example3.sh └── default │ ├── input.yaml │ └── run_example.sh ├── .gitmodules ├── rundirs └── SampleRunDir │ └── run_example.sh ├── .devcontainer ├── devcontainer.json ├── README.md └── Dockerfile.apcemm ├── LICENSE ├── .gitignore ├── .gitattributes └── input_data └── init.txt /scripts/simple_met_input/src/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Code.v05-00/include/EPM/Models/Original/Integrate.hpp: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Code.v05-00/tests/testmain.cpp: -------------------------------------------------------------------------------- 1 | #define CATCH_CONFIG_MAIN -------------------------------------------------------------------------------- /examples/issl_rhi140/example_met_file.nc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MIT-LAE/APCEMM/HEAD/examples/issl_rhi140/example_met_file.nc -------------------------------------------------------------------------------- /Code.v05-00/tests/test_meteorology_metfile.nc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MIT-LAE/APCEMM/HEAD/Code.v05-00/tests/test_meteorology_metfile.nc -------------------------------------------------------------------------------- /examples/default/input.yaml: -------------------------------------------------------------------------------- 1 | METEOROLOGY MENU: 2 | METEOROLOGICAL INPUT SUBMENU: 3 | Met input file path (string): example_met_file.nc 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Code.v05-00/submodules/vcpkg"] 2 | path = Code.v05-00/submodules/vcpkg 3 | url = https://github.com/Microsoft/vcpkg.git 4 | -------------------------------------------------------------------------------- /rundirs/SampleRunDir/run_example.sh: -------------------------------------------------------------------------------- 1 | cd ../../Code.v05-00/ 2 | cmake --build . 3 | cd ../rundirs/SampleRunDir 4 | ./../../Code.v05-00/APCEMM input.yaml 5 | 6 | -------------------------------------------------------------------------------- /scripts/simple_met_input/moist_region_parametrisation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MIT-LAE/APCEMM/HEAD/scripts/simple_met_input/moist_region_parametrisation.png -------------------------------------------------------------------------------- /Code.v05-00/src/YamlInputReader/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SRCS 2 | YamlInputReader.cpp) 3 | add_library(YamlInputReader STATIC ${SRCS}) 4 | target_link_libraries(YamlInputReader yaml-cpp::yaml-cpp) 5 | 6 | -------------------------------------------------------------------------------- /Code.v05-00/include/APCEMM.h.in: -------------------------------------------------------------------------------- 1 | /* Template for CMake to generate an APCEMM.h with appropriate preprocessor definitions 2 | given boolean values of the parameters during CMake compilation. */ 3 | #cmakedefine DEBUG 4 | #cmakedefine RINGS 5 | #cmakedefine OMP -------------------------------------------------------------------------------- /Code.v05-00/include/Util/YamlUtils.hpp: -------------------------------------------------------------------------------- 1 | #ifndef YAMLUTILS_H_ 2 | #define YAMLUTILS_H_ 3 | 4 | #include 5 | 6 | const YAML::Node mergeYamlNodes(const YAML::Node& defaults, const YAML::Node& overrides); 7 | 8 | #endif // YAMLUTILS_H_ 9 | -------------------------------------------------------------------------------- /Code.v05-00/vcpkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": [ 3 | "boost-array", 4 | "boost-math", 5 | "boost-odeint", 6 | "boost-range", 7 | "catch2", 8 | "eigen3", 9 | "fmt", 10 | "fftw3", 11 | "netcdf-cxx4", 12 | {"name": "openssl", "version>=": "3.4.0"}, 13 | "curl", 14 | "yaml-cpp" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /Code.v05-00/src/Util/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Source files that need to be compiled 2 | set(SRCS 3 | Error.cpp 4 | MC_Rand.cpp 5 | PhysFunction.cpp 6 | MetFunction.cpp 7 | PlumeModelUtils.cpp 8 | VectorUtils.cpp 9 | YamlUtils.cpp 10 | ) 11 | 12 | # This command ensures the static library gets build 13 | add_library(Util STATIC ${SRCS}) 14 | -------------------------------------------------------------------------------- /examples/default/run_example.sh: -------------------------------------------------------------------------------- 1 | # # Uncomment the following lines to compile APCEMM 2 | # git submodule update --init --recursive 3 | # mkdir ../../build 4 | # cd ../../build/ 5 | # cmake ../Code.v05-00 && cmake --build . || exit 1 6 | # cd ../examples/Example3_met_input 7 | 8 | # Run Example 3 9 | export APCEMM_runDir="." 10 | ./../../build/APCEMM input.yaml 11 | -------------------------------------------------------------------------------- /examples/issl_rhi140/run_example3.sh: -------------------------------------------------------------------------------- 1 | # # Uncomment the following lines to compile APCEMM 2 | # git submodule update --init --recursive 3 | # mkdir ../../build 4 | # cd ../../build/ 5 | # cmake ../Code.v05-00 && cmake --build . || exit 1 6 | # cd ../examples/Example3_met_input 7 | 8 | # Run Example 3 9 | export APCEMM_runDir="." 10 | ./../../build/APCEMM input.yaml 11 | -------------------------------------------------------------------------------- /Code.v05-00/src/LAGRID/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Source files that need to be compiled 2 | set(SRCS 3 | FreeCoordBoxGrid.cpp 4 | RemappingFunctions.cpp 5 | ) 6 | 7 | # This command ensures the static library gets built 8 | add_library(LAGRID STATIC ${SRCS}) 9 | # This command defines the dependencies of libFDM_ANDS.a 10 | target_link_libraries(LAGRID OpenMP::OpenMP_CXX) 11 | -------------------------------------------------------------------------------- /Code.v05-00/src/AIM/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Source files that need to be compiled 2 | set(SRCS 3 | Aerosol.cpp 4 | buildKernel.cpp 5 | Coagulation.cpp 6 | Nucleation.cpp 7 | Settling.cpp) 8 | 9 | # This command ensures the static library gets build 10 | add_library(AIM STATIC ${SRCS}) 11 | 12 | # This command defines the dependencies of libAIM.a 13 | target_link_libraries(AIM Util OpenMP::OpenMP_CXX) 14 | -------------------------------------------------------------------------------- /Code.v05-00/vcpkg-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "default-registry": { 3 | "kind": "git", 4 | "baseline": "c75ff8cf3b784f67aa614552f32a6b2c7b9d8efc", 5 | "repository": "https://github.com/microsoft/vcpkg" 6 | }, 7 | "registries": [ 8 | { 9 | "kind": "artifact", 10 | "location": "https://github.com/microsoft/vcpkg-ce-catalog/archive/refs/heads/main.zip", 11 | "name": "microsoft" 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /Code.v05-00/src/FVM_ANDS/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Source files that need to be compiled 2 | set(SRCS 3 | AdvDiffSystem.cpp 4 | BoundaryCondition.cpp 5 | FVM_ANDS_HelperFunctions.cpp 6 | FVM_Solver.cpp 7 | ) 8 | 9 | # This command ensures the static library gets build 10 | add_library(FVM_ANDS STATIC ${SRCS}) 11 | # This command defines the dependencies of libFDM_ANDS.a 12 | target_link_libraries(FVM_ANDS Util Eigen3::Eigen OpenMP::OpenMP_CXX) 13 | -------------------------------------------------------------------------------- /Code.v05-00/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # These commands ensure that the libraries get built 2 | add_subdirectory(${CMAKE_SOURCE_DIR}/src/Util) 3 | add_subdirectory(${CMAKE_SOURCE_DIR}/src/AIM) 4 | add_subdirectory(${CMAKE_SOURCE_DIR}/src/KPP) 5 | add_subdirectory(${CMAKE_SOURCE_DIR}/src/EPM) 6 | add_subdirectory(${CMAKE_SOURCE_DIR}/src/Core) 7 | add_subdirectory(${CMAKE_SOURCE_DIR}/src/YamlInputReader) 8 | add_subdirectory(${CMAKE_SOURCE_DIR}/src/FVM_ANDS) 9 | add_subdirectory(${CMAKE_SOURCE_DIR}/src/LAGRID) 10 | -------------------------------------------------------------------------------- /Code.v05-00/tests/test2.yaml: -------------------------------------------------------------------------------- 1 | PARAMETER MENU: 2 | Plume Process [hr] (double): 24 3 | METEOROLOGICAL PARAMETERS SUBMENU: 4 | Horiz. diff. coeff. [m^2/s] (double): 17.0 5 | Brunt-Vaisala Frequency [s^-1] (double): 0.017 6 | Pressure [hPa] (double): 320 330 340 7 | LOCATION AND TIME SUBMENU: 8 | LON [deg] (double): -45 9 | LAT [deg] (double): 65 10 | Emission day [1-365] (int): 143 11 | Emission time [hr] (double) : 12 12 | Total fuel flow [kg/s] (double) : 2.9 13 | Aircraft mass [kg] (double): 2.30E+05 14 | -------------------------------------------------------------------------------- /Code.v05-00/src/EPM/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Source files that need to be compiled 2 | set(SRCS 3 | EPM.cpp 4 | Solution.cpp 5 | Utils/Physics.cpp 6 | Models/Original/Model.cpp 7 | Models/Original/StateObserver.cpp 8 | Models/Original/Integrate.cpp 9 | Models/Original/RHS.cpp 10 | Models/External.cpp 11 | ) 12 | 13 | # This command ensures the static library gets build 14 | add_library(EPM STATIC ${SRCS}) 15 | 16 | # This command defines the dependencies of libEPM.a 17 | target_link_libraries(EPM AIM Core Util) 18 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "build": { 3 | "dockerfile": "Dockerfile.apcemm" 4 | }, 5 | "customizations": { 6 | "vscode": { 7 | "extensions": [ 8 | "dbaeumer.vscode-eslint", 9 | "ms-vscode.cpptools-themes", 10 | "ms-vscode.cpptools", 11 | "ms-vscode.cpptools-extension-pack" 12 | ] 13 | } 14 | }, 15 | "workspaceMount": "source=${localWorkspaceFolder},target=/home/APCEMM,type=bind,consistency=cached", 16 | "workspaceFolder": "/home/APCEMM" 17 | } -------------------------------------------------------------------------------- /Code.v05-00/include/EPM/Models/External.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EPM_MODELS_EXTERNAL_HPP_INCLUDED 2 | #define EPM_MODELS_EXTERNAL_HPP_INCLUDED 3 | 4 | #include "EPM/Models/Base.hpp" 5 | 6 | 7 | namespace EPM::Models { 8 | 9 | class External : public Base { 10 | public: 11 | External(const OptInput &optInput, const Input &input, 12 | const Aircraft &aircraft, const Emission &EI, 13 | const Meteorology &met, const MPMSimVarsWrapper &simVars); 14 | 15 | std::variant run() override; 16 | }; 17 | 18 | } 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /Code.v05-00/include/FVM_ANDS/FVM_ANDS_HelperFunctions.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FVM_ANDS_HELPERFUNCTIONS_H 2 | #define FVM_ANDS_HELPERFUNCTIONS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "FVM_ANDS/BoundaryCondition.hpp" 8 | 9 | namespace FVM_ANDS{ 10 | int twoDIdx_to_vecIdx(int idx_x, int idx_y, int nx, int ny, vecFormat format = vecFormat::COLMAJOR); 11 | Eigen::VectorXd std2dVec_to_eigenVec(const Vector_2D& phi, vecFormat format = vecFormat::COLMAJOR); 12 | BoundaryConditions bcFrom2DVector(const Vector_2D& initialVec, bool zeroBC = false); 13 | Vector_2D eigenVec_to_std2dVec(Eigen::VectorXd eig_vec, int nx, int ny); 14 | } 15 | #endif -------------------------------------------------------------------------------- /Code.v05-00/include/EPM/Models/NewPhysics.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EPM_MODELS_NEW_PHYSICS_HPP_INCLUDED 2 | #define EPM_MODELS_NEW_PHYSICS_HPP_INCLUDED 3 | 4 | #include 5 | 6 | #include "EPM/Models/Base.hpp" 7 | 8 | 9 | namespace EPM::Models { 10 | 11 | class NewPhysics : public Base { 12 | public: 13 | NewPhysics(const OptInput &optInput, const Input &input, 14 | const Aircraft &aircraft, const Emission &EI, 15 | const Meteorology &met, const MPMSimVarsWrapper &simVars) : 16 | Base(optInput, input, aircraft, EI, met, simVars) { 17 | throw std::runtime_error("New EPM model is not implemented yet."); 18 | } 19 | 20 | std::variant run() override; 21 | }; 22 | 23 | } // namespace EPM::Models 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /Code.v05-00/src/KPP/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Source files that need to be compiled 2 | set(SRCS 3 | KPP_Function.cpp 4 | KPP_Hessian.cpp 5 | KPP_HessianSP.cpp 6 | KPP_HetRates.cpp 7 | KPP_Integrator_ADJ.cpp 8 | KPP_Integrator.cpp 9 | KPP_Jacobian.cpp 10 | KPP_JacobianSP.cpp 11 | KPP_LinearAlgebra.cpp 12 | KPP_Main_ADJ.cpp 13 | KPP_Monitor.cpp 14 | KPP_Photol.cpp 15 | KPP_Rates.cpp 16 | KPP_Stoichiom.cpp 17 | KPP_StoichiomSP.cpp 18 | KPP_Util.cpp 19 | ) 20 | 21 | # This command ensures the static library gets build 22 | add_library(KPP STATIC ${SRCS}) 23 | 24 | # This command defines the dependencies of libKPP.a 25 | target_link_libraries(KPP ${NETCDF_LIBRARIES} 26 | ${netCDFCxx_LIBRARIES} OpenMP::OpenMP_CXX) 27 | -------------------------------------------------------------------------------- /.devcontainer/README.md: -------------------------------------------------------------------------------- 1 | ### NOTICE 2 | 3 | This work was produced for the U.S. Government under Contract 693KA8 -22-C- 00001 and is subject to Federal Aviation Administration Acquisition Management System Clause 3.5 -13, Rights In Data -General, Alt. III and Alt. IV (Oct. 1996). 4 | 5 | The contents of this document reflect the views of the author and The MITRE Corporation and do not necessarily reflect the views of the Federal Aviation Administration (FAA) or the Department of Transportation (DOT). Neither the FAA nor the DOT makes any warranty or guarantee, expressed or implied, concerning the content or accuracy of these views. 6 | 7 | For further information, please contact The MITRE Corporation, Contracts Management Office, 7515 Colshire Drive, McLean, VA 22102 -7539 , (703) 983- 6000. 8 | 9 | PRS Case: 23-2977 10 | 11 | © 2023 The MITRE Corporation. All Rights Reserved. 12 | -------------------------------------------------------------------------------- /Code.v05-00/include/EPM/Models/Original.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EPM_MODELS_ORIGINAL_HPP_INCLUDED 2 | #define EPM_MODELS_ORIGINAL_HPP_INCLUDED 3 | 4 | #include "Util/ForwardDecl.hpp" 5 | #include "EPM/Models/Base.hpp" 6 | 7 | namespace EPM::Models { 8 | 9 | class Original : public Base { 10 | public: 11 | Original(const OptInput &optInput, const Input &input, 12 | const Aircraft &aircraft, const Emission &EI, 13 | const Meteorology &met, const MPMSimVarsWrapper &simVars); 14 | 15 | std::variant run() override; 16 | 17 | private: 18 | std::variant Integrate(double sootDensity); 19 | 20 | SimStatus RunMicrophysics(EPM::Output &out, double sootDensity, double delta_T); 21 | 22 | Vector_1D VAR_; // Concentration of variable species. 23 | }; 24 | 25 | } // namespace EPM::Models 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /Code.v05-00/src/Core/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Source files that need to be compiled 2 | set(SRCS 3 | Aircraft.cpp 4 | Cluster.cpp 5 | Diag_Mod.cpp 6 | Emission.cpp 7 | Engine.cpp 8 | Fuel.cpp 9 | Input_Mod.cpp 10 | Input.cpp 11 | LAGRIDPlumeModel.cpp 12 | LiquidAer.cpp 13 | Meteorology.cpp 14 | Mesh.cpp 15 | MPMSimVarsWrapper.cpp 16 | Ring.cpp 17 | Species.cpp 18 | SZA.cpp 19 | Util.cpp 20 | TimestepVarsWrapper.cpp 21 | Vortex.cpp 22 | ) 23 | 24 | # This command ensures the static library gets build 25 | add_library(Core STATIC ${SRCS}) 26 | 27 | target_link_libraries(Core PRIVATE netCDF::netcdf netCDF::netcdf-cxx4) 28 | target_link_libraries(Core PRIVATE yaml-cpp::yaml-cpp) 29 | 30 | # This command defines the dependencies of libCore.a 31 | target_link_libraries(Core PRIVATE LAGRID FVM_ANDS AIM Util EPM KPP YamlInputReader) 32 | -------------------------------------------------------------------------------- /Code.v05-00/include/Util/PlumeModelUtils.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PLUMEMODELUTILS_H 2 | #define PLUMEMODELUTILS_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace PlumeModelUtils { 9 | double UpdateTime( double time, const double tStart, \ 10 | const double DYN_DT, double& nextTimeStep ); 11 | 12 | std::vector BuildTime( const double tStart, const double tEnd, \ 13 | const double DYN_DT ); 14 | 15 | 16 | void AdvGlobal( const double time, const double T_UPDRAFT, \ 17 | const double V_UPDRAFT, \ 18 | double &v_x, double &v_y, \ 19 | double &dTrav_x, double &dTrav_y ); 20 | 21 | void DiffParam( const double time, double &d_x, double &d_y, \ 22 | const double D_X, const double D_Y ); 23 | } 24 | 25 | 26 | 27 | #endif -------------------------------------------------------------------------------- /Code.v05-00/src/EPM/Models/External.cpp: -------------------------------------------------------------------------------- 1 | #include "EPM/Models/External.hpp" 2 | 3 | namespace EPM::Models { 4 | 5 | External::External(const OptInput &optInput, const Input &input, 6 | const Aircraft &aircraft, const Emission &EI, 7 | const Meteorology &met, const MPMSimVarsWrapper &simVars) : 8 | Base(optInput, input, aircraft, EI, met, simVars) 9 | { 10 | if (optInput.SIMULATION_EXTERNAL_EPM_NETCDF_FILENAME == "=MISSING=") { 11 | throw std::invalid_argument( 12 | "External EPM NetCDF filename is missing in the input file."); 13 | } 14 | } 15 | 16 | std::variant External::run() { 17 | EPM::Output output; 18 | std::cout << "Reading external EPM NetCDF file: " 19 | << optInput_.SIMULATION_EXTERNAL_EPM_NETCDF_FILENAME << std::endl; 20 | output.read(optInput_.SIMULATION_EXTERNAL_EPM_NETCDF_FILENAME); 21 | return output; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /Code.v05-00/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(Catch) 2 | 3 | set(SRC_TEST 4 | testmain.cpp 5 | test_physfunction.cpp 6 | test_nucleation.cpp 7 | test_buildkernel.cpp 8 | test_aerosol.cpp 9 | #test_meteorology.cpp 10 | test_integrate.cpp 11 | test_metfunction.cpp 12 | test_aircraft.cpp 13 | test_yamlreader.cpp 14 | ) 15 | #Add preprocessor def of the tests dir 16 | add_definitions(-DAPCEMM_TESTS_DIR="${CMAKE_SOURCE_DIR}/tests") 17 | 18 | add_executable(unittest ${SRC_TEST}) 19 | target_link_libraries(unittest Catch2::Catch2WithMain Util AIM EPM YamlInputReader) 20 | catch_discover_tests(unittest) 21 | 22 | add_executable(test_solver test_adv_diff_solver.cpp) 23 | target_link_libraries(test_solver Catch2::Catch2WithMain FVM_ANDS Core LAGRID OpenSSL::SSL OpenSSL::Crypto) 24 | catch_discover_tests(test_solver) 25 | 26 | add_executable(test_LAGRID test_LAGRID.cpp) 27 | target_link_libraries(test_LAGRID Catch2::Catch2WithMain LAGRID) 28 | catch_discover_tests(test_LAGRID) 29 | -------------------------------------------------------------------------------- /Code.v05-00/include/FVM_ANDS/FVM_ANDS_enums.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #ifndef FVM_ANDS_ENUMS_H 3 | #define FVM_ANDS_ENUMS_H 4 | namespace FVM_ANDS{ 5 | enum class BoundaryConditionFlag: unsigned char { 6 | INTERIOR = 0, 7 | DIRICHLET_INT_BPOINT = 1, 8 | PERIODIC_INT_BPOINT = 2, 9 | DIRICHLET_GHOSTPOINT = 101, 10 | PERIODIC_GHOSTPOINT = 102, 11 | ERROR = std::numeric_limits::max() 12 | }; 13 | enum class FaceDirection: unsigned char { 14 | NORTH, 15 | SOUTH, 16 | EAST, 17 | WEST, 18 | ERROR 19 | }; 20 | enum class SolutionMethod : unsigned char { 21 | ForwardEuler, 22 | BackwardEuler, 23 | OperatorSplitting 24 | }; 25 | enum class AdvectionScheme : unsigned char { 26 | FirstOrderUpwind, 27 | CentralDifference, 28 | MinMod 29 | }; 30 | enum class vecFormat: unsigned char { 31 | ROWMAJOR, 32 | COLMAJOR 33 | }; 34 | } 35 | #endif -------------------------------------------------------------------------------- /Code.v05-00/include/EPM/Models/Original/Indexes.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EPM_MODELS_ORIGINALIMPL_INDEXES_H_INCLUDED 2 | #define EPM_MODELS_ORIGINALIMPL_INDEXES_H_INCLUDED 3 | 4 | namespace EPM::Models::OriginalImpl { 5 | 6 | // Indices for the gas-aerosol system 7 | enum EPM_ind { 8 | EPM_ind_Trac = 0, // Tracer 9 | EPM_ind_T, // Temperature 10 | EPM_ind_P, // Pressure 11 | EPM_ind_H2O, // Water vapor mixing ratio 12 | EPM_ind_SO4, // Sulfate gas mixing ratio 13 | EPM_ind_SO4l, // Sulfate liquid mixing ratio 14 | EPM_ind_SO4g, // Sulfate gas mixing ratio 15 | EPM_ind_SO4s, // Sulfate solid mixing ratio 16 | EPM_ind_HNO3, // Nitric acid mixing ratio 17 | EPM_ind_Part, // Particle mixing ratio 18 | EPM_ind_ParR, // Particle radius 19 | EPM_ind_the1, // Surface coverage 1 20 | EPM_ind_the2 // Surface coverage 2 21 | }; 22 | 23 | } // namespace EPM::Models::OriginalImpl 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /scripts/simple_met_input/main.py: -------------------------------------------------------------------------------- 1 | from src.met import make_idealised_met 2 | import matplotlib.pyplot as plt 3 | 4 | ######################### MAIN FUNCTION (EXAMPLE) ######################### 5 | 6 | if __name__ == "__main__": 7 | met = make_idealised_met( 8 | centre_altitude_m=10000, # m 9 | moist_depth_m=1000, # m 10 | RHi_background_PC=40, # m 11 | RHi_peak_PC=140, # % 12 | grad_RHi_PC_per_m=None, # % RHi / m; None indicates a rectangular moist region 13 | alt_resolution_m=100, # m 14 | upper_alt_m=11001, # m 15 | shear_over_s=2e-3, # 1/s 16 | T_offset_K=0, # K 17 | filename_prefix="example", 18 | ) 19 | 20 | RHi_PC = met.relative_humidity_ice.to_numpy() 21 | alt_m = met.altitude.to_numpy() * 1e3 # km to m 22 | 23 | plt.plot(RHi_PC, alt_m, color="b", lw=1.5) 24 | plt.ylabel("Altitude, m") 25 | plt.xlabel("RHi, %") 26 | plt.yticks([9000, 9500, 10000, 10500, 11000]) 27 | plt.ylim(9000, 11000) 28 | plt.xlim(0, 150) 29 | plt.show() 30 | -------------------------------------------------------------------------------- /Code.v05-00/include/EPM/Models/Original/StateObserver.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EPM_MODELS_ORIGINALIMPL_STATEOBSERVER_H_INCLUDED 2 | #define EPM_MODELS_ORIGINALIMPL_STATEOBSERVER_H_INCLUDED 3 | 4 | #include 5 | #include 6 | 7 | #include "Util/ForwardDecl.hpp" 8 | 9 | namespace EPM::Models::OriginalImpl 10 | { 11 | class StateObserver 12 | { 13 | public: 14 | StateObserver( 15 | Vector_2D &states, Vector_1D ×, 16 | std::vector indices, 17 | std::string fileName, UInt write_every = 100); 18 | StateObserver& operator=(const StateObserver &obs); 19 | void operator()(const Vector_1D &x, double t); 20 | double getLastElement() const; 21 | void print2File() const; 22 | bool checkwatersat() const; 23 | 24 | UInt m_write_every; 25 | UInt m_count = 0; 26 | std::string fileName; 27 | 28 | Vector_2D &m_states; 29 | Vector_1D &m_times; 30 | 31 | private: 32 | const std::vector m_indices; 33 | }; 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Massachusetts Institute of Technology 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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. 8 | -------------------------------------------------------------------------------- /Code.v05-00/include/Util/Error.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* Error Header File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 10/17/2018 */ 10 | /* File : Error.hpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #ifndef ERROR_H_INCLUDED 15 | #define ERROR_H_INCLUDED 16 | 17 | extern "C" bool SafeDiv( double num, double denom ); 18 | 19 | #endif /* ERROR_H_INCLUDED */ 20 | -------------------------------------------------------------------------------- /Code.v05-00/include/Util/VectorUtils.hpp: -------------------------------------------------------------------------------- 1 | #ifndef VECTORUTILS_H 2 | #define VECTORUTILS_H 3 | 4 | #include 5 | #include "Util/ForwardDecl.hpp" 6 | 7 | namespace VectorUtils { 8 | using std::vector; 9 | 10 | void set_shape(Vector_2D &vec, const UInt n_x, const UInt n_y, const double value = 0.0); 11 | void set_value(Vector_2D &vec, const double value = 0.0); 12 | 13 | Vector_2D cellAreas(const Vector_1D &xEdges, const Vector_1D &yEdges); 14 | 15 | double min(const Vector_2D &vec); 16 | 17 | double max(const Vector_2D &vec); 18 | Vector_1D max(const Vector_2D &vec, int axis); 19 | 20 | struct MaskInfo { 21 | int count; 22 | double maxX; 23 | double maxY; 24 | double minX; 25 | double minY; 26 | }; 27 | 28 | std::pair>, int> mask(const Vector_2D& vec, std::function maskFunc); 29 | std::pair>, MaskInfo> mask(const Vector_2D& vec, const Vector_1D& xEdges, const Vector_1D& yEdges, std::function maskFunc); 30 | } 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /Code.v05-00/src/Core/Input_Mod.cpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* Input_Mod Program File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 12/12/2018 */ 10 | /* File : Input_Mod.cpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #include "Core/Input_Mod.hpp" 15 | 16 | OptInput::OptInput() { 17 | 18 | /* Default constructor */ 19 | 20 | } /* End of OptInput::OptInput */ 21 | 22 | /* End of Input_Mod.cpp */ -------------------------------------------------------------------------------- /Code.v05-00/include/Core/Monitor.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* Monitor Header File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 7/26/2018 */ 10 | /* File : Monitor.hpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #ifndef MONITOR_H_INCLUDED 15 | #define MONITOR_H_INCLUDED 16 | 17 | #include "KPP/KPP_Parameters.h" 18 | 19 | /* Index declaration for aerosol */ 20 | 21 | #define ind_SOOT 0 22 | 23 | #endif /* MONITOR_H_INCLUDED */ 24 | -------------------------------------------------------------------------------- /Code.v05-00/include/AIM/Settling.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* AIrcraft Microphysics */ 4 | /* (AIM) */ 5 | /* */ 6 | /* Settling Header File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 10/31/2018 */ 10 | /* File : Settling.hpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #ifndef SETTLING_H_INCLUDED 15 | #define SETTLING_H_INCLUDED 16 | 17 | #include "Util/ForwardDecl.hpp" 18 | 19 | namespace AIM 20 | { 21 | 22 | Vector_1D SettlingVelocity( const Vector_1D binCenters, const double T, const double P ); 23 | 24 | } 25 | 26 | #endif /* SETTLING_H_INCLUDED */ 27 | -------------------------------------------------------------------------------- /Code.v05-00/tests/test_integrate.cpp: -------------------------------------------------------------------------------- 1 | #include "EPM/Utils/Physics.hpp" 2 | #include 3 | #include 4 | 5 | using namespace EPM::Utils::Physics; 6 | 7 | TEST_CASE("EPM integrate", "[single-file]") { 8 | 9 | SECTION("Integrate") { 10 | 11 | 12 | } 13 | 14 | SECTION("RunMicrophysics") { 15 | 16 | 17 | } 18 | 19 | 20 | SECTION("Entrainment rate") { 21 | // Data from Karcher 1995 Figure 1 22 | // Act more like order of magnitude tests 23 | REQUIRE(entrainmentRate(0.0144) == Catch::Approx(40.82).epsilon(0.5)); 24 | REQUIRE(entrainmentRate(0.311) == Catch::Approx(2.488).epsilon(0.5)); 25 | REQUIRE(entrainmentRate(21.54) == Catch::Approx(0.01789).epsilon(0.5)); 26 | REQUIRE(entrainmentRate(377.67) == Catch::Approx(0.00328).epsilon(0.5)); 27 | REQUIRE(entrainmentRate(14762.3) == Catch::Approx(0.00006645468400721386).epsilon(0.5)); 28 | } 29 | 30 | SECTION("Deposition rate") { 31 | 32 | 33 | } 34 | 35 | SECTION("odeRHS") { 36 | 37 | } 38 | 39 | SECTION("isFreezable") { 40 | 41 | } 42 | 43 | SECTION("Condensation rate") { 44 | 45 | } 46 | 47 | 48 | } 49 | 50 | 51 | -------------------------------------------------------------------------------- /Code.v05-00/include/Core/Status.hpp: -------------------------------------------------------------------------------- 1 | // Enum to monitor the return status of APCEMM 2 | #ifndef STATUS_H_INCLUDED 3 | #define STATUS_H_INCLUDED 4 | 5 | enum class SimStatus : int { 6 | // Exit status: Contrail formed and disappeared before APCEMM reached max simulation timestep 7 | Complete, 8 | // Exit status: Contrail formed but did not disappear before APCEMM reached max simulation timestep 9 | Incomplete, 10 | // Exit status: No contrail formation due to not satisfying SAC 11 | NoWaterSaturation, 12 | // Exit status: Contrail forms but does not persist because RHi < 1 13 | // This status may need more thought if APCEMM is used for plume chemistry 14 | // regardless of contrail formation 15 | NoPersistence, 16 | // Exit status: Ice crystals do not survive vortex sinking 17 | NoSurvivalVortex, 18 | // Exit status: Simulation failed, placeholder to replace iERR < 0. In practice, iERR was never 19 | // assigned a negative (error) value in Main.cpp 20 | Failed, 21 | 22 | // Intermediary status: EPM completed and contrail forms, simulation can proceed to vortex parametrization 23 | // and then continue to transport model 24 | EPMSuccess, 25 | }; 26 | 27 | #endif // STATUS_H_INCLUDED 28 | -------------------------------------------------------------------------------- /Code.v05-00/include/EPM/EPM.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EPM_HPP_INCLUDED 2 | #define EPM_HPP_INCLUDED 3 | 4 | #include 5 | 6 | #include "AIM/Aerosol.hpp" 7 | #include "Core/Aircraft.hpp" 8 | #include "Core/Emission.hpp" 9 | #include "Core/Input.hpp" 10 | #include "Core/Input_Mod.hpp" 11 | #include "Core/MPMSimVarsWrapper.hpp" 12 | #include "Core/Meteorology.hpp" 13 | 14 | 15 | namespace EPM { 16 | struct Output { 17 | double finalTemp; 18 | double iceRadius; 19 | double iceDensity; 20 | double sootDensity; 21 | double H2O_mol; 22 | double SO4g_mol; 23 | double SO4l_mol; 24 | AIM::Aerosol SO4Aer; 25 | AIM::Aerosol IceAer; 26 | double area; 27 | double bypassArea; 28 | double coreExitTemp; 29 | 30 | void write(std::string filename) const; 31 | void read(std::string filename); 32 | }; 33 | 34 | namespace Models { 35 | class Base; 36 | class Original; 37 | class NewPhysics; 38 | class External; 39 | } 40 | 41 | std::unique_ptr make_epm( 42 | const OptInput &optInput, const Input &input, 43 | const Aircraft &aircraft, const Emission &EI, 44 | const Meteorology &met, const MPMSimVarsWrapper &simVars); 45 | 46 | } 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /Code.v05-00/include/Util/MC_Rand.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* MC_Rand Header File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 1/25/2019 */ 10 | /* File : MC_Rand.hpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #ifndef MC_RAND_H_INCLUDED 15 | #define MC_RAND_H_INCLUDED 16 | 17 | #include 18 | #include "Core/Input_Mod.hpp" 19 | 20 | /* Set seed for pseudo-random generator */ 21 | void setSeed(const OptInput& input); 22 | 23 | /* Generates a random number of type T between fMin and fMax */ 24 | template 25 | T fRand(const T fMin, const T fMax); 26 | 27 | #endif /* MC_RAND_H_INCLUDED */ 28 | -------------------------------------------------------------------------------- /Code.v05-00/include/Util/ForwardDecl.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* ForwardDecl Header File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 10/1/2018 */ 10 | /* File : ForwardDecl.hpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #ifndef FORWARDDECL_H_INCLUDED 15 | #define FORWARDDECL_H_INCLUDED 16 | 17 | #include 18 | 19 | /* List typedefs */ 20 | typedef unsigned int UInt; 21 | 22 | /* List vector typedefs */ 23 | typedef std::vector Vector_1D; 24 | typedef std::vector Vector_2D; 25 | typedef std::vector Vector_3D; 26 | typedef std::vector Vector_1Dui; 27 | typedef std::vector Vector_2Dui; 28 | 29 | #endif /* FORWARDDECL_H_INCLUDED */ 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/*.a 2 | **/*.pl 3 | **/_deps/ 4 | **/generated-includes/ 5 | **/Makefile 6 | **/APCEMM_out/ 7 | **/*.cmake 8 | **/*.tcl 9 | 10 | APCEMM 11 | unittest 12 | 13 | # Compiled source # 14 | ################### 15 | *.com 16 | *.dll 17 | *.exe 18 | *.o 19 | *.so 20 | 21 | # KPP files # 22 | ############# 23 | *.kpp 24 | *.map 25 | 26 | # Packages # 27 | ############ 28 | *.7z 29 | *.gz 30 | *.jar 31 | *.rar 32 | *.tar 33 | *.zip 34 | 35 | # Logs # 36 | ######## 37 | *.log 38 | *.sql 39 | *.out 40 | 41 | # OS generated files # 42 | ###################### 43 | .DS_Store 44 | .DS_Store? 45 | ._* 46 | .Trashes 47 | Thumbs.db 48 | 49 | # Some Shell files # 50 | #################### 51 | *.mp 52 | *.sp 53 | rundirs/*/APCEMM 54 | 55 | # Folders # 56 | ########### 57 | /build 58 | Code*/build 59 | Code*/trash 60 | Code*/lib* 61 | Code*/debug* 62 | rundirs/* 63 | !rundirs/SampleRunDir 64 | !rundirs/CreateRunFolder.sh 65 | 66 | # netCDF files # 67 | ################ 68 | *.nc 69 | !examples/Example3_met_input/example_met_file.nc 70 | !Code*/tests/test_meteorology_metfile.nc 71 | 72 | # Debug files # 73 | ############### 74 | gdb* 75 | valgrind* 76 | 77 | # For UNIX # 78 | ############ 79 | *~ 80 | .envrc 81 | .cache 82 | compile_commands.json 83 | 84 | # Cmake files # 85 | CMakeFiles 86 | CMakeCache.txt 87 | cmake_install.cmake 88 | 89 | /Code.v05-00/vcpkg_installed/ 90 | /Code.v05-00/include/APCEMM.h 91 | -------------------------------------------------------------------------------- /Code.v05-00/include/EPM/Models/Base.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EPM_MODELS_BASE_HPP_INCLUDED 2 | #define EPM_MODELS_BASE_HPP_INCLUDED 3 | 4 | #include 5 | 6 | #include "Core/Input.hpp" 7 | #include "Core/Input_Mod.hpp" 8 | #include "Core/Status.hpp" 9 | #include "EPM/EPM.hpp" 10 | 11 | 12 | namespace EPM::Models { 13 | 14 | class Base { 15 | public: 16 | Base() = delete; 17 | Base(const OptInput &optInput, const Input &input, 18 | const Aircraft &aircraft, const Emission &EI, 19 | const Meteorology &met, const MPMSimVarsWrapper &simVars): 20 | optInput_(optInput), input_(input), 21 | aircraft_(aircraft), EI_(EI), met_(met), simVars_(simVars) {} 22 | virtual ~Base() = default; 23 | 24 | // Disable copy and move semantics: EPM model instances will only ever be 25 | // accessed via std::unique_ptr values. 26 | Base(const Base &) = delete; 27 | Base &operator=(const Base &) = delete; 28 | Base(Base &&) = delete; 29 | Base &operator=(Base &&) = delete; 30 | 31 | // Virtual function to be overridden by derived classes 32 | virtual std::variant run() = 0; 33 | 34 | protected: 35 | const OptInput &optInput_; 36 | const Input &input_; 37 | const Aircraft &aircraft_; 38 | const Emission &EI_; 39 | const Meteorology &met_; 40 | const MPMSimVarsWrapper &simVars_; 41 | }; 42 | 43 | } // namespace EPM::Models 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /Code.v05-00/include/Core/ReadJRates.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* ReadJRates Header File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 1/16/2019 */ 10 | /* File : ReadJRates.hpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #ifndef READJRATES_H_INCLUDED 15 | #define READJRATES_H_INCLUDED 16 | 17 | #include 18 | #include 19 | 20 | using namespace netCDF; 21 | using namespace netCDF::exceptions; 22 | 23 | void ReadJRates( const char* ROOTDIR, \ 24 | const unsigned int MM, const unsigned int DD, \ 25 | const double LON, const double LAT, \ 26 | const double P_hPa, \ 27 | double NOON_JRATES[] ); 28 | 29 | #endif /* READJREATES_H_INCLUDED */ 30 | -------------------------------------------------------------------------------- /Code.v05-00/include/AIM/Nucleation.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* AIrcraft Microphysics */ 4 | /* (AIM) */ 5 | /* */ 6 | /* Nucleation Header File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 10/1/2018 */ 10 | /* File : Nucleation.hpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #ifndef NUCLEATION_H_INCLUDED 15 | #define NUCLEATION_H_INCLUDED 16 | 17 | #include 18 | 19 | namespace AIM 20 | { 21 | 22 | double sigma( double x_m, double T ); 23 | double rho( double x_m, double T ); 24 | double x_star( double T, double RH, double nSulf ); 25 | double nuclRate( double T, double x_m, double RH, double nSulf ); 26 | double nTot( double T, double x_m, double RH, double nSulf ); 27 | double radCluster( double x_m, double n ); 28 | double nThresh( double T, double RH ); 29 | 30 | } 31 | 32 | #endif /* NUCLEATION_H_INCLUDED */ 33 | -------------------------------------------------------------------------------- /Code.v05-00/include/Core/Util.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* Util Header File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 7/26/2018 */ 10 | /* File : Util.hpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #ifndef UTIL_H_INCLUDED 15 | #define UTIL_H_INCLUDED 16 | 17 | #include 18 | 19 | namespace util 20 | { 21 | double* vect2double( const std::vector> &vals, unsigned int N, unsigned int M ); 22 | 23 | float* vect2float( const std::vector>> &vals, unsigned int N1, unsigned int N2, unsigned int N3 ); 24 | float* vect2float( const std::vector> &vals, unsigned int N, unsigned int M ); 25 | float* vect2float( const std::vector &vals, unsigned int N ); 26 | } 27 | 28 | #endif /* UTIL_H_INCLUDED */ 29 | -------------------------------------------------------------------------------- /Code.v05-00/include/Core/Ring.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* Ring Header File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 8/12/2018 */ 10 | /* File : Ring.hpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #ifndef RING_H_INCLUDED 15 | #define RING_H_INCLUDED 16 | 17 | class Ring 18 | { 19 | 20 | public: 21 | 22 | Ring( ); 23 | Ring( double a, double b ); 24 | Ring( const Ring &r ); 25 | Ring& operator=( const Ring &r ); 26 | ~Ring( ); 27 | void Assign( double a, double b ); 28 | void Print( ) const; 29 | double getHAxis( ) const; 30 | double getVAxis( ) const; 31 | 32 | protected: 33 | 34 | double horizontalAxis; 35 | double verticalAxis; 36 | 37 | private: 38 | 39 | }; 40 | 41 | #endif /* RING_H_INCLUDED */ 42 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile.apcemm: -------------------------------------------------------------------------------- 1 | FROM --platform=linux/amd64 gcc:11.2 as builder 2 | 3 | RUN apt-get update \ 4 | && apt-get install -y \ 5 | build-essential \ 6 | ca-certificates \ 7 | curl \ 8 | libssl-dev \ 9 | zlib1g-dev \ 10 | libcurl4-openssl-dev \ 11 | libfftw3-dev \ 12 | libnetcdf-dev \ 13 | libnetcdf-c++4-dev \ 14 | locales \ 15 | make \ 16 | python3-venv \ 17 | sudo \ 18 | zsh \ 19 | autoconf \ 20 | automake \ 21 | libtool \ 22 | zip \ 23 | unzip \ 24 | tar 25 | 26 | RUN apt-get clean \ 27 | && rm -rf /var/lib/apt/lists/* \ 28 | && apt-get update \ 29 | && apt-get install gettext -y 30 | 31 | RUN locale-gen en_US.UTF-8 32 | 33 | RUN wget https://github.com/Kitware/CMake/releases/download/v3.30.3/cmake-3.30.3-Linux-x86_64.sh \ 34 | -q -O /tmp/cmake-install.sh \ 35 | && chmod u+x /tmp/cmake-install.sh \ 36 | && mkdir /opt/cmake-3.30.3 \ 37 | && /tmp/cmake-install.sh --skip-license --prefix=/opt/cmake-3.30.3 \ 38 | && rm /tmp/cmake-install.sh \ 39 | && ln -s /opt/cmake-3.30.3/bin/* /usr/local/bin 40 | 41 | RUN zsh -c 'git clone --depth 1 --recursive https://github.com/sorin-ionescu/prezto.git "${ZDOTDIR:-$HOME}/.zprezto"' && \ 42 | cd ${ZDOTDIR:-$HOME}/.zprezto && \ 43 | git pull && \ 44 | git submodule sync --recursive && \ 45 | git submodule update --init --recursive && \ 46 | zsh -c 'setopt EXTENDED_GLOB; for rcfile in "${ZDOTDIR:-$HOME}"/.zprezto/runcoms/^README.md(.N); do ln -s "$rcfile" "${ZDOTDIR:-$HOME}/.${rcfile:t}"; done' && \ 47 | chsh -s /bin/zsh 48 | 49 | CMD ["/usr/sbin/sshd", "-D", "-e", "-f", "/etc/ssh/sshd_config"] -------------------------------------------------------------------------------- /Code.v05-00/include/LAGRID/FreeCoordBoxGrid.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LAGRID_FREECOORDBOXGRID_H 2 | #define LAGRID_FREECOORDBOXGRID_H 3 | 4 | #include "Util/ForwardDecl.hpp" 5 | 6 | namespace LAGRID { 7 | using std::vector; 8 | struct MassBox { 9 | MassBox(double tlx, double tly, double brx, double bry, double mass): 10 | topLeftX(tlx), topLeftY(tly), botRightX(brx), botRightY(bry), mass(mass) 11 | { 12 | 13 | } 14 | double topLeftX; 15 | double topLeftY; 16 | double botRightX; 17 | double botRightY; 18 | double mass; // mass = phi * dy * dx where phi is a concentration 19 | inline const double area() const { 20 | return (botRightX - topLeftX) * (topLeftY - botRightY); 21 | } 22 | }; 23 | struct FreeCoordBoxGrid { 24 | FreeCoordBoxGrid() = delete; 25 | //Can apply a mask to the cutoff, and then can easily find the boundary nodes in O(N) time using the 0/1 mask. 26 | FreeCoordBoxGrid(const Vector_1D& dx, const Vector_1D& dy, const Vector_2D& phi, const Vector_1D& x0, double y0, double cutoff); 27 | FreeCoordBoxGrid(const Vector_1D& dx, const Vector_1D& dy, const Vector_2D& phi, const Vector_1D& x0, double y0, const vector>& mask); 28 | 29 | void setMinMaxCoords(); 30 | std::vector boxes; 31 | std::vector boundaryBoxIndices; //To speed up the remapping algorithm 32 | double minX; 33 | double minY; 34 | double maxX; 35 | double maxY; 36 | 37 | 38 | 39 | }; 40 | } 41 | 42 | #endif -------------------------------------------------------------------------------- /Code.v05-00/src/FVM_ANDS/BoundaryCondition.cpp: -------------------------------------------------------------------------------- 1 | #include "FVM_ANDS/BoundaryCondition.hpp" 2 | 3 | namespace FVM_ANDS { 4 | Point::Point(BoundaryConditionFlag bcType){ 5 | bc_ = BoundaryCondDescription(bcType); 6 | } 7 | Point::Point(BoundaryCondDescription bcDesc){ 8 | bc_ = bcDesc; 9 | } 10 | 11 | GhostPoint::GhostPoint(BoundaryCondDescription bc) { 12 | const bool is_ghost_flag = static_cast(bc.bcType) > 100; 13 | if(!is_ghost_flag){ 14 | bc.bcType = static_cast(static_cast(bc.bcType) + 100); 15 | } 16 | setBC(bc); 17 | } 18 | IntBoundPoint::IntBoundPoint(BoundaryCondDescription bc1) 19 | : Point(bc1) { 20 | secondary_bc_= std::nullopt; 21 | } 22 | IntBoundPoint::IntBoundPoint(BoundaryCondDescription bc1, BoundaryCondDescription bc2) 23 | : Point(bc1) { 24 | secondary_bc_ = bc2; 25 | } 26 | 27 | BoundaryCondDescription::BoundaryCondDescription() 28 | : bcType(BoundaryConditionFlag::ERROR), 29 | direction(FaceDirection::ERROR), 30 | bcVal(-1), 31 | corrPoint(-1){ 32 | 33 | } 34 | BoundaryCondDescription::BoundaryCondDescription(BoundaryConditionFlag bcType) 35 | : bcType(bcType), 36 | direction(FaceDirection::ERROR), 37 | bcVal(-1), 38 | corrPoint(-1){ 39 | 40 | } 41 | BoundaryCondDescription::BoundaryCondDescription(BoundaryConditionFlag bcType, FaceDirection direction, double bcVal, int corrPoint) 42 | : bcType(bcType), 43 | direction (direction), 44 | bcVal (bcVal), 45 | corrPoint(corrPoint){ 46 | 47 | } 48 | } -------------------------------------------------------------------------------- /Code.v05-00/src/Util/YamlUtils.cpp: -------------------------------------------------------------------------------- 1 | #include "Util/YamlUtils.hpp" 2 | 3 | #include 4 | 5 | 6 | // Adapted from https://stackoverflow.com/a/66205210 7 | 8 | const YAML::Node mergeYamlNodes(const YAML::Node& defaults, const YAML::Node& overrides) 9 | { 10 | // If overrides is not a map, merge result is overrides, unless overrides 11 | // is null. 12 | if (!overrides.IsMap()) return overrides.IsNull() ? defaults : overrides; 13 | 14 | // If defaults is not a map, merge result is overrides. 15 | if (!defaults.IsMap()) return overrides; 16 | 17 | if (!defaults.size()) return YAML::Node(overrides); 18 | 19 | // Create a new map 'newNode' with the same mappings as defaults, merged 20 | // with overrides. 21 | auto newNode = YAML::Node(YAML::NodeType::Map); 22 | for (auto node : defaults) { 23 | if (node.first.IsScalar()) { 24 | const std::string& key = node.first.Scalar(); 25 | if (overrides[key]) { 26 | newNode[node.first] = mergeYamlNodes(node.second, overrides[key]); 27 | continue; 28 | } 29 | } 30 | newNode[node.first] = node.second; 31 | } 32 | 33 | // Add the mappings from 'overrides' not already in 'newNode'. 34 | for (auto node : overrides) { 35 | if (!node.first.IsScalar()) { 36 | const std::string& key = node.first.Scalar(); 37 | if (defaults[key]) { 38 | newNode[node.first] = mergeYamlNodes(defaults[key], node.second); 39 | continue; 40 | } 41 | } 42 | newNode[node.first] = node.second; 43 | } 44 | 45 | return YAML::Node(newNode); 46 | } 47 | -------------------------------------------------------------------------------- /Code.v05-00/include/EPM/Utils/Physics.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EPM_UTILS_PHYSICS_H_INCLUDED 2 | #define EPM_UTILS_PHYSICS_H_INCLUDED 3 | 4 | namespace EPM::Utils::Physics { 5 | 6 | /* Vortex sinking timescales, taken from Unterstrasser et al., 2008 */ 7 | const double t_Vortex_0 = 8.00E+00; 8 | const double t_Vortex_1 = 1.10E+02; 9 | 10 | /* Dilution timescales for a B747, taken from: 11 | * B. Kärcher, "A trajectory box model for aircraft exhaust plumes", Journal of Geophysical Research, 1995 */ 12 | const double t_0 = 1.00E-04; /* [s], */ 13 | const double t_j = 1.00E-02; /* [s], */ 14 | const double t_1 = 8.00E+00; /* [s], Transition to vortex regime */ 15 | const double t_2 = 6.60E+01; /* [s], Transition to dispersion regime */ 16 | 17 | const double m = 2.0; 18 | const double n = 50.0; 19 | const double Cv = 3.0; 20 | 21 | /* Engine exit plane characteristics for a B747, taken from: 22 | * B. Kärcher, "A trajectory box model for aircraft exhaust plumes", Journal of Geophysical Research, 1995 */ 23 | /* Engine exit core area im m^2 */ 24 | const double Ac0 = 0.604; 25 | /* Engine exit core velocity in m/s */ 26 | const double uc0 = 475.7; 27 | /* Engine exit core temperature in K */ 28 | /* const double Tc0 = 547.3; */ 29 | /* double Tc0 */ 30 | /* Engine exit bypass area in m^2 */ 31 | /* const double Ab0 = 1.804; */ 32 | /* double Ab0 */ 33 | 34 | double entrainmentRate(const double time); 35 | double depositionRate(const double r, const double T, const double P, const double H2O, 36 | const double r_0, const double theta ); 37 | double dT_Vortex(const double time, const double delta_T, bool deriv = 0); 38 | bool isFreezable(const double r, const double T, const double H2O, 39 | const double r0); 40 | double condensationRate(const double r, const double T, const double P, 41 | const double H2O, const double theta); 42 | 43 | } // namespace EPM::Utils::Physics 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /Code.v05-00/include/Core/Fuel.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* Fuel Header File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 7/26/2018 */ 10 | /* File : Fuel.hpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #ifndef FUEL_H_INCLUDED 15 | #define FUEL_H_INCLUDED 16 | 17 | #include 18 | #include 19 | 20 | class Fuel 21 | { 22 | public: 23 | 24 | Fuel( ); 25 | Fuel( const char *fuelName ); 26 | Fuel( const Fuel &f ); 27 | Fuel& operator=( const Fuel &f ); 28 | ~Fuel( ); 29 | void getAtoms( const char *fuelChem ); 30 | double getAtomC() const; 31 | double getAtomH() const; 32 | double getAtomN() const; 33 | double getAtomS() const; 34 | double getFSC() const; 35 | void setFSC( const double FSC_ ); 36 | std::string getChemFormula() const; 37 | 38 | protected: 39 | 40 | /* Atomic composition: CxHy */ 41 | double atomC; 42 | double atomH; 43 | double atomN; 44 | double atomS; 45 | 46 | /* Sulfur content */ 47 | double FSC; /* [ppm] */ 48 | 49 | std::string ChemFormula; 50 | 51 | private: 52 | 53 | }; 54 | 55 | #endif /* FUEL_H_INCLUDED */ 56 | -------------------------------------------------------------------------------- /Code.v05-00/src/Util/Error.cpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* Error Program File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 10/17/2018 */ 10 | /* File : Error.cpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #include 15 | #include "Util/Error.hpp" 16 | 17 | bool SafeDiv( double num, double denom ) 18 | { 19 | 20 | //typedef std::numeric_limits limits; 21 | typedef std::numeric_limits limits; 22 | 23 | if ( denom == 0 ) { 24 | return 0; 25 | } else { 26 | if ( ( (num / denom) > limits::max() ) || ( (num/denom) < limits::min() ) ) 27 | return 0; 28 | else 29 | return 1; 30 | } 31 | 32 | } /* End of SafeDiv */ 33 | 34 | // bool SafeDiv( float num, float denom ) 35 | // { 36 | // 37 | // //typedef std::numeric_limits limits; 38 | // typedef std::numeric_limits limits; 39 | // 40 | // if ( denom == 0 ) { 41 | // return 0; 42 | // } else { 43 | // if ( ( (num / denom) > limits::max() ) || ( (num/denom) < limits::min() ) ) 44 | // return 0; 45 | // else 46 | // return 1; 47 | // } 48 | // 49 | // } /* End of SafeDiv */ 50 | 51 | //} 52 | 53 | /* End of Error.cpp */ 54 | -------------------------------------------------------------------------------- /Code.v05-00/src/EPM/Models/Original/Model.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "EPM/Models/Original.hpp" 4 | #include "EPM/EPM.hpp" 5 | #include "EPM/Solution.hpp" 6 | #include "KPP/KPP_Parameters.h" 7 | #include "Util/PhysConstant.hpp" 8 | 9 | using physConst::kB; 10 | 11 | 12 | namespace EPM::Models { 13 | 14 | Original::Original(const OptInput &optInput, const Input &input, const Aircraft &aircraft, 15 | const Emission &EI, const Meteorology &met, 16 | const MPMSimVarsWrapper &simVars) : 17 | Base(optInput, input, aircraft, EI, met, simVars), VAR_(NVAR) 18 | { } 19 | 20 | std::variant Original::run() { 21 | // This is used for initializing the EPM solution. The only thing that 22 | // gets taken from it in the end is the soot density. 23 | EPM::Solution epmSolution(optInput_); 24 | 25 | /* Compute airDens from pressure and temperature */ 26 | double airDens = simVars_.pressure_Pa / (kB * met_.tempRef()) * 1.00E-06; 27 | // [molec/cm3] = [Pa = J/m3] / ([J/K] * [K]) * [m3/cm3] 28 | 29 | /* This sets the species array values in the Solution data structure to the 30 | ambient data file, EXCEPT FOR H2O which is user defined via met input or 31 | rhw input */ 32 | epmSolution.Initialize( 33 | simVars_.BACKG_FILENAME.c_str(), input_, airDens, met_, 34 | optInput_, VAR_, false); 35 | 36 | double dy = 37 | (optInput_.ADV_GRID_YLIM_UP + optInput_.ADV_GRID_YLIM_DOWN) / 38 | optInput_.ADV_GRID_NY; 39 | double y0 = -optInput_.ADV_GRID_YLIM_DOWN; 40 | unsigned int i_0 = static_cast( 41 | std::floor(optInput_.ADV_GRID_XLIM_LEFT / 42 | optInput_.ADV_GRID_NX)); // index i where x = 0 43 | unsigned int j_0 = static_cast(std::floor(-y0 / dy)); // index j where y = 0 44 | 45 | // This sets the values in VAR_ to the values in the solution data 46 | // structure at indices i, j 47 | epmSolution.getData(VAR_, i_0, j_0); 48 | 49 | // Run EPM. 50 | return Integrate(epmSolution.getSootDensity()); 51 | } 52 | 53 | } // namespace EPM::Models 54 | -------------------------------------------------------------------------------- /Code.v05-00/src/Core/MPMSimVarsWrapper.cpp: -------------------------------------------------------------------------------- 1 | #include "Util/PhysFunction.hpp" 2 | #include "Core/MPMSimVarsWrapper.hpp" 3 | 4 | MPMSimVarsWrapper::MPMSimVarsWrapper(const Input& input, const OptInput& Input_Opt, const double depth_estimate): 5 | RUN_BOXMODEL(Input_Opt.SIMULATION_BOXMODEL), 6 | BUILD_LUT(Input_Opt.SIMULATION_PARAMETER_SWEEP), 7 | SAVE_FORWARD(Input_Opt.SIMULATION_SAVE_FORWARD), 8 | ADJOINT(Input_Opt.SIMULATION_ADJOINT), 9 | BACKG_FILENAME(Input_Opt.SIMULATION_INPUT_BACKG_COND), 10 | THREADED_FFT(Input_Opt.SIMULATION_THREADED_FFT), 11 | USE_WISDOM(Input_Opt.SIMULATION_USE_FFTW_WISDOM), 12 | FFTW_DIR(Input_Opt.SIMULATION_DIRECTORY_W_WRITE_PERMISSION), 13 | TRANSPORT(Input_Opt.TRANSPORT_TRANSPORT), 14 | FILLNEG(Input_Opt.TRANSPORT_FILL), 15 | UPDRAFT(Input_Opt.TRANSPORT_UPDRAFT), 16 | UPDRAFT_TIME(Input_Opt.TRANSPORT_UPDRAFT_TIMESCALE), 17 | UPDRAFT_VEL(Input_Opt.TRANSPORT_UPDRAFT_VELOCITY), 18 | CHEMISTRY(Input_Opt.CHEMISTRY_CHEMISTRY), 19 | HETCHEM(Input_Opt.CHEMISTRY_HETCHEM), 20 | JRATE_FOLDER(Input_Opt.CHEMISTRY_JRATE_FOLDER), 21 | GRAVSETTLING(Input_Opt.AEROSOL_GRAVSETTLING), 22 | ICE_COAG(Input_Opt.AEROSOL_COAGULATION_SOLID), 23 | LIQ_COAG(Input_Opt.AEROSOL_COAGULATION_LIQUID), 24 | ICE_GROWTH(Input_Opt.AEROSOL_ICE_GROWTH), 25 | TEMP_PERTURB(Input_Opt.MET_ENABLE_TEMP_PERTURB), 26 | metDepth(depth_estimate), 27 | DIAG_FILENAME(Input_Opt.DIAG_FILENAME), 28 | TS_FOLDER(Input_Opt.SIMULATION_OUTPUT_FOLDER), 29 | TS_SPEC(Input_Opt.TS_SPEC), 30 | TS_SPEC_FILEPATH(TS_FOLDER + "/" + Input_Opt.TS_FILENAME), 31 | TS_SPEC_LIST(Input_Opt.TS_SPECIES), 32 | TS_FREQ(Input_Opt.TS_FREQ), 33 | TS_AERO(Input_Opt.TS_AERO), 34 | TS_AERO_FILEPATH(TS_FOLDER + "/" + Input_Opt.TS_AERO_FILENAME), 35 | TS_AERO_LIST(Input_Opt.TS_AEROSOL), 36 | TS_AERO_FREQ(Input_Opt.TS_AERO_FREQ), 37 | SAVE_PL(Input_Opt.PL_PL), 38 | SAVE_O3PL(Input_Opt.PL_O3), 39 | temperature_K(input.temperature_K()), 40 | pressure_Pa(input.pressure_Pa()), 41 | relHumidity_w(input.relHumidity_w()) 42 | 43 | 44 | { 45 | /* Compute relative humidity w.r.t ice */ 46 | relHumidity_i = relHumidity_w * physFunc::pSat_H2Ol( temperature_K )\ 47 | / physFunc::pSat_H2Os( temperature_K ); 48 | 49 | } 50 | 51 | -------------------------------------------------------------------------------- /Code.v05-00/include/Util/MolarWeights.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* MolarWeights Header File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 7/26/2018 */ 10 | /* File : MolarWeights.h */ 11 | /* Working directory : /home/fritzt/APCEMM-SourceCode */ 12 | /* */ 13 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 14 | 15 | 16 | #ifndef MOLARWEIGHTS_H_INCLUDED 17 | #define MOLARWEIGHTS_H_INCLUDED 18 | 19 | /* Molar weights, Unit : [ kg / mol ] */ 20 | #define MW_Air 28.9647E-03 21 | #define MW_O2 31.9988E-03 22 | #define MW_N2 28.0134E-03 23 | #define MW_N 14.0067E-03 24 | #define MW_CO2 44.0095E-03 25 | #define MW_CO 28.0101E-03 26 | #define MW_CH4 16.0425E-03 27 | #define MW_H2O 18.0153E-03 28 | #define MW_HNO3 63.0128E-03 29 | #define MW_S 32.0655E-03 30 | #define MW_H2SO4 98.0785E-03 31 | #define MW_SO4 96.0785E-03 32 | #define MW_SO2 64.0638E-03 33 | #define MW_NO 30.0061E-03 34 | #define MW_NO2 46.0055E-03 35 | #define MW_HNO2 47.0134E-03 36 | #define MW_C2H6 30.0690E-03 37 | #define MW_N2O5 108.010E-03 38 | #define MW_PRPE 42.0800E-03 39 | #define MW_ALK4 58.1230E-03 40 | #define MW_CH2O 30.0260E-03 41 | #define MW_ALD2 44.0530E-03 42 | #define MW_GLYX 58.0370E-03 43 | #define MW_MGLY 72.0640E-03 44 | #define MW_NIT 62.0000E-03 45 | #define MW_NAT 117.000E-03 46 | #define MW_BrNO3 141.909E-03 47 | #define MW_ClNO3 97.4579E-03 48 | #define MW_HOCl 52.4603E-03 49 | #define MW_HCl 36.4580E-03 50 | #define MW_HOBr 96.9110E-03 51 | #define MW_HBr 80.9119E-03 52 | 53 | #endif /* MOLARWEIGHTS_H_INCLUDED */ 54 | -------------------------------------------------------------------------------- /Code.v05-00/include/Core/Cluster.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* Cluster Header File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 8/12/2018 */ 10 | /* File : Cluster.hpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #ifndef CLUSTER_H_INCLUDED 15 | #define CLUSTER_H_INCLUDED 16 | 17 | #include 18 | #include 19 | #include "Core/Ring.hpp" 20 | #include "Util/ForwardDecl.hpp" 21 | 22 | class Cluster 23 | { 24 | 25 | public: 26 | 27 | Cluster( ); 28 | Cluster( const UInt n, const bool sRing, \ 29 | const double sigma1 = 0.0E+00, \ 30 | const double sigma2 = 0.0E+00, \ 31 | const double d1 = 0.0E+00, \ 32 | const double d2 = 0.0E+00 ); 33 | Cluster( const Cluster& cl ); 34 | Cluster& operator=( const Cluster& cl ); 35 | ~Cluster( ); 36 | 37 | void ComputeRingAreas( const Vector_2D &cellAreas, const Vector_3D &weights ); 38 | const UInt getnRing() const { return nR; } 39 | const bool halfRing() const { return semiRing; } 40 | const std::vector& getRings() const { return Rings; } 41 | const std::vector& getRingIndex() const { return ringIndices; } 42 | const Vector_1D& getRingArea( ) const { return ringAreas; } 43 | 44 | void PrintRings() const; 45 | void Debug() const; 46 | 47 | protected: 48 | 49 | UInt nR; 50 | bool semiRing; 51 | double sigmaX, sigmaY; 52 | double dH, dV; 53 | std::vector Rings; 54 | std::vector ringIndices; 55 | Vector_1D ringAreas; 56 | 57 | }; 58 | 59 | #endif /* CLUSTER_H_INCLUDED */ 60 | -------------------------------------------------------------------------------- /Code.v05-00/include/Core/SZA.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* SZA Header File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 10/18/2018 */ 10 | /* File : SZA.hpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #ifndef SZA_H_INCLUDED 15 | #define SZA_H_INCLUDED 16 | 17 | #ifdef __cplusplus 18 | 19 | #include 20 | 21 | class SZA 22 | { 23 | 24 | public: 25 | 26 | SZA( const double latitude, const unsigned int dayGMT ); 27 | ~SZA( ); 28 | 29 | void Update( const double solarTime ); 30 | double getCSZA( const double solarTime ); 31 | std::vector getSZA_Vector( ) const; 32 | 33 | const double latitude; 34 | const unsigned int dayGMT; 35 | 36 | double sunRise; 37 | double sunSet; 38 | 39 | double CSZA_max; 40 | double CSZA; 41 | 42 | std::vector CSZA_Vector; 43 | 44 | private: 45 | 46 | double const A0 = 0.006918; 47 | double const A1 = 0.399912; 48 | double const A2 = 0.006758; 49 | double const A3 = 0.002697; 50 | double const B1 = 0.070257; 51 | double const B2 = 0.000907; 52 | double const B3 = 0.000148; 53 | 54 | double DEC; 55 | double sinLAT; 56 | double cosLAT; 57 | double sinDEC; 58 | double cosDEC; 59 | 60 | }; 61 | 62 | #endif /* __cplusplus */ 63 | 64 | #ifdef __cplusplus 65 | extern "C" 66 | { 67 | #endif /* __cplusplus */ 68 | 69 | void* castSZA( SZA *sun ); 70 | double castCSZA( void *sun, const double solarTime ); 71 | 72 | #ifdef __cplusplus 73 | } 74 | #endif /* __cplusplus */ 75 | 76 | #endif /* SZA_H_INCLUDED */ 77 | -------------------------------------------------------------------------------- /Code.v05-00/src/FVM_ANDS/FVM_ANDS_HelperFunctions.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | namespace FVM_ANDS{ 3 | int twoDIdx_to_vecIdx(int idx_x, int idx_y, int nx, int ny, vecFormat format){ 4 | return (format == vecFormat::ROWMAJOR) ? 5 | idx_y * nx + idx_x : 6 | idx_x * ny + idx_y; 7 | } 8 | Eigen::VectorXd std2dVec_to_eigenVec(const Vector_2D& phi, vecFormat format){ 9 | //Doesn't create ghost nodes but its fine because AdvDiffSys constructor resizes. 10 | int ny = phi.size(); 11 | int nx = ny > 0 ? phi[0].size() : 0; 12 | Eigen::VectorXd vec(nx*ny); 13 | for(int i = 0; i < nx; i++){ 14 | for(int j = 0; j < ny; j++){ 15 | int vecIdx = twoDIdx_to_vecIdx(i, j, nx, ny, format); 16 | vec[vecIdx] = phi[j][i]; 17 | } 18 | } 19 | return vec; 20 | } 21 | Vector_2D eigenVec_to_std2dVec(Eigen::VectorXd eig_vec, int nx, int ny){ 22 | Vector_2D std2dVec(ny, Vector_1D(nx, 0)); 23 | for(int i = 0; i < nx; i++){ 24 | for(int j = 0; j < ny; j++){ 25 | std2dVec[j][i] = eig_vec(ny*i + j); 26 | } 27 | } 28 | return std2dVec; 29 | } 30 | BoundaryConditions bcFrom2DVector(const Vector_2D& initialVec, bool zeroBC){ 31 | int ny = initialVec.size(); 32 | int nx = initialVec[0].size(); 33 | BoundaryConditions bc; 34 | bc.bcType_top = BoundaryConditionFlag::DIRICHLET_INT_BPOINT; 35 | bc.bcType_left = BoundaryConditionFlag::DIRICHLET_INT_BPOINT; 36 | bc.bcType_right = BoundaryConditionFlag::DIRICHLET_INT_BPOINT; 37 | bc.bcType_bot = BoundaryConditionFlag::DIRICHLET_INT_BPOINT; 38 | bc.bcVals_top = Vector_1D(nx, 0); 39 | bc.bcVals_bot = Vector_1D(nx, 0); 40 | bc.bcVals_left = Vector_1D(ny, 0); 41 | bc.bcVals_right = Vector_1D(ny, 0); 42 | 43 | if(!zeroBC){ 44 | for(int i = 0; i < nx; i++){ 45 | bc.bcVals_top[i] = initialVec[ny-1][i]; 46 | bc.bcVals_bot[i] = initialVec[0][i]; 47 | } 48 | for(int j = 0; j < ny; j++){ 49 | bc.bcVals_left[j] = initialVec[j][0]; 50 | bc.bcVals_right[j] = initialVec[j][nx-1]; 51 | } 52 | } 53 | return bc; 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /Code.v05-00/src/Util/MC_Rand.cpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* MC_Rand Program File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 1/25/2019 */ 10 | /* File : MC_Rand.cpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | #include 14 | #include "APCEMM.h" 15 | #include "Util/MC_Rand.hpp" 16 | #include "Core/Input_Mod.hpp" 17 | 18 | void setSeed(const OptInput& input) { 19 | 20 | // Sets seed for pseudo-random generator. 21 | #ifdef DEBUG 22 | // With DEBUG compile flag set a constant seed for reproducibility 23 | std::cout << "Compiled in DEBUG mode: random seed is set to 0 for all simulations" << std::endl; 24 | srand(0); 25 | #else 26 | if(input.SIMULATION_FORCE_SEED){ 27 | srand(input.SIMULATION_SEED_VALUE); 28 | std::cout << "Random seed is set to " << input.SIMULATION_SEED_VALUE << " for all simulations" << std::endl; 29 | } 30 | else{ 31 | // If the seed is not being forced to a value use the current unix timestamp instead. 32 | srand(time(NULL)); 33 | } 34 | 35 | #endif 36 | 37 | } /* End of setSeed */ 38 | 39 | template 40 | T fRand(const T fMin, const T fMax) { 41 | 42 | /* Returns a random number between fMin and fMax */ 43 | 44 | double f = (double) rand()/RAND_MAX; 45 | return (T) fMin + f * (fMax - fMin); 46 | 47 | } /* End of fRand */ 48 | 49 | template double fRand(const double fMin, const double fMax); 50 | template float fRand(const float fMin, const float fMax); 51 | template int fRand(const int fMin, const int fMax); 52 | template unsigned int fRand(const unsigned int fMin, const unsigned int fMax); 53 | 54 | /* End of MC_Rand.cpp */ 55 | -------------------------------------------------------------------------------- /Code.v05-00/tests/test_aircraft.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "Util/PhysConstant.hpp" 9 | 10 | 11 | // std::string engineFileName = std::string(APCEMM_TESTS_DIR)+"/../../input_data/ENG_EI.txt"; 12 | // TEST_CASE("Vortex Losses Survival Fraction"){ 13 | // /* Comparing against results from Unterstrasser (2016) 14 | 15 | // Issue is that params like z_emit, N_BV, and beta (the parameter chosen in calculating z_desc) are arbitrarily chosen and hard coded. 16 | // Also, it's assumed that all soot particles become ice. 17 | // How to quantify this uncertainty? Therefore tests are just order of magnitude sanity checks. 18 | // Function works perfectly when the aforementioned parameters are manually prescribed. -Michael 19 | // */ 20 | // SECTION("Unterstrasser Table A2 #25"){ 21 | // //B747, EI_iceno = 2.8e14, 217 K, RH = 120%, N_BV = 0.015 s-1, z_atm = 148m, z_desc = 361m, z_emit = 98m 22 | // Aircraft aircraft("B747", engineFileName, 200000.0, 217.0, 22000.0, 148.0, 0.015); 23 | // double EI_ice_target = 2.8E14; 24 | // double EISootRad = 20.0E-9; 25 | // double volume = 4.0/3.0 * physConst::PI * pow(EISootRad, 3.0); 26 | // double mass = physConst::RHO_SOOT*volume*1.0E3; // convert to grams 27 | // double EI_soot = EI_ice_target * mass; 28 | // double z_atm = 148; 29 | 30 | // REQUIRE(aircraft.VortexLosses(EI_soot, EISootRad, z_atm) == Catch::Approx(0.506).margin(0.2)); 31 | // } 32 | // SECTION("Unterstrasser Table A2 #80"){ 33 | // //B747, EI_iceno = 1.22e15, 217 K, RH = 120%, N_BV = 0.015 s-1, z_atm = 148m, z_desc = 361m, z_emit = 98m 34 | // Aircraft aircraft("B747", engineFileName, 200000.0, 217.0, 22000.0, 148.0, 0.013); 35 | // double EI_ice_target = 1.22E15; 36 | // double EISootRad = 20.0E-9; 37 | // double volume = 4.0/3.0 * physConst::PI * pow(EISootRad, 3.0); 38 | // double mass = physConst::RHO_SOOT*volume*1.0E3; //convert to grams 39 | // double EI_soot = EI_ice_target * mass; 40 | // double z_atm = 148; 41 | 42 | // REQUIRE(aircraft.VortexLosses(EI_soot, EISootRad, z_atm) == Catch::Approx(0.218).margin(0.2)); 43 | // } 44 | 45 | // } 46 | -------------------------------------------------------------------------------- /Code.v05-00/src/Core/Util.cpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* Util Program File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 7/26/2018 */ 10 | /* File : Util.cpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #include "Core/Util.hpp" 15 | 16 | namespace util 17 | { 18 | double* vect2double( const std::vector> &vals, unsigned int N, unsigned int M ) 19 | { 20 | double* temp; 21 | temp = new double[N*M]; 22 | 23 | for( unsigned int n = 0; n < N; n++ ) { 24 | for( unsigned int m = 0; m < M; m++ ) 25 | temp[m + M*n] = vals[n][m]; 26 | } 27 | 28 | return temp; 29 | } 30 | 31 | float* vect2float( const std::vector>> &vals, unsigned int N1, unsigned int N2, unsigned int N3 ) 32 | { 33 | float* temp; 34 | temp = new float[N1*N2*N3]; 35 | 36 | for( unsigned int n1 = 0; n1 < N1; n1++ ) { 37 | for( unsigned int n2 = 0; n2 < N2; n2++ ){ 38 | for( unsigned int n3 = 0; n3 < N3; n3++ ) 39 | temp[n3 + N3*(n2 + N2*n1)] = (float) vals[n1][n2][n3]; 40 | } 41 | } 42 | 43 | return temp; 44 | } 45 | 46 | float* vect2float( const std::vector> &vals, unsigned int N, unsigned int M ) 47 | { 48 | float* temp; 49 | temp = new float[N*M]; 50 | 51 | for( unsigned int n = 0; n < N; n++ ) { 52 | for( unsigned int m = 0; m < M; m++ ) 53 | temp[m + M*n] = (float) vals[n][m]; 54 | } 55 | 56 | return temp; 57 | } 58 | 59 | float* vect2float( const std::vector &vals, unsigned int N ) 60 | { 61 | float* temp; 62 | temp = new float[N]; 63 | 64 | for( unsigned int n = 0; n < N; n++ ) 65 | temp[n] = (float) vals[n]; 66 | 67 | return temp; 68 | } 69 | } 70 | 71 | /* End of Util.cpp */ 72 | -------------------------------------------------------------------------------- /Code.v05-00/include/Core/Species.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* Species Header File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 7/26/2018 */ 10 | /* File : Species.hpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #ifndef SPECIES_H_INCLUDED 15 | #define SPECIES_H_INCLUDED 16 | 17 | #include "Util/ForwardDecl.hpp" 18 | 19 | class SpeciesArray 20 | { 21 | 22 | public: 23 | 24 | SpeciesArray( ); 25 | 26 | SpeciesArray( const UInt nRing, const UInt nTime, const bool halfRing = 0 ); 27 | 28 | SpeciesArray( const SpeciesArray &sp ); 29 | 30 | SpeciesArray& operator=( const SpeciesArray &sp ); 31 | 32 | SpeciesArray& operator+( const SpeciesArray &sp ); 33 | 34 | SpeciesArray& operator-( const SpeciesArray &sp ); 35 | 36 | ~SpeciesArray( ); 37 | 38 | /* FIXME: See comment in Ambient.hpp about classes modifying global state variables */ 39 | void getData( UInt iTime, UInt iRing, double* varSpeciesArray, double* fixSpeciesArray ); 40 | 41 | Vector_1D RingAverage( const Vector_1D ringArea, \ 42 | const double totArea, \ 43 | const UInt iNt ) const; 44 | 45 | Vector_2D RingAverage( const Vector_1D ringArea, \ 46 | const double totArea ) const; 47 | 48 | UInt getnRing() const { return nRing; } 49 | UInt getnTime() const { return nTime; } 50 | bool gethalfRing() const { return halfRing; } 51 | 52 | /* Reactive species */ 53 | Vector_3D Species; 54 | 55 | /* Aerosols */ 56 | Vector_2D sootDens, sootRadi, sootArea, \ 57 | iceDens , iceRadi , iceArea, \ 58 | sulfDens, sulfRadi, sulfArea; 59 | 60 | protected: 61 | 62 | UInt nRing; 63 | UInt nTime; 64 | bool halfRing; 65 | 66 | private: 67 | 68 | }; 69 | 70 | #endif /* SPECIES_H_INCLUDED */ 71 | 72 | -------------------------------------------------------------------------------- /Code.v05-00/include/EPM/Models/Original/RHS.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Early Plume Microphysics */ 4 | /* (EPM) */ 5 | /* */ 6 | /* Right-hand side Header File */ 7 | /* */ 8 | /* File : RHS.hpp */ 9 | /* */ 10 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 11 | 12 | #ifndef EPM_MODELS_ORIGINALIMPL_RHS_H_INCLUDED 13 | #define EPM_MODELS_ORIGINALIMPL_RHS_H_INCLUDED 14 | 15 | #include "Util/ForwardDecl.hpp" 16 | #include "AIM/Aerosol.hpp" 17 | 18 | 19 | namespace EPM::Models::OriginalImpl { 20 | 21 | struct gas_aerosol_rhs { 22 | const double m_temperature_K; 23 | const double m_pressure_Pa; 24 | const double m_delta_T; 25 | const double m_H2O_mixingratio; 26 | const double m_SO4_mixingratio; 27 | const double m_SO4l_mixingratio; 28 | const double m_SO4g_mixingratio; 29 | const double m_HNO3_mixingratio; 30 | const double m_part_mixingratio; 31 | const double m_part_r0; 32 | 33 | const double sticking_SO4; 34 | const double sigma_SO4; 35 | 36 | const Vector_1D KernelSO4Soot; 37 | 38 | AIM::Aerosol &nPDF_SO4; 39 | 40 | 41 | gas_aerosol_rhs(double temperature_K, double pressure_Pa, double delta_T, 42 | double H2O_mixingratio, double SO4_mixingratio, double SO4l_mixingratio, 43 | double SO4g_mixingratio, double HNO3_mixingratio, double part_mixingratio, 44 | double part_r0, Vector_1D Kernel_, AIM::Aerosol &nPDF_SO4_) : 45 | m_temperature_K(temperature_K), 46 | m_pressure_Pa(pressure_Pa), 47 | m_delta_T(delta_T), 48 | m_H2O_mixingratio (H2O_mixingratio), 49 | m_SO4_mixingratio (SO4_mixingratio), 50 | m_SO4l_mixingratio (SO4l_mixingratio), 51 | m_SO4g_mixingratio (SO4g_mixingratio), 52 | m_HNO3_mixingratio (HNO3_mixingratio), 53 | m_part_mixingratio(part_mixingratio), 54 | m_part_r0(part_r0), 55 | sticking_SO4(1.0), 56 | sigma_SO4(5.0E+14), 57 | KernelSO4Soot(Kernel_), 58 | nPDF_SO4(nPDF_SO4_) {} 59 | 60 | void operator()(const Vector_1D &x, Vector_1D &dxdt, const double t = 0) const; 61 | }; 62 | 63 | } // namespace EPM::Models::Original 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /scripts/simple_met_input/README.txt: -------------------------------------------------------------------------------- 1 | This folder contains python scripts to produce idealised met files containing trapezoidal moist layers (in an altitude 2 | vs RHi plot). 3 | 4 | TO RUN THE "main.py" SCRIPT, PLEASE OPEN THE FOLDER "simple_met_input" IN YOUR EDITOR/SET IT AS YOUR PYTHON RUNDIR. 5 | 6 | The trapezoid is symmetrical about its centre, and is parametrised as follows: 7 | - centre_altitude_m: The centre altitude in meters. 8 | - moist_depth_m: The moist layer depth in meters; the vertical extent of the moist layer. 9 | - RHi_background_PC: The background RHi in %, which is also the lowest RHi value in the trapezium. 10 | - RHi_peak_PC: The peak trapezium RHi in %. If too shallow a gradient is used, this value might not be reached. 11 | - grad_RHi_PC_per_m: The gradient of the trapezium sides in RHi % / vertical m. If too shallow a gradient is used, 12 | the moist layer will be a triangle instead of a trapezium and its peak will be lower than 13 | or equal to the RHi_peak_PC value. 14 | 15 | The met generator has additional parameters: 16 | - alt_resolution_m: The vertical interval (in m) at which the met is sampled at. 17 | - upper_alt_m: The vertical upper limit (in m) for met sampling. 18 | - shear: The horizontal wind shear (in 1/s). Constant throughout the entire met domain. 19 | - T_offset_K: A temperature offset (in K) from the ISA temperature distribution. Constant throughout the entire met 20 | domain. 21 | 22 | Other than the RHi and shear, all other weather parameters assume the use of the International Standard Atmosphere. 23 | The temperature is decoupled from the pressure by assuming a constant alpha regardless of any temperature offset. 24 | The ideal gas relation is then used to calculate the air density from pressure and temperature to guarantee 25 | consistency. 26 | 27 | The python version used to develop this code is python 3.9.15, with the following modules: 28 | - matplotlib 3.6.2 29 | - netcdf4 1.6.3 30 | - numpy 1.23.5 31 | - xarray 2023.12.0 32 | 33 | Desired improvements: 34 | - No distinction is made between dry and moist air density in this code. The difference is very small at altitude, 35 | but it is still a deficiency that needs to be addressed. 36 | 37 | Contact: 38 | - Please contact ca525@cam.ac.uk (or Calebsakhtar on GitHub) for any queries or suggestions. 39 | 40 | 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. -------------------------------------------------------------------------------- /Code.v05-00/src/Core/TimestepVarsWrapper.cpp: -------------------------------------------------------------------------------- 1 | #include "Core/TimestepVarsWrapper.hpp" 2 | #include 3 | #include 4 | //Declaration of vars is same order as in header, so no undefined behavior 5 | TimestepVarsWrapper::TimestepVarsWrapper(const Input& input, const OptInput& Input_Opt): 6 | tEmission_h(input.emissionTime()), 7 | tInitial_h(tEmission_h), 8 | tFinal_h(tInitial_h + input.simulationTime()), 9 | tInitial_s(tInitial_h * 3600.0), 10 | tFinal_s(tFinal_h * 3600.0), 11 | curr_Time_s(tInitial_s), 12 | dt(0), 13 | nTime(0), 14 | LAST_STEP(0), 15 | ITS_TIME_FOR_TRANSPORT(0), 16 | ITS_TIME_FOR_LIQ_COAGULATION(0), 17 | ITS_TIME_FOR_ICE_COAGULATION(0), 18 | ITS_TIME_FOR_ICE_GROWTH(0), 19 | ITS_TIME_FOR_TEMPPERTURB(0), 20 | TRANSPORT_DT(Input_Opt.TRANSPORT_TIMESTEP * 60.0), 21 | CHEMISTRY_DT(Input_Opt.CHEMISTRY_TIMESTEP * 60.0), 22 | COAG_DT(Input_Opt.AEROSOL_COAGULATION_TIMESTEP * 60.0), 23 | TEMP_PERTURB_DT(Input_Opt.MET_TEMP_PERTURB_TIMESCALE * 60.0), 24 | ICE_GROWTH_DT(Input_Opt.AEROSOL_ICE_GROWTH_TIMESTEP * 60.0), 25 | lastTimeTransport(curr_Time_s), 26 | lastTimeChem(curr_Time_s), 27 | lastTimeLiqCoag(curr_Time_s), 28 | lastTimeIceCoag(curr_Time_s), 29 | lastTimeIceGrowth(curr_Time_s), 30 | lastTimeTempPerturb(curr_Time_s), 31 | totalIceParticles_before(0), 32 | totalIceMass_before(0), 33 | totalIceParticles_initial(0), 34 | totalIceMass_initial(0), 35 | totalIceParticles_now(0), 36 | totalIceMass_now(0), 37 | totalIceParticles_last(0), 38 | totalIceMass_last(0), 39 | totalIceParticles_after(0), 40 | totalIceMass_after(0), 41 | totPart_lost(0), 42 | totIce_lost(0), 43 | ABORT_THRESHOLD(1.0e-3) 44 | { 45 | /* The base timestep is determinined by checking if transport, chemistry, coagulation, temp. perturbation, and ice growth are on. 46 | The enabled process with the smallest timestep is then chosen to be the timestep for the overall time loop. 47 | 48 | There are many bad decisions about relative timestep sizes that can be made, but for now we will not employ any user error safeguards. - MX */ 49 | 50 | Vector_1D timesteps; 51 | 52 | if(Input_Opt.TRANSPORT_TRANSPORT) 53 | timesteps.push_back(TRANSPORT_DT); 54 | if(Input_Opt.CHEMISTRY_CHEMISTRY) 55 | timesteps.push_back(CHEMISTRY_DT); 56 | if(Input_Opt.AEROSOL_COAGULATION_SOLID || Input_Opt.AEROSOL_COAGULATION_LIQUID) 57 | timesteps.push_back(COAG_DT); 58 | if(Input_Opt.MET_ENABLE_TEMP_PERTURB) 59 | timesteps.push_back(TEMP_PERTURB_DT); 60 | if(Input_Opt.AEROSOL_ICE_GROWTH) 61 | timesteps.push_back(ICE_GROWTH_DT); 62 | 63 | dt = *(std::min_element(timesteps.begin(), timesteps.end())); 64 | std::cout << "Calculated Timestep: " << dt/60.0 << "[min]" << std::endl; 65 | if (dt <= 0) throw std::runtime_error("Invalid Timestep"); 66 | } -------------------------------------------------------------------------------- /Code.v05-00/include/Core/Diag_Mod.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* Diag_Mod Header File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 12/17/2018 */ 10 | /* File : Diag_Mod.hpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #ifndef DIAG_MOD_H_INCLUDED 15 | #define DIAG_MOD_H_INCLUDED 16 | 17 | #include 18 | #include 19 | #include 20 | #include "AIM/Aerosol.hpp" 21 | #include "Core/Meteorology.hpp" 22 | #include "KPP/KPP_Global.h" 23 | 24 | namespace Diag { 25 | using namespace netCDF; 26 | using namespace netCDF::exceptions; 27 | using std::string; 28 | using std::vector; 29 | 30 | 31 | static const int SAVE_SUCCESS = 1; 32 | static const int SAVE_FAILURE = 0; 33 | 34 | /* ================================================================== */ 35 | /* ---- Timeseries Diagnostics -------------------------------------- */ 36 | /* ================================================================== */ 37 | 38 | /* Timeseries diagnostic files must be of the form: 39 | * *hhmmss.nc or *hhmm.nc */ 40 | 41 | void Diag_TS_Phys( const char* rootName, 42 | const int hh, const int mm, const int ss, 43 | const AIM::Grid_Aerosol& iceAer, const Vector_2D& H2O, 44 | const Vector_1D& xCoord, const Vector_1D& yCoord, 45 | const Vector_1D& xEdges, const Vector_1D& yEdges, 46 | const Meteorology &met); 47 | 48 | void add0DVar(NcFile& currFile, const float toSave, const NcDim& dim, const string& name, const string& desc, const string& units); 49 | void add1DVar(NcFile& currFile, const Vector_1D& toSave, const NcDim& dim, const string& name, const string& desc, const string& units); 50 | void add2DVar(NcFile& currFile, const Vector_2D& toSave, const vector dims, const string& name, const string& desc, const string& units); 51 | void add3DVar(NcFile& currFile, const Vector_3D& toSave, const vector dims, const string& name, const string& desc, const string& units); 52 | void replace_hhmmss(string& fileName, int hh, int mm, int ss); 53 | void set_storePSD(bool val); 54 | 55 | } // namespace Diag 56 | 57 | #endif /* DIAG_MOD_H_INCLUDED */ 58 | -------------------------------------------------------------------------------- /Code.v05-00/include/AIM/Coagulation.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* AIrcraft Microphysics */ 4 | /* (AIM) */ 5 | /* */ 6 | /* Coagulation Header File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 9/27/2018 */ 10 | /* File : Coagulation.hpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #ifndef COAGULATION_H_INCLUDED 15 | #define COAGULATION_H_INCLUDED 16 | 17 | #include 18 | #include 19 | #include "Util/ForwardDecl.hpp" 20 | 21 | namespace AIM 22 | { 23 | 24 | /* We need forward declaration here */ 25 | class Aerosol; 26 | class Grid_Aerosol; 27 | 28 | class Coagulation; 29 | 30 | } 31 | 32 | class AIM::Coagulation 33 | { 34 | 35 | friend class Aerosol; 36 | friend class Grid_Aerosol; 37 | 38 | public: 39 | 40 | Coagulation( ); 41 | Coagulation( const char* phase, Vector_1D const &bin_Centers_1, Vector_1D &bin_VCenters_1, double rho_1, Vector_1D const &bin_Centers_2, double rho_2, double temperature_K_, double pressure_Pa_ ); 42 | Coagulation( const char* phase, Vector_1D const &bin_Centers_1, Vector_1D &bin_VCenters_1, double rho_1, double temperature_K_, double pressure_Pa_ ); 43 | Coagulation( const char* phase, Vector_1D const &bin_Centers_1, double rho_1, double bin_Centers_2, double rho_2, double temperature_K_, double pressure_Pa_ ); 44 | 45 | ~Coagulation( ); 46 | Coagulation( const Coagulation& k ); 47 | Coagulation& operator=( const Coagulation& k ); 48 | void buildBeta( const Vector_1D &bin_Centers ); 49 | void buildF( const Vector_1D &bin_VCenters ); 50 | void buildF( const Vector_3D &bin_VCenters, const UInt jNy, const UInt iNx ); 51 | Vector_2D getKernel() const; 52 | Vector_1D getKernel_1D() const; 53 | Vector_2D getBeta() const; 54 | Vector_3D getF() const; 55 | 56 | Vector_3D f; 57 | std::vector > > indices; 58 | 59 | protected: 60 | 61 | Vector_2D Kernel; 62 | Vector_1D Kernel_1D; 63 | Vector_2D beta; 64 | 65 | private: 66 | 67 | const double A0 = 5.07; 68 | const double A1 = -5.94; 69 | const double A2 = 7.27; 70 | const double A3 = -5.29; 71 | 72 | 73 | }; 74 | 75 | #endif /* COAGULATION_H_INCLUDED */ 76 | 77 | -------------------------------------------------------------------------------- /Code.v05-00/src/Core/Ring.cpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* Ring Program File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 8/12/2018 */ 10 | /* File : Ring.cpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #include 15 | #include "Core/Ring.hpp" 16 | 17 | Ring::Ring( ) 18 | { 19 | /* Default Constructor */ 20 | 21 | horizontalAxis = 0.0; 22 | verticalAxis = 0.0; 23 | 24 | } /* End of Ring::Ring */ 25 | 26 | Ring::Ring( double a, double b ) 27 | { 28 | 29 | /* Constructor */ 30 | 31 | if ( a < 0 || b < 0 ) { 32 | std::cout << "Horizontal and/or vertical axis are negative!" << std::endl; 33 | a = 0.0; 34 | b = 0.0; 35 | } 36 | 37 | horizontalAxis = a; 38 | verticalAxis = b; 39 | 40 | } /* End of Ring::Ring */ 41 | 42 | Ring::Ring( const Ring &r ) 43 | { 44 | 45 | /* Constructor */ 46 | 47 | horizontalAxis = r.getHAxis(); 48 | verticalAxis = r.getVAxis(); 49 | 50 | } /* End of Ring::Ring */ 51 | 52 | Ring& Ring::operator=( const Ring &r ) 53 | { 54 | 55 | if ( &r == this ) 56 | return *this; 57 | 58 | horizontalAxis = r.getHAxis(); 59 | verticalAxis = r.getVAxis(); 60 | 61 | return *this; 62 | 63 | } /* End of Ring::operator= */ 64 | 65 | Ring::~Ring( ) 66 | { 67 | /* Destructor */ 68 | 69 | } /* End of Ring::~Ring */ 70 | 71 | void Ring::Assign( double a, double b ) 72 | { 73 | 74 | if ( a < 0 || b < 0 ) { 75 | std::cout << "Horizontal and/or vertical axis are negative!" << std::endl; 76 | a = 0.0; 77 | b = 0.0; 78 | } 79 | 80 | horizontalAxis = a; 81 | verticalAxis = b; 82 | 83 | 84 | } /* End of Ring::Assign */ 85 | 86 | void Ring::Print( ) const 87 | { 88 | std::cout << "Ring's horizontal and vertical axis: " << horizontalAxis << ", " << verticalAxis << " [m]" << std::endl; 89 | 90 | } /* End of Ring::Print */ 91 | 92 | double Ring::getHAxis( ) const 93 | { 94 | 95 | return horizontalAxis; 96 | 97 | } /* End of Ring::getHAxis */ 98 | 99 | double Ring::getVAxis( ) const 100 | { 101 | 102 | return verticalAxis; 103 | 104 | } /* End of Ring::getVAxis */ 105 | 106 | /* End of Ring.cpp */ 107 | -------------------------------------------------------------------------------- /Code.v05-00/include/AIM/buildKernel.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* AIrcraft Microphysics */ 4 | /* (AIM) */ 5 | /* */ 6 | /* buildKernel Header File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 9/27/2018 */ 10 | /* File : buildKernel.hpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #ifndef BUILDKERNEL_H_INCLUDED 15 | #define BUILDKERNEL_H_INCLUDED 16 | 17 | #include "Util/ForwardDecl.hpp" 18 | 19 | namespace AIM 20 | { 21 | 22 | /* Brownian coagulation kernel */ 23 | Vector_1D buildBrownianKernel( double temperature_K, double pressure_Pa, Vector_1D const &bin_Centers, double rho_1 , double bin_R, double rho_2 ); 24 | Vector_2D buildBrownianKernel( double temperature_K, double pressure_Pa, Vector_1D const &bin_Centers_1, double rho_1 , Vector_1D const &bin_Centers_2, double rho_2 ); 25 | 26 | /* Convective Brownian diffusion enhancement */ 27 | Vector_1D buildDEKernel( double temperature_K, double pressure_Pa, Vector_1D const &bin_Centers, double rho_1, double bin_R, double rho_2, Vector_1D const &K_Brow ); 28 | Vector_2D buildDEKernel( double temperature_K, double pressure_Pa, Vector_1D const &bin_Centers_1, double rho_1, Vector_1D const &bin_Centers_2, double rho_2, Vector_2D const &K_Brow ); 29 | 30 | /* Gravitational collection kernel */ 31 | Vector_1D buildGCKernel( double temperature_K, double pressure_Pa, Vector_1D const &bin_Centers, double rho_1, double bin_R, double rho_2 ); 32 | Vector_2D buildGCKernel( double temperature_K, double pressure_Pa, Vector_1D const &bin_Centers_1, double rho_1, Vector_1D const &bin_Centers_2, double rho_2 ); 33 | 34 | /* Turbulent initial motion */ 35 | Vector_1D buildTIKernel( double temperature_K, double pressure_Pa, Vector_1D const &bin_Centers, double rho_1, double bin_R, double rho_2 ); 36 | Vector_2D buildTIKernel( double temperature_K, double pressure_Pa, Vector_1D const &bin_Centers_1, double rho_1, Vector_1D const &bin_Centers_2, double rho_2 ); 37 | 38 | /* Turbulent shear */ 39 | Vector_1D buildTSKernel( double temperature_K, double pressure_Pa, Vector_1D const &bin_Centers, double rho_1, double bin_R, double rho_2 ); 40 | Vector_2D buildTSKernel( double temperature_K, double pressure_Pa, Vector_1D const &bin_Centers_1, double rho_1, Vector_1D const &bin_Centers_2, double rho_2 ); 41 | 42 | } 43 | 44 | #endif /* BUILDKERNEL_H_INCLUDED */ 45 | -------------------------------------------------------------------------------- /Code.v05-00/include/KPP/KPP_Global.h: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Global Data Header File */ 4 | /* */ 5 | /* Generated by KPP-2.2.3 symbolic chemistry Kinetics PreProcessor */ 6 | /* (http://www.cs.vt.edu/~asandu/Software/KPP) */ 7 | /* KPP is distributed under GPL, the general public licence */ 8 | /* (http://www.gnu.org/copyleft/gpl.html) */ 9 | /* (C) 1995-1997, V. Damian & A. Sandu, CGRER, Univ. Iowa */ 10 | /* (C) 1997-2005, A. Sandu, Michigan Tech, Virginia Tech */ 11 | /* With important contributions from: */ 12 | /* M. Damian, Villanova University, USA */ 13 | /* R. Sander, Max-Planck Institute for Chemistry, Mainz, Germany */ 14 | /* */ 15 | /* File : KPP_Global.h */ 16 | /* Equation file : KPP.kpp */ 17 | /* Output root filename : KPP */ 18 | /* */ 19 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 20 | 21 | #include "omp.h" 22 | #include "KPP/KPP_Parameters.h" 23 | 24 | #ifndef KPP_GLOBAL_H_INCLUDED 25 | #define KPP_GLOBAL_H_INCLUDED 26 | 27 | /* Declaration of global variables */ 28 | 29 | extern double C[NSPEC]; /* Concentration of all species */ 30 | extern double * VAR; 31 | extern double * FIX; 32 | extern double RCONST[NREACT]; /* Rate constants (global) */ 33 | extern double TIME; /* Current integration time */ 34 | extern int LOOKAT[NLOOKAT]; /* Indexes of species to look at */ 35 | extern const char * SPC_NAMES[NSPEC]; /* Names of chemical species */ 36 | extern char * SMASS[NMASS]; /* Names of atoms for mass balance */ 37 | extern const char * EQN_NAMES[NREACT]; /* Equation names */ 38 | extern char * EQN_TAGS[NREACT]; /* Equation tags */ 39 | 40 | /* INLINED global variable declarations */ 41 | 42 | extern double NOON_JRATES[NPHOTOL]; /* Noon-time photolysis rates */ 43 | extern double PHOTOL[NPHOTOL]; /* Photolysis rates */ 44 | extern double HET[NSPEC][3]; /* Heterogeneous reaction rates */ 45 | extern double SZA_CST[3]; /* Constants to compute cosSZA */ 46 | 47 | /* The following variables need to be declared THREADPRIVATE 48 | * because they get written to within an OpenMP parallel loop */ 49 | #pragma omp threadprivate( C, VAR, FIX, RCONST, NOON_JRATES, PHOTOL, HET, TIME, SZA_CST ) 50 | 51 | /* INLINED global variable declarations */ 52 | 53 | #endif /* KPP_GLOBAL_H_INCLUDED */ 54 | -------------------------------------------------------------------------------- /Code.v05-00/include/KPP/KPP.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* */ 7 | /* KPP Header File */ 8 | /* */ 9 | /* Author : Thibaud M. Fritz */ 10 | /* Time : 10/4/2018 */ 11 | /* File : KPP.hpp */ 12 | /* */ 13 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 14 | 15 | #ifndef KPP_H_INCLUDED 16 | #define KPP_H_INCLUDED 17 | 18 | #include "KPP/KPP_Parameters.h" 19 | 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif /* __cplusplus */ 23 | 24 | int INTEGRATE( double VAR[] , double FIX[], double TIN , double TOUT, \ 25 | double ATOL[], double RTOL[], double STEPMIN ); 26 | int KPP_Main_ADJ( const double finalPlume[], const double initBackg[], \ 27 | const double temperature_K, const double pressure_Pa, \ 28 | const double airDens, const double timeArray[], \ 29 | const unsigned int NT, \ 30 | const double RTOLS, const double ATOLS, \ 31 | double VAR_OUTPUT[], double *METRIC, \ 32 | const bool VERBOSE = 0, const bool RETRY = 0 ); 33 | int INTEGRATE_ADJ( int NADJ, double Y[], double Lambda[][NVAR], \ 34 | double TIN, double TOUT, double ATOL_adj[][NVAR], \ 35 | double RTOL_adj[][NVAR], double ATOL[], \ 36 | double RTOL[], int ICNTRL_U[], \ 37 | double RCNTRL_U[], int ISTATUS_U[], \ 38 | double RSTATUS_U[], double STEPMIN ); 39 | void Update_RCONST( const double TEMP, const double PRESS, \ 40 | const double AIRDENS, const double H2O ); 41 | void GC_SETHET( const double TEMP, const double PATM, const double AIRDENS, \ 42 | const double RELHUM, const unsigned int STATE_PSC, \ 43 | const double SPC[], const double AREA[NAERO], \ 44 | const double RADI[NAERO], const double IWC, \ 45 | const double KHETI_SLA[11], double tropopausePressure); 46 | void Update_JRates ( double JRates[], const double CSZA ); 47 | void ComputeFamilies( const double V[], const double F[], const double RCT[], \ 48 | double familyRates[] ); 49 | 50 | // static int KPP_FAIL = -1; 51 | // static int KPPADJ_FAIL = -5; 52 | 53 | 54 | #ifdef __cplusplus 55 | } 56 | #endif /* __cplusplus */ 57 | 58 | #endif /* KPP_H_INCLUDED */ 59 | -------------------------------------------------------------------------------- /Code.v05-00/include/KPP/KPP_Sparse.h: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Sparse Data Header File */ 4 | /* */ 5 | /* Generated by KPP-2.2.3 symbolic chemistry Kinetics PreProcessor */ 6 | /* (http://www.cs.vt.edu/~asandu/Software/KPP) */ 7 | /* KPP is distributed under GPL, the general public licence */ 8 | /* (http://www.gnu.org/copyleft/gpl.html) */ 9 | /* (C) 1995-1997, V. Damian & A. Sandu, CGRER, Univ. Iowa */ 10 | /* (C) 1997-2005, A. Sandu, Michigan Tech, Virginia Tech */ 11 | /* With important contributions from: */ 12 | /* M. Damian, Villanova University, USA */ 13 | /* R. Sander, Max-Planck Institute for Chemistry, Mainz, Germany */ 14 | /* */ 15 | /* File : KPP_Sparse.h */ 16 | /* Equation file : KPP.kpp */ 17 | /* Output root filename : KPP */ 18 | /* */ 19 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 20 | 21 | #ifndef KPP_SPARSE_H_INCLUDED 22 | #define KPP_SPARSE_H_INCLUDED 23 | 24 | 25 | /* ----------> Sparse Jacobian Data */ 26 | 27 | extern int LU_IROW[LU_NONZERO]; /* Row indexes of the LU Jacobian of variables */ 28 | extern int LU_ICOL[LU_NONZERO]; /* Column indexes of the LU Jacobian of variables */ 29 | extern int LU_CROW[CNVAR]; /* Compressed row indexes of the LU Jacobian of variables */ 30 | extern int LU_DIAG[CNVAR]; /* Diagonal indexes of the LU Jacobian of variables */ 31 | 32 | 33 | /* ----------> Sparse Hessian Data */ 34 | 35 | extern int IHESS_I[NHESS]; /* Index i of Hessian element d^2 f_i/dv_j.dv_k */ 36 | extern int IHESS_J[NHESS]; /* Index j of Hessian element d^2 f_i/dv_j.dv_k */ 37 | extern int IHESS_K[NHESS]; /* Index k of Hessian element d^2 f_i/dv_j.dv_k */ 38 | 39 | 40 | /* ----------> Sparse Stoichiometric Matrix */ 41 | 42 | extern double STOICM[NSTOICM]; /* Stoichiometric Matrix in compressed column format */ 43 | extern int IROW_STOICM[NSTOICM]; /* Row indices in STOICM */ 44 | extern int CCOL_STOICM[CNEQN]; /* Beginning of columns in STOICM */ 45 | extern int ICOL_STOICM[NSTOICM]; /* Column indices in STOICM */ 46 | 47 | 48 | /* ----------> Sparse Data for Jacobian of Reactant Products */ 49 | 50 | extern int ICOL_JVRP[NJVRP]; /* Column indices in JVRP */ 51 | extern int IROW_JVRP[NJVRP]; /* Row indices in JVRP */ 52 | extern int CROW_JVRP[CNEQN]; /* Beginning of rows in JVRP */ 53 | 54 | #endif /* KPP_SPARSE_H_INCLUDED */ 55 | -------------------------------------------------------------------------------- /Code.v05-00/include/Core/LiquidAer.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* LiquidAer Header File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 10/22/2018 */ 10 | /* File : LiquidAer.hpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #ifndef LIQUIDAER_H_INCLUDED 15 | #define LIQUIDAER_H_INCLUDED 16 | 17 | #include 18 | 19 | double H2SO4_GASFRAC( const double temperature_K, const double SO4 ); 20 | unsigned int STRAT_AER( const double temperature_K , const double pressure_Pa , const double airDens , \ 21 | const double latitude_deg , std::vector &Data , double Area , \ 22 | std::vector &KHETI_SLA , std::vector &SOLIDFRAC , \ 23 | std::vector &AERFRAC , std::vector &RAD_AER , \ 24 | std::vector &RHO_AER , std::vector &KG_AER , \ 25 | std::vector &NDENS_AER , std::vector &SAD_AER , 26 | double tropopausePressure, bool DBG_IN ); 27 | std::vector SLA_GAMMA( const double T_K , const double P_Pa , \ 28 | const double WT_FRC , \ 29 | const double H2OSUM , const double HClSUM , \ 30 | const double HBrSUM , const double HOBrSUM , \ 31 | const double ClNO3SUM , const double BrNO3SUM , \ 32 | const double RHO , const double ARAD ); 33 | void TERNARY( const double TIN_K , const double PIN_Pa , const double H2OSUM_IN , \ 34 | const double H2SO4SUM , const double HNO3SUM , const double HClSUM , \ 35 | const double HOClSUM , const double HBrSUM , const double HOBrSUM , \ 36 | double &W_H2SO4 , double &W_H2O , double &W_HNO3 , \ 37 | double &W_HCl , double &W_HOCl , double &W_HBr , \ 38 | double &W_HOBr , double &HNO3GASFRAC , double &HClGASFRAC , \ 39 | double &HOClGASFRAC , double &HBrGASFRAC , double &HOBrGASFRAC , \ 40 | double &SLA_VOL , double &SLA_RHO ); 41 | double CARSLAW_DENSITY( const double CS, const double CN, const double T_K ); 42 | 43 | 44 | #endif /* LIQUIDAER_H_INCLUDED */ 45 | -------------------------------------------------------------------------------- /Code.v05-00/include/Core/Interface.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* Interface Header File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 8/12/2018 */ 10 | /* File : Interface.hpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #ifndef INTERFACE_H_INCLUDED 15 | #define INTERFACE_H_INCLUDED 16 | 17 | /* SYMMETRIES */ 18 | #define X_SYMMETRY 0 /* Is the problem symmetric 19 | around the x-axis? */ 20 | #define Y_SYMMETRY 0 /* Is the problem symmetric 21 | around the y-axis? */ 22 | 23 | /* OUTPUT CONCENTRATIONS */ 24 | 25 | /* Save output as double? otherwise save as float. 26 | * Saving as float will reduce the memory requirements */ 27 | #define SAVE_TO_DOUBLE 0 28 | 29 | 30 | /* MASS CHECK */ 31 | #define NOy_MASS_CHECK 0 /* NOy mass check? */ 32 | #define CO2_MASS_CHECK 0 /* CO2 mass check? */ 33 | #define H2O_MASS_CHECK 0 /* H2O mass check? */ 34 | 35 | /* DEBUG */ 36 | /* DEBUG is now specified in Makefile header */ 37 | #define DEBUG_ALL 0 /* Debug all? */ 38 | //#define DEBUG 0 /* Debug all except variables that have 39 | // specific debug options (see below) */ 40 | 41 | #define DEBUG_AC_INPUT 0 /* Debug AC Input? */ 42 | #define DEBUG_BG_INPUT 0 /* Debug Background Input? */ 43 | #define DEBUG_EI_INPUT 0 /* Debug Emission Input? */ 44 | #define DEBUG_RINGS 0 /* Debug Rings? */ 45 | #define DEBUG_MAPPING 0 /* Debug Mesh to ring mapping? */ 46 | #define DEBUG_COAGKERNEL 0 /* Debug Coagulation Kernel? */ 47 | #define DEBUG_ADJOINT 0 /* Debug adjoint? */ 48 | 49 | #if DEBUG_ALL 50 | 51 | #undef DEBUG 52 | #undef DEBUG_AC_INPUT 53 | #undef DEBUG_BG_INPUT 54 | #undef DEBUG_EI_INPUT 55 | #undef DEBUG_RINGS 56 | #undef DEBUG_MAPPING 57 | #undef DEBUG_COAGKERNEL 58 | #define DEBUG 1 59 | #define DEBUG_AC_INPUT 1 60 | #define DEBUG_BG_INPUT 1 61 | #define DEBUG_EI_INPUT 1 62 | #define DEBUG_RINGS 1 63 | #define DEBUG_MAPPING 1 64 | #define DEBUG_COAGKERNEL 1 65 | #define DEBUG_ADJOINT 1 66 | 67 | #endif 68 | 69 | /* If adjoint is turned off, make sure DEBUG_ADJOINT is false */ 70 | #if ( !ADJOINT ) 71 | 72 | #undef DEBUG_ADJOINT 73 | #define DEBUG_ADJOINT 0 74 | 75 | #endif 76 | 77 | 78 | #endif /* INTERFACE_H_INCLUDED */ 79 | -------------------------------------------------------------------------------- /Code.v05-00/src/KPP/UCX.def: -------------------------------------------------------------------------------- 1 | #include UCX.spc 2 | #include UCX.eqn 3 | 4 | #LANGUAGE C 5 | #INTEGRATOR rosenbrock 6 | #DRIVER general 7 | 8 | #LOOKATALL 9 | 10 | #INITVALUES 11 | 12 | A3O2 = 1.000E-20; 13 | ACET = 7.500E-10; 14 | ALD2 = 1.600E-10; 15 | ALK4 = 1.000E-20; 16 | ATO2 = 1.000E-20; 17 | B3O2 = 1.000E-20; 18 | C2H6 = 2.590E-12; 19 | C3H8 = 4.800E-11; 20 | CH2O = 1.020E-11; 21 | CH4 = 1.700E-06; 22 | CO = 5.510E-08; 23 | CO2 = 3.600E-04; 24 | ETO2 = 1.000E-20; 25 | ETP = 1.000E-20; 26 | GLYC = 1.000E-20; 27 | GLYX = 1.000E-20; 28 | H = 4.000E-20; 29 | H2O = 3.84E-05; 30 | H2O2 = 2.720E-12; 31 | HAC = 1.000E-20; 32 | HNO2 = 4.000E-15; 33 | HNO3 = 2.170E-10; 34 | HNO4 = 2.360E-11; 35 | HO2 = 1.020E-12; 36 | IAP = 1.000E-20; 37 | INO2 = 1.000E-20; 38 | INPN = 1.000E-20; 39 | ISN1 = 1.000E-20; 40 | ISNOOA = 1.000E-20; 41 | ISNOOB = 1.000E-20; 42 | ISNOHOO = 1.000E-20; 43 | ISNP = 1.000E-20; 44 | ISOP = 2.000E-10; 45 | KO2 = 1.000E-20; 46 | MACR = 1.000E-20; 47 | MAN2 = 1.000E-20; 48 | MAO3 = 1.000E-20; 49 | MAOP = 1.000E-20; 50 | MAOPO2 = 1.000E-20; 51 | MAP = 1.000E-20; 52 | MCO3 = 1.000E-20; 53 | MEK = 1.000E-20; 54 | MGLY = 1.000E-20; 55 | MO2 = 5.400E-12; 56 | MP = 1.200E-09; 57 | MRO2 = 1.000E-20; 58 | MRP = 1.000E-20; 59 | MVK = 1.000E-20; 60 | N = 4.000E-25; 61 | N2O = 3.000E-07; 62 | N2O5 = 1.200E-11; 63 | NO = 4.410E-11; 64 | NO2 = 5.880E-11; 65 | NO3 = 1.300E-11; 66 | O = 1.300E-16; 67 | O1D = 1.000E-20; 68 | O3 = 6.460E-08; 69 | OH = 7.000E-14; 70 | PAN = 1.000E-20; 71 | PMN = 1.000E-20; 72 | PO2 = 1.000E-20; 73 | PP = 1.000E-20; 74 | PPN = 1.000E-20; 75 | PRN1 = 1.000E-20; 76 | PRPE = 6.000E-12; 77 | PRPN = 1.000E-20; 78 | R4N1 = 1.000E-20; 79 | R4N2 = 1.000E-20; 80 | R4O2 = 1.000E-20; 81 | R4P = 1.000E-20; 82 | RA3P = 1.000E-20; 83 | RB3P = 1.000E-20; 84 | RCHO = 1.000E-20; 85 | RCO3 = 1.000E-20; 86 | RIO2 = 1.000E-20; 87 | RIP = 1.000E-20; 88 | ROH = 1.000E-20; 89 | RP = 1.000E-20; 90 | VRO2 = 1.000E-20; 91 | VRP = 1.000E-20; 92 | SO2 = 1.250E-10; 93 | SO4 = 1.000E-70; 94 | Br2 = 1.000E-20; 95 | Br = 9.100E-16; 96 | BrO = 1.300E-14; 97 | HOBr = 6.600E-14; 98 | HBr = 3.700E-14; 99 | BrNO2 = 1.000E-20; 100 | BrNO3 = 1.700E-13; 101 | MPN = 1.000E-20; 102 | ISOPND = 1.000E-20; 103 | ISOPNB = 1.000E-20; 104 | HC5 = 1.000E-20; 105 | DIBOO = 1.000E-20; 106 | HC5OO = 1.000E-20; 107 | DHMOB = 1.000E-20; 108 | MOBA = 1.000E-20; 109 | MOBAOO = 1.000E-20; 110 | ISOPNBO2 = 1.000E-20; 111 | ISOPNDO2 = 1.000E-20; 112 | PROPNN = 1.000E-20; 113 | ETHLN = 1.000E-20; 114 | MACRN = 1.000E-20; 115 | MVKN = 1.000E-20; 116 | IEPOX = 1.000E-20; 117 | IEPOXOO = 1.000E-20; 118 | ATOOH = 1.000E-20; 119 | PMNN = 1.000E-20; 120 | MACRNO2 = 1.000E-20; 121 | CH2OO = 1.000E-20; 122 | MACROO = 1.000E-20; 123 | MVKOO = 1.000E-20; 124 | GAOO = 1.000E-20; 125 | MGLYOO = 1.000E-20; 126 | MGLOO = 1.000E-20; 127 | CH3CHOO = 1.000E-20; 128 | BrCl = 3.500E-18; 129 | Cl = 1.600E-17; 130 | Cl2 = 1.000E-20; 131 | ClO = 1.000E-14; 132 | ClOO = 1.000E-20; 133 | OClO = 1.000E-20; 134 | Cl2O2 = 1.000E-20; 135 | ClNO2 = 1.000E-20; 136 | ClNO3 = 1.300E-12; 137 | HCl = 3.160E-12; 138 | HOCl = 1.700E-13; 139 | ACTA = 3.000E-09; 140 | EOH = 1.000E-20; 141 | H2 = 2.700E-07; 142 | HCOOH = 1.800E-09; 143 | MNO3 = 1.000E-20; 144 | MOH = 1.000E-20; 145 | N2 = 7.808E-01; 146 | O2 = 2.095E-01; 147 | RCOOH = 1.000E-20; 148 | -------------------------------------------------------------------------------- /Code.v05-00/src/Core/SZA.cpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* SZA Program File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 7/26/2018 */ 10 | /* File : SZA.cpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #include 15 | #include "Util/PhysConstant.hpp" 16 | #include "Core/SZA.hpp" 17 | 18 | SZA::SZA( const double lat_, const unsigned int day_ ): 19 | latitude( lat_ ), 20 | dayGMT( day_ ) 21 | { 22 | 23 | /* Default Constructor */ 24 | 25 | const double r_SZA = 2*physConst::PI*(std::floor(dayGMT) - 1)/365.0; 26 | 27 | DEC = A0 - A1*cos(1.0*r_SZA) + B1*sin(1.0*r_SZA)\ 28 | - A2*cos(2.0*r_SZA) + B2*sin(2.0*r_SZA)\ 29 | - A3*cos(3.0*r_SZA) + B3*sin(3.0*r_SZA); 30 | 31 | sinLAT = std::sin(lat_ * physConst::PI/180.0); 32 | cosLAT = std::cos(lat_ * physConst::PI/180.0); 33 | sinDEC = std::sin(DEC); 34 | cosDEC = std::cos(DEC); 35 | 36 | sunRise = std::max((12.0 - 180.0/(physConst::PI*15.0)*acos(-(sinLAT * sinDEC)\ 37 | / (cosLAT * cosDEC))), 0.0); 38 | sunSet = std::min((12.0 + 180.0/(physConst::PI*15.0)*acos(-(sinLAT * sinDEC)\ 39 | / (cosLAT * cosDEC))), 24.0); 40 | 41 | CSZA_max = std::max( sinLAT * sinDEC + cosLAT * cosDEC, 0.0 ); 42 | CSZA = 0.0; 43 | 44 | /* Vector of coefficient 45 | * CSZA = CSZA_Vector[0] + CSZA_Vector[1] * cos( CSZA_Vector{3} * (Time/3600.0 - 12.0 ) )*/ 46 | CSZA_Vector = { sinLAT * sinDEC, cosLAT * cosDEC, 15.0 * physConst::PI / 180.0 }; 47 | 48 | } /* End of SZA::SZA */ 49 | 50 | SZA::~SZA( ) 51 | { 52 | 53 | /* Destructor */ 54 | 55 | } /* End of SZA::~SZA */ 56 | 57 | void SZA::Update( const double solarTime ) 58 | { 59 | 60 | CSZA = std::max( sinLAT * sinDEC + cosLAT * cosDEC * std::cos( std::abs( ( solarTime/3600.0 - 12.0 ) ) * 15.0 * physConst::PI / 180.0 ), 0.0 ); 61 | 62 | } /* End of SZA::Update */ 63 | 64 | double SZA::getCSZA( const double solarTime ) 65 | { 66 | 67 | return std::max( sinLAT * sinDEC + cosLAT * cosDEC * std::cos( std::abs( ( solarTime/3600.0 - 12.0 ) ) * 15.0 * physConst::PI / 180.0 ), 0.0 ); 68 | 69 | } /* End of SZA::getCSZA */ 70 | 71 | std::vector SZA::getSZA_Vector( ) const 72 | { 73 | 74 | return CSZA_Vector; 75 | 76 | } /* End of SZA::getSZA_Vector */ 77 | 78 | void* castSZA( SZA *sun ) 79 | { 80 | 81 | return( reinterpret_cast< void* >( sun ) ); 82 | 83 | } /* End of castSZA */ 84 | 85 | double castCSZA( void *sun, const double solarTime ) 86 | { 87 | 88 | return( reinterpret_cast< SZA* >( sun )->getCSZA( solarTime ) ); 89 | 90 | } /* End of castCSZA */ 91 | 92 | /* End of SZA.cpp */ 93 | -------------------------------------------------------------------------------- /Code.v05-00/include/EPM/Solution.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* Structure Header File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 7/26/2018 */ 10 | /* File : Structure.hpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #ifndef EPM_SOLUTION_H_INCLUDED 15 | #define EPM_SOLUTION_H_INCLUDED 16 | 17 | #include "AIM/Aerosol.hpp" 18 | #include "KPP/KPP_Global.h" 19 | #include "Util/ForwardDecl.hpp" 20 | #include "Core/Input.hpp" 21 | #include "Core/Input_Mod.hpp" 22 | #include "Core/Input_Mod.hpp" 23 | #include "Core/Meteorology.hpp" 24 | 25 | namespace EPM { 26 | 27 | class Solution 28 | { 29 | public: 30 | 31 | Solution(const OptInput& optInput); 32 | 33 | // NOTE: THIS IS ONLY CALLED FOR THE EPM 34 | void Initialize(std::string fileName, const Input &input, 35 | const double airDens, const Meteorology &met, 36 | const OptInput &Input_Opt, Vector_1D &varSpeciesArray, 37 | const bool DBG); 38 | 39 | void getData(Vector_1D &varSpeciesArray, const UInt i = 0, const UInt j = 0); 40 | 41 | void SpinUp(Vector_1D &amb_Value, const Input &input, 42 | const double airDens, const double startTime, 43 | Vector_1D &varSpeciesArray, const bool DGB = 0); 44 | 45 | double getSootDensity() const { return sootDens[0][0]; } 46 | 47 | /* Species */ 48 | Vector_3D Species; 49 | 50 | /* Aerosols */ 51 | Vector_2D sootDens, sootRadi, sootArea; 52 | 53 | AIM::Grid_Aerosol liquidAerosol, solidAerosol; 54 | 55 | UInt nBin_PA; 56 | UInt nBin_LA; 57 | 58 | double LA_nDens, LA_rEff, LA_SAD; 59 | double PA_nDens, PA_rEff, PA_SAD; 60 | 61 | Vector_1D KHETI_SLA; 62 | Vector_1D AERFRAC, SOLIDFRAC; 63 | UInt STATE_PSC; 64 | 65 | private: 66 | void readInputBackgroundConditions(const Input &input, Vector_1D &amb_Value, 67 | Vector_2D &aer_Value, 68 | std::string filename); 69 | void processInputBackgroundLine(std::istream &s, Vector_1D &amb_Value, 70 | Vector_2D &aer_Value); 71 | void setAmbientConcentrations(const Input &input, Vector_1D &amb_Value); 72 | void initializeSpeciesH2O(const Input &input, const OptInput &input_Opt, 73 | Vector_1D &amb_Value, const double airDens, 74 | const Meteorology &met); 75 | void setSpeciesValues(Vector_1D &AERFRAC, Vector_1D &SOLIDFRAC, 76 | const Vector_1D &stratData); 77 | 78 | const UInt nVariables; 79 | const UInt nAer; 80 | const UInt size_x; 81 | const UInt size_y; 82 | 83 | bool reducedSize; 84 | }; 85 | 86 | } // namespace EPM 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /Code.v05-00/include/Core/Emission.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* Emission Header File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 7/26/2018 */ 10 | /* File : Emission.hpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #ifndef EMISSION_H_INCLUDED 15 | #define EMISSION_H_INCLUDED 16 | 17 | #include 18 | #include "Core/Engine.hpp" 19 | #include "Core/Fuel.hpp" 20 | 21 | class Emission 22 | { 23 | public: 24 | 25 | Emission( ); 26 | Emission( const Engine &engine, const Fuel &fuel, const double SO2ToSO4Ratio); 27 | Emission( const Emission &e ); 28 | ~Emission( ); 29 | void Populate_withEngine( const Engine &engine ); 30 | void Populate_withFuel( const Fuel &fuel ); 31 | Emission& operator=( const Emission &em ); 32 | Emission& operator+( const Emission &em ); 33 | double getCO2( ) const; 34 | double getH2O( ) const; 35 | double getNOx( ) const; 36 | double getNO( ) const; 37 | double getNO2( ) const; 38 | double getHNO2( ) const; 39 | double getSO2( ) const; 40 | double getCO( ) const; 41 | double getHC( ) const; 42 | double getCH4( ) const; 43 | double getC2H6( ) const; 44 | double getPRPE( ) const; 45 | double getALK4( ) const; 46 | double getCH2O( ) const; 47 | double getALD2( ) const; 48 | double getGLYX( ) const; 49 | double getMGLY( ) const; 50 | double getSO2toSO4( ) const; 51 | double getSoot( ) const; 52 | double getSootRad( ) const; 53 | std::string getEngineName( ) const; 54 | std::string getFuelChem( ) const; 55 | void Debug( ) const; 56 | 57 | protected: 58 | 59 | /* Gaseous species */ 60 | double CO2; /* [g/kg fuel] */ 61 | double H2O; /* [g/kg fuel] */ 62 | double NOx; /* [g/kg fuel] */ 63 | double NO; /* [g/kg fuel] */ 64 | double NO2; /* [g/kg fuel] */ 65 | double HNO2; /* [g/kg fuel] */ 66 | double SO2; /* [g/kg fuel] */ 67 | double CO; /* [g/kg fuel] */ 68 | double HC; /* [g/kg fuel] */ 69 | double CH4; /* [g/kg fuel] */ 70 | double C2H6; /* [g/kg fuel] */ 71 | double PRPE; /* [g/kg fuel] */ 72 | double ALK4; /* [g/kg fuel] */ 73 | double CH2O; /* [g/kg fuel] */ 74 | double ALD2; /* [g/kg fuel] */ 75 | double GLYX; /* [g/kg fuel] */ 76 | double MGLY; /* [g/kg fuel] */ 77 | 78 | /* BC */ 79 | double Soot; /* [g/kg fuel] */ 80 | double SootRad; /* [m] */ 81 | 82 | /* Conversion ratio */ 83 | double SO2toSO4; /* unitless in [0-1] */ 84 | 85 | std::string engineName; 86 | std::string fuelChem; 87 | 88 | private: 89 | 90 | }; 91 | 92 | #endif /* EMISSION_H_INCLUDED */ 93 | -------------------------------------------------------------------------------- /Code.v05-00/src/LAGRID/FreeCoordBoxGrid.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "LAGRID/FreeCoordBoxGrid.hpp" 4 | 5 | namespace LAGRID { 6 | FreeCoordBoxGrid::FreeCoordBoxGrid(const Vector_1D& dx, const Vector_1D& dy, const Vector_2D& phi, const Vector_1D& x0, double y0, double cutoff) { 7 | auto isInteriorCell = [&](std::size_t i, std::size_t j) -> bool { 8 | bool edgeIndex = (i == 0 || j == 0 || i == dx.size() - 1 || j == dy.size() - 1); 9 | return !edgeIndex && (phi[j+1][i] > cutoff && phi[j-1][i] > cutoff && 10 | phi[j][i+1] > cutoff && phi[j][i-1] > cutoff); 11 | }; 12 | 13 | double curr_y = y0; // Y coordinate of bottom edge of the cell row 14 | for(std::size_t j = 0; j < dy.size(); j++) { 15 | double curr_x = x0[j]; // X coord of left edge of cell column 16 | for(std::size_t i = 0; i < dx.size(); i++) { 17 | if(phi[j][i] < cutoff) { 18 | curr_x += dx[j]; 19 | continue; 20 | } 21 | boxes.emplace_back(curr_x, curr_y + dy[j], curr_x + dx[j], curr_y, phi[j][i] * dx[j] * dy[j]); 22 | if(!isInteriorCell(i, j)) { 23 | boundaryBoxIndices.push_back(boxes.size() - 1); 24 | } 25 | curr_x += dx[j]; 26 | } 27 | curr_y += dy[j]; 28 | } 29 | setMinMaxCoords(); 30 | } 31 | 32 | FreeCoordBoxGrid::FreeCoordBoxGrid(const Vector_1D& dx, const Vector_1D& dy, const Vector_2D& phi, const Vector_1D& x0, double y0, const vector>& mask) { 33 | std::size_t nx = phi[0].size(); 34 | auto isInteriorCell = [&](std::size_t i, std::size_t j) -> bool { 35 | bool edgeIndex = (i == 0 || j == 0 || i == nx - 1 || j == dy.size() - 1); 36 | return !edgeIndex && (mask[j+1][i] == 1 && mask[j-1][i] == 1 && 37 | mask[j][i+1] == 1 && mask[j][i-1] == 1); 38 | }; 39 | 40 | double curr_y = y0; // Y coordinate of bottom edge of the cell row 41 | 42 | for(std::size_t j = 0; j < dy.size(); j++) { 43 | double curr_x = x0[j]; // X coord of left edge of cell column 44 | for(std::size_t i = 0; i < nx; i++) { 45 | if(mask[j][i] == 0) { 46 | curr_x += dx[j]; 47 | continue; 48 | } 49 | boxes.emplace_back(curr_x, curr_y + dy[j], curr_x + dx[j], curr_y, phi[j][i] * dx[j] * dy[j]); 50 | if(!isInteriorCell(i, j)) { 51 | boundaryBoxIndices.push_back(boxes.size() - 1); 52 | } 53 | curr_x += dx[j]; 54 | } 55 | curr_y += dy[j]; 56 | } 57 | 58 | setMinMaxCoords(); 59 | } 60 | 61 | void FreeCoordBoxGrid::setMinMaxCoords() { 62 | minX = std::numeric_limits::max(); 63 | minY = std::numeric_limits::max(); 64 | maxX = std::numeric_limits::min(); 65 | maxY = std::numeric_limits::min(); 66 | for (auto& b: boxes) { 67 | if(b.topLeftX < minX) { 68 | minX = b.topLeftX; 69 | } 70 | if(b.botRightY < minY) { 71 | minY = b.botRightY; 72 | } 73 | if(b.topLeftY > maxY) { 74 | maxY = b.topLeftY; 75 | } 76 | if(b.botRightX > maxX) { 77 | maxX = b.botRightX; 78 | } 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Code.v05-00/include/Core/Mesh.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* Mesh Header File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 7/26/2018 */ 10 | /* File : Mesh.hpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #ifndef MESH_H_INCLUDED 15 | #define MESH_H_INCLUDED 16 | 17 | #include "Util/ForwardDecl.hpp" 18 | #include "Core/Cluster.hpp" 19 | #include "Core/Input_Mod.hpp" 20 | 21 | enum class MeshDomainLimitsSpec : unsigned char{ 22 | CENTERED_LIMITS = 0, //all domain limits must be positive 23 | ABS_COORDS = 1 // regular x,y coords 24 | }; 25 | class Mesh 26 | { 27 | public: 28 | Mesh(const OptInput& optInput); 29 | Mesh(int nx, int ny, double xlim_left, double xlim_right, double ylim_up, double ylim_down, MeshDomainLimitsSpec limitsSpec = MeshDomainLimitsSpec::CENTERED_LIMITS); 30 | void Ring2Mesh( Cluster &c ); 31 | void MapWeights( ); 32 | inline const Vector_1D& x( ) const { return x_; } 33 | inline const Vector_1D& y( ) const { return y_; } 34 | inline const Vector_1D& xE( ) const { return x_e_; } 35 | inline const Vector_1D& yE( ) const { return y_e_; } 36 | inline const Vector_1D& dx( ) const { return dx_; } 37 | inline const Vector_1D& dy( ) const { return dy_; } 38 | inline const Vector_2D& areas( ) const { return areas_; } 39 | inline double hx( ) const { return hx_; } 40 | inline double hy( ) const { return hy_; } 41 | inline UInt Nx() const { return nx; } 42 | inline UInt Ny() const { return ny; } 43 | inline const Vector_3D& map( ) const { return weights; } 44 | inline const Vector_1Dui& nMap( ) const { return nCellMap; } 45 | inline const Vector_2Dui& mapIndex( ) const { return mapIndex_; } 46 | Vector_3D weights; 47 | 48 | void updateVertGrid( const Vector_1D& yE_new ); 49 | 50 | private: 51 | 52 | void initCoordVectors(MeshDomainLimitsSpec limitsSpec); 53 | 54 | inline void calcAreas() { 55 | // UInt to be consistent with mesh size definition 56 | for ( UInt j = 0; j < ny; j++ ) { 57 | for ( UInt i = 0; i < nx; i++ ) { 58 | areas_[j][i] = dx_[i] * dy_[j]; 59 | } 60 | } 61 | } 62 | 63 | /* Cell center coordinates */ 64 | Vector_1D x_, y_; 65 | 66 | /* Cell edges */ 67 | Vector_1D x_e_, y_e_; 68 | 69 | /* Cell dimensions */ 70 | Vector_1D dx_, dy_; 71 | 72 | /* Cell areas */ 73 | Vector_2D areas_; 74 | 75 | /* Total area */ 76 | double totArea_; 77 | /* Cell area */ 78 | double cellArea_; 79 | 80 | double xlim_right, xlim_left, ylim_up, ylim_down; 81 | double hx_, hy_; 82 | UInt nx, ny; 83 | Vector_1Dui nCellMap; 84 | Vector_2Dui mapIndex_; 85 | 86 | }; 87 | 88 | #endif /* MESH_H_INCLUDED */ 89 | 90 | -------------------------------------------------------------------------------- /scripts/simple_met_input/src/thermo.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | ######################### WATER THERMODYNAMIC FUNCTIONS ######################### 5 | def compute_p_sat_liq(T_K): 6 | # Calculates the liquid saturation pressure "p_sat_liq" (in units of Pa). 7 | # This equation can be found in Schumann 2012. 8 | # 9 | # The inputs are as follows: 10 | # - T_K is the absolute temperature in Kelvin 11 | 12 | a = -6096.9385 13 | b = 16.635794 14 | c = -0.02711193 15 | d = 1.673952e-5 16 | e = 2.433502 17 | 18 | return 100 * np.exp(a / T_K + b + c * T_K + d * T_K * T_K + e * np.log(T_K)) 19 | 20 | 21 | def compute_p_sat_ice(T_K): 22 | # Calculates the ice saturation pressure "p_sat_ice" (in units of Pa) 23 | # The equation can be found in Schumann 2012. 24 | # 25 | # The inputs are as follows 26 | # - T_K is the absolute temperature in Kelvin 27 | 28 | a = -6024.5282 29 | b = 24.7219 30 | c = 0.010613868 31 | d = -1.3198825e-5 32 | e = -0.49382577 33 | 34 | return 100 * np.exp(a / T_K + b + c * T_K + d * T_K * T_K + e * np.log(T_K)) 35 | 36 | 37 | def convert_RH_to_RHi(T_K, RH): 38 | return RH * compute_p_sat_liq(T_K) / compute_p_sat_ice(T_K) 39 | 40 | 41 | def convert_RHi_to_RH(T_K, RHi): 42 | return RHi * compute_p_sat_ice(T_K) / compute_p_sat_liq(T_K) 43 | 44 | 45 | def convert_RH_to_SH(T_K, p_Pa, RH_PC): 46 | # Implements the equations from https://earthscience.stackexchange.com/a/2361 47 | # The output specific humidity is in ratio format. 48 | # The input RH must be in %. 49 | 50 | RH_ratio = RH_PC / 100.0 51 | R_d = 287 # J kg^-1 K^-1 from https://en.wikipedia.org/wiki/Gas_constant#:~:text=Specific%20gas%20constant,-Rspecific&text=for%20dry%20air%20of%2028.964917%20g%2Fmol. 52 | R_v = 461.5 # J kg^-1 K^-1 from https://en.wikipedia.org/wiki/Water_vapor 53 | 54 | e_s_Pa = compute_p_sat_liq(T_K) # Saturation pressure of water vapour 55 | w_s = ( 56 | (R_d / R_v) * e_s_Pa / (p_Pa - e_s_Pa) 57 | ) # Mass mixing ratio of water vapor to dry air at equilibrium (dimensionless) 58 | 59 | w = RH_ratio * w_s # Mass mixing ratio of water vapor to dry air 60 | 61 | return w / (w + 1) 62 | 63 | 64 | def convert_RHi_to_SH(T_K, p_Pa, RHi_PC): 65 | # Implements the equations from https://earthscience.stackexchange.com/a/2361 66 | # The output specific humidity is in ratio format. 67 | # The input RHi must be in %. 68 | 69 | RH_PC = convert_RHi_to_RH(T_K, RHi_PC) 70 | 71 | return convert_RH_to_SH(T_K, p_Pa, RH_PC) 72 | 73 | 74 | def convert_SH_to_RH(T_K, p_Pa, SH): 75 | # Implements the equations from https://earthscience.stackexchange.com/a/2361 76 | # The specific humidity must be in ratio format. The output RH is in % 77 | 78 | R_d = 287 # J kg^-1 K^-1 from https://en.wikipedia.org/wiki/Gas_constant#:~:text=Specific%20gas%20constant,-Rspecific&text=for%20dry%20air%20of%2028.964917%20g%2Fmol. 79 | R_v = 461.5 # J kg^-1 K^-1 from https://en.wikipedia.org/wiki/Water_vapor 80 | 81 | e_s_Pa = compute_p_sat_liq(T_K) # Saturation pressure of water vapour 82 | w_s = ( 83 | (R_d / R_v) * e_s_Pa / (p_Pa - e_s_Pa) 84 | ) # Mass mixing ratio of water vapor to dry air at equilibrium (dimensionless) 85 | 86 | w = SH / (1 - SH) 87 | 88 | return w / w_s * 100 89 | 90 | 91 | def convert_SH_to_RHi(T_K, p_Pa, SH): 92 | # Implements the equations from https://earthscience.stackexchange.com/a/2361 93 | # The specific humidity must be in ratio format. The output RHi is in % 94 | 95 | RH_PC = convert_SH_to_RH(T_K, p_Pa, SH) 96 | 97 | return convert_RH_to_RHi(T_K, RH_PC) 98 | -------------------------------------------------------------------------------- /Code.v05-00/include/Util/MetFunction.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* MetFunction Header File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 11/2/2018 */ 10 | /* File : MetFunction.hpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #ifndef METFUNCTION_H_INCLUDED 15 | #define METFUNCTION_H_INCLUDED 16 | 17 | #include 18 | #include "ForwardDecl.hpp" 19 | 20 | #define ABS(x) ( ((x) >= 0 ) ?(x):(-x) ) 21 | 22 | namespace met 23 | { 24 | 25 | /* Defined meteorological functions */ 26 | 27 | /* International Standard Atmosphere (ISA) */ 28 | 29 | const double ISA_LAPSERATE = 6.5E-03; 30 | const double ISA_HTS = 1.1E+04; 31 | const double ISA_HTP = 2.0E+04; 32 | const double ISA_RHO0 = 1.225E+00; 33 | const double ISA_P0 = 101325; 34 | const double ISA_T0 = 288.15; 35 | 36 | void ISA( const double &z, double &pressure, \ 37 | double &temperature ); 38 | void ISA( const Vector_1D &z, Vector_1D &pressure, \ 39 | Vector_1D &temperature ); 40 | void ISA( const double &z, double &pressure ); 41 | void ISA( const Vector_1D &z, Vector_1D &pressure ); 42 | void ISA_pAlt( double &z, const double &pressure ); 43 | void ISA_pAlt( Vector_1D &z, const Vector_1D &pressure ); 44 | 45 | 46 | double ComputeLapseRate( const double TEMP, const double RHi, \ 47 | const double DEPTH ); 48 | 49 | std::size_t nearestNeighbor( const Vector_1D& xq, double x); 50 | double linearInterp( const Vector_1D& xq, const Vector_1D& yq, double x ); 51 | double linearInterp( double x1, double y1, double x2, double y2, double xq, bool support_extrapolation = false); 52 | 53 | double linInterpMetData(const Vector_1D& altitude_init, const Vector_1D& metVar_init, double altitude_query); 54 | 55 | double satdepth_calc( const Vector_1D& RHi, const Vector_1D& alt, int iFlight, double YLIM_DOWN); 56 | 57 | 58 | inline double rhiCorrection( double rhi, double a = 0.9779, double b = 1.635 ) { 59 | /* 60 | @param: rhi - Relative humidity wrt ice in % 61 | @return: "Corrected" rhi to be biased in favor of ISSRs in % 62 | 63 | Source: Teoh et al (2022) 64 | "Aviation contrail climate effects in the North Atlantic from 2016 to 2021" 65 | Atmospheric Chemistry and Physics 66 | https://doi.org/10.5194/acp-22-10919-2022 67 | */ 68 | 69 | double rhi_abs = rhi / 100.0; 70 | 71 | double rhi_corr = (rhi_abs / a) <= 1 72 | ? rhi_abs / a 73 | : std::min(std::pow(rhi_abs / a, b), 1.65); 74 | return rhi_corr * 100.0; 75 | } 76 | struct newXCoordsPair { 77 | Vector_1D x0_new; 78 | Vector_1D dx_new; 79 | }; 80 | newXCoordsPair calcNewXCoords(const Vector_1D& dy_old, const Vector_1D& dy_new, const Vector_1D& x0_old, const Vector_1D& dx_old, int nx); 81 | } 82 | 83 | #endif /* METFUNCTION_H_INCLUDED */ 84 | -------------------------------------------------------------------------------- /Code.v05-00/include/Core/Engine.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* Engine Header File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 7/26/2018 */ 10 | /* File : Engine.hpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #ifndef ENGINE_H_INCLUDED 15 | #define ENGINE_H_INCLUDED 16 | 17 | #include 18 | #include 19 | 20 | 21 | class Engine 22 | { 23 | 24 | /* Forward declaration */ 25 | class Aircraft; 26 | 27 | friend class Aircraft; 28 | 29 | public: 30 | 31 | Engine( ); 32 | Engine( std::string engineName, std::string engineFileName, double tempe_K, double pres_Pa, double relHum_w, double machNumber ); 33 | Engine( const Engine &e ); 34 | Engine& operator=( const Engine &e ); 35 | ~Engine( ); 36 | bool GetEDB( std::istream &file, std::string engineName, std::string &idle, std::string &approach, std::string &climbout, std::string &takeoff ); 37 | std::string getName() const; 38 | double getEI_NOx() const; 39 | double getEI_NO() const; 40 | double getEI_NO2() const; 41 | double getEI_HNO2() const; 42 | double getEI_CO() const; 43 | double getEI_HC() const; 44 | double getEI_Soot() const; 45 | double getSootRad() const; 46 | double getFuelFlow() const; 47 | double getTheta() const; 48 | double getDelta() const; 49 | void setEI_NOx(const double NOx); 50 | void setEI_CO(const double CO); 51 | void setEI_HC(const double HC); 52 | void setEI_Soot(const double Soot); 53 | void setSootRad(const double sootRad); 54 | void setFuelFlow(const double ff); 55 | 56 | protected: 57 | 58 | /* Engine name */ 59 | std::string Name; 60 | 61 | /* Emission indices */ 62 | /** NOx emission indices */ 63 | double EI_NOx; /* [g/kg fuel] */ 64 | double EI_NO; 65 | double EI_NO2; 66 | double EI_HNO2; 67 | /** CO emission index */ 68 | double EI_CO; /* [g/kg fuel] */ 69 | /** UHC emission index */ 70 | double EI_HC; /* [g/kg fuel] */ 71 | 72 | /* Soot */ 73 | double EI_Soot; /* [g/kg fuel] */ 74 | double SootRad; /* [m] */ 75 | 76 | /* Fuel flow */ 77 | double fuelflow; /* [kg fuel/s] */ 78 | 79 | /* Atmospheric characteristics */ 80 | /** Ratio of ambient to sea-level conditions */ 81 | double theta; /* [-] */ 82 | double delta; /* [-] */ 83 | 84 | private: 85 | 86 | std::vector ratedThrust = std::vector(4); 87 | std::vector LTO_fuelflow = std::vector(4); 88 | std::vector LTO_NOx = std::vector(4); 89 | std::vector LTO_CO = std::vector(4); 90 | std::vector LTO_HC = std::vector(4); 91 | 92 | double NOxtoHNO2 = 0.015; 93 | double NOxtoNO2 = 0.20 * ( 1.0 - NOxtoHNO2 ); 94 | double NOxtoNO = 1.0 - NOxtoNO2 - NOxtoHNO2; 95 | 96 | }; 97 | 98 | #endif /* ENGINE_H_INCLUDED */ 99 | -------------------------------------------------------------------------------- /Code.v05-00/include/FVM_ANDS/BoundaryCondition.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FVM_ANDS_BOUNDARYCONDITION_H 2 | #define FVM_ANDS_BOUNDARYCONDITION_H 3 | 4 | #include 5 | #include 6 | #include "FVM_ANDS_enums.hpp" 7 | namespace FVM_ANDS{ 8 | struct BoundaryCondDescription { 9 | BoundaryCondDescription(); 10 | BoundaryCondDescription(BoundaryConditionFlag bcType); 11 | BoundaryCondDescription(BoundaryConditionFlag bcType, FaceDirection direction, double bcVal, int corrPoint); 12 | BoundaryConditionFlag bcType; 13 | FaceDirection direction; 14 | double bcVal; 15 | int corrPoint; 16 | }; 17 | class Point { 18 | public: 19 | Point() = default; 20 | virtual ~Point() = default; 21 | Point(BoundaryConditionFlag bcType); 22 | Point(BoundaryCondDescription bcDesc); 23 | inline void setBC(BoundaryCondDescription bc){ 24 | bc_ = bc; 25 | } 26 | inline BoundaryCondDescription boundaryConds() const { 27 | return bc_; 28 | } 29 | inline BoundaryConditionFlag bcType() const noexcept { 30 | return bc_.bcType; 31 | } 32 | inline double bcVal() const { 33 | return bc_.bcVal; 34 | } 35 | inline FaceDirection bcDirection() const { 36 | return bc_.direction; 37 | } 38 | inline int corrPoint() const { 39 | return bc_.corrPoint; 40 | } 41 | inline void setBCVal(double bcVal){ 42 | bc_.bcVal = bcVal; 43 | } 44 | inline virtual void setBCType(BoundaryConditionFlag bcType){ 45 | bc_.bcType = bcType; 46 | } 47 | constexpr virtual bool isGhost(){ 48 | return false; 49 | } 50 | inline virtual void setSecondaryBC(BoundaryCondDescription bc) { 51 | return; 52 | } 53 | virtual inline std::optional secondBoundaryConds() const { 54 | return std::nullopt; 55 | } 56 | protected: 57 | BoundaryCondDescription bc_; 58 | }; 59 | struct GhostPoint : public Point { 60 | public: 61 | GhostPoint() = delete; 62 | GhostPoint(BoundaryCondDescription bc); 63 | constexpr bool isGhost() override { 64 | return true; 65 | } 66 | inline void setBCType(BoundaryConditionFlag bcType) override { 67 | bc_.bcType = static_cast((static_cast(bcType) < 100) * 100 + static_cast(bcType)); 68 | } 69 | }; 70 | struct IntBoundPoint : public Point { 71 | public: 72 | IntBoundPoint() = delete; 73 | IntBoundPoint(BoundaryCondDescription bc1); 74 | IntBoundPoint(BoundaryCondDescription bc1, BoundaryCondDescription bc2); 75 | inline void setSecondaryBC(BoundaryCondDescription bc) override { 76 | secondary_bc_ = bc; 77 | } 78 | inline std::optional secondBoundaryConds() const override{ 79 | return secondary_bc_; 80 | } 81 | 82 | private: 83 | std::optional secondary_bc_; 84 | }; 85 | struct BoundaryConditions { 86 | BoundaryConditionFlag bcType_top; 87 | BoundaryConditionFlag bcType_left; 88 | BoundaryConditionFlag bcType_right; 89 | BoundaryConditionFlag bcType_bot; 90 | Vector_1D bcVals_top; 91 | Vector_1D bcVals_left; 92 | Vector_1D bcVals_right; 93 | Vector_1D bcVals_bot; 94 | }; 95 | } 96 | #endif -------------------------------------------------------------------------------- /Code.v05-00/tests/test_solver_helpfunctions.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #ifndef TEST_SOLVER_HELPFUNCTIONS_H 7 | #define TEST_SOLVER_HELPFUNCTIONS_H 8 | double l2norm(const Vector_2D& vec){ 9 | int ny = vec.size(); 10 | int nx = vec[0].size(); 11 | double norm = 0; 12 | for(int i = 0; i < nx; i++){ 13 | for(int j = 0; j < ny; j++){ 14 | norm += vec[j][i] * vec[j][i]; 15 | } 16 | } 17 | return std::sqrt(norm); 18 | } 19 | double l2err(const Vector_2D& exact, const Vector_2D& solution){ 20 | int ny = exact.size(); 21 | int nx = exact[0].size(); 22 | double err = 0; 23 | for(int i = 0; i < nx; i++){ 24 | for(int j = 0; j < ny; j++){ 25 | err += std::pow(solution[j][i] - exact[j][i],2); 26 | } 27 | } 28 | return std::sqrt(err)/l2norm(exact); 29 | } 30 | //Can't use this to test SANDS because nontrivial to add required source terms 31 | void setVecToPrescribedSoln(Vector_2D& v, double t, double dx, double dy){ 32 | int ny = v.size(); 33 | int nx = v[0].size(); 34 | for(int i = 0; i < nx; i++){ 35 | for(int j = 0; j < ny; j++){ 36 | double x = dx*i; 37 | double y = dy*j; 38 | v[j][i] = std::exp(-t) * std::sin(physConst::PI*x) * std::sin(physConst::PI*y); 39 | } 40 | } 41 | } 42 | 43 | void initTestVecAdvection(Vector_2D& v, double dx, double dy){ 44 | int ny = v.size(); 45 | int nx = v[0].size(); 46 | for(int i = 0; i < nx; i++){ 47 | for(int j = 0; j < ny; j++){ 48 | double x = dx*i; 49 | double y = dy*j; 50 | if(x < 0.25 && y < 0.25) 51 | v[j][i] = std::sin(physConst::PI*4*x) * std::sin(physConst::PI*4*y); 52 | else 53 | v[j][i] = 0; 54 | } 55 | } 56 | } 57 | 58 | void initTestVecShear(Vector_2D& v, double dx, double dy){ 59 | int ny = v.size(); 60 | int nx = v[0].size(); 61 | for(int i = 0; i < nx; i++){ 62 | for(int j = 0; j < ny; j++){ 63 | double x = dx*i; 64 | double y = dy*j; 65 | if(x > 0.25){ 66 | v[j][i] = 0; 67 | continue; 68 | } 69 | v[j][i] = std::sin(physConst::PI * 4 * x); 70 | } 71 | } 72 | } 73 | 74 | std::tuple vecMax2D(const Vector_2D& v, double dx, double dy){ 75 | double max = std::numeric_limits::min(); 76 | double max_x = 0; 77 | double max_y = 0; 78 | int ny = v.size(); 79 | int nx = v[0].size(); 80 | for(int i = 0; i < nx; i++){ 81 | for(int j = 0; j < ny; j++){ 82 | if(v[j][i] > max){ 83 | max = v[j][i]; 84 | max_x = dx*i; 85 | max_y = dy*i; 86 | } 87 | } 88 | } 89 | //std::cout << "max:" << max << ", max x: " << max_j << ", maxi: " << max_i << std::endl; 90 | return std::make_tuple(max, max_x, max_y); 91 | } 92 | 93 | std::tuple vecMin2D(const Vector_2D& v, double dx, double dy){ 94 | double min = std::numeric_limits::max(); 95 | double min_x = 0; 96 | double min_y = 0; 97 | int ny = v.size(); 98 | int nx = v[0].size(); 99 | for(int i = 0; i < nx; i++){ 100 | for(int j = 0; j < ny; j++){ 101 | if(v[j][i] < min){ 102 | min = v[j][i]; 103 | min_x = dx*i; 104 | min_y = dy*i; 105 | } 106 | } 107 | } 108 | //std::cout << "max:" << max << ", max x: " << max_j << ", maxi: " << max_i << std::endl; 109 | return std::make_tuple(min, min_x, min_y); 110 | } 111 | #endif -------------------------------------------------------------------------------- /scripts/simple_met_input/src/moist.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | ###### 4 | ## Moist layer shape Creation 5 | ###### 6 | 7 | 8 | def trapezium_moist_layer( 9 | centre_altitude_m, 10 | moist_depth_m, 11 | RHi_background_PC=0.0, 12 | RHi_peak_PC=150, 13 | grad_RHi_PC_per_m=None, 14 | alt_resolution_m=100, 15 | upper_alt_m=11001, 16 | ): 17 | # Creates a RHi (%) and altitude (m) vector that represents a trapezium in an alt vs RHi 18 | # graph to simulate a moist region. 19 | # 20 | # The altitude is sampled at intervals with spacing of alt_resolution_m, up until 21 | # upper_alt_m (not inclusive of this) 22 | # 23 | # The depth of the moist region indicates where the relative humidity is above background 24 | # levels. 25 | # 26 | # The generated trapezium is defined from the sides inwards, meaning that if it is too 27 | # narrow, the peak RHi will not be reached anywhere in the moist region. 28 | 29 | altitudes_m = np.arange(start=0, stop=upper_alt_m, step=alt_resolution_m) 30 | 31 | # Add the missing key points to the altutude array 32 | if not np.any(altitudes_m == centre_altitude_m): 33 | altitudes_m = np.append(altitudes_m, centre_altitude_m) 34 | 35 | thresh_upper_m = centre_altitude_m + moist_depth_m / 2.0 36 | thresh_lower_m = centre_altitude_m - moist_depth_m / 2.0 37 | 38 | if not np.any(altitudes_m == thresh_upper_m): 39 | altitudes_m = np.append(altitudes_m, thresh_upper_m) 40 | 41 | if not np.any(altitudes_m == thresh_lower_m): 42 | altitudes_m = np.append(altitudes_m, thresh_lower_m) 43 | 44 | # Add points adjacent to the threshold in order to reduce interpolation distortion of the trapezium 45 | if grad_RHi_PC_per_m is None: 46 | if not np.any(altitudes_m == thresh_upper_m + 1e-6): 47 | altitudes_m = np.append(altitudes_m, thresh_upper_m + 1e-6) 48 | 49 | if not np.any(altitudes_m == thresh_lower_m - 1e-6): 50 | altitudes_m = np.append(altitudes_m, thresh_lower_m - 1e-6) 51 | 52 | # Create the inner trapezium thresholds if necessary 53 | if grad_RHi_PC_per_m is not None: 54 | thresh_2_m = thresh_lower_m + (RHi_peak_PC - RHi_background_PC) / grad_RHi_PC_per_m 55 | thresh_3_m = thresh_upper_m - (RHi_peak_PC - RHi_background_PC) / grad_RHi_PC_per_m 56 | 57 | if thresh_3_m < thresh_2_m: 58 | thresh_2_m = centre_altitude_m 59 | thresh_3_m = centre_altitude_m 60 | else: 61 | if not np.any(altitudes_m == thresh_2_m): 62 | altitudes_m = np.append(altitudes_m, thresh_2_m) 63 | if not np.any(altitudes_m == thresh_3_m): 64 | altitudes_m = np.append(altitudes_m, thresh_3_m) 65 | 66 | # Sort the altitude array and create the RHi array 67 | altitudes_m = np.sort(altitudes_m) 68 | RHis_PC = np.zeros(altitudes_m.shape) 69 | 70 | # Enforce the moisture step 71 | mask = (altitudes_m >= thresh_lower_m) & (altitudes_m <= thresh_upper_m) 72 | RHis_PC = np.where(mask, RHi_peak_PC, RHi_background_PC) 73 | 74 | # Add the moisture gradient from the sides inwards. 75 | if grad_RHi_PC_per_m is not None: 76 | for i in range(len(altitudes_m)): 77 | current_alt_m = altitudes_m[i] 78 | 79 | if (current_alt_m < thresh_lower_m) or (current_alt_m > thresh_upper_m): 80 | continue 81 | 82 | if current_alt_m <= thresh_2_m: 83 | RHis_PC[i] = ( 84 | RHi_background_PC + (current_alt_m - thresh_lower_m) * grad_RHi_PC_per_m 85 | ) 86 | 87 | if current_alt_m >= thresh_3_m: 88 | RHis_PC[i] = ( 89 | RHi_background_PC + (thresh_upper_m - current_alt_m) * grad_RHi_PC_per_m 90 | ) 91 | 92 | return altitudes_m, RHis_PC 93 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ##### Global default ##### 2 | ## Any file not listed below will not have EOL characters normalized. 3 | ## (Diffing and merging will depend on whether Git thinks the file is really 4 | ## text or binary.) 5 | * -text 6 | 7 | ## Alternatively, we could let Git auto-detect text files and normalize EOL, 8 | ## by setting: 9 | ## * text=auto 10 | 11 | ##### Source code ##### 12 | 13 | ## C++ and C source files 14 | *.h text diff=cpp 15 | *.cc text diff=cpp 16 | *.c text diff=cpp 17 | *.cpp text diff=cpp 18 | *.cxx text diff=cpp 19 | *.hpp text diff=cpp 20 | *.hh text diff=cpp 21 | 22 | ## Python scripts 23 | *.py text eol=lf diff=python 24 | 25 | ## Perl scripts/libraries/modules 26 | *.perl text eol=lf diff=perl 27 | *.pl text eol=lf diff=perl 28 | *.pm text eol=lf diff=perl 29 | 30 | ## Shell scripts 31 | *.sh text eol=lf 32 | *.bash text eol=lf 33 | 34 | ## Windows batch scripts 35 | *.bat text eol=crlf 36 | 37 | ## Shader program source 38 | *.frag text diff=cpp 39 | *.vert text diff=cpp 40 | 41 | ##### Other file types ##### 42 | ## Text files and documentation 43 | *.txt text 44 | README* text 45 | INSTALL* text 46 | LICENSE* text 47 | 48 | ## Non-text documentation 49 | *.html text diff=html 50 | *.pdf binary 51 | *.rtf binary 52 | 53 | ## Doxygen documentation configuration files 54 | Doxyfile text 55 | *.dox text 56 | 57 | ## Image files 58 | *.png binary 59 | *.PNG binary 60 | *.jpg binary 61 | *.JPG binary 62 | *.gif binary 63 | *.GIF binary 64 | *.bmp binary 65 | *.BMP binary 66 | *.ico binary 67 | *.ICO binary 68 | *.ppm binary 69 | *.pgm binary 70 | *.pbm binary 71 | *.xpm -text diff -merge 72 | 73 | ## Vector graphics 74 | *.svg -text diff -merge 75 | 76 | ## Model files 77 | *.obj text diff -merge 78 | *.mtl text diff -merge 79 | *.osg text diff -merge 80 | *.osgt text diff -merge 81 | *.ply text diff -merge 82 | *.stl text diff -merge 83 | *.osgb binary 84 | *.oct binary 85 | *.phi binary 86 | *.rgd binary 87 | *.tet binary 88 | *.tri binary 89 | 90 | ## CMake files 91 | CMakeLists.txt text 92 | 93 | ## Makefiles 94 | Makefile text 95 | makefile text 96 | GNUmakefile text 97 | *.mk text 98 | 99 | ## Various IDE project files, etc 100 | *.sln -text diff merge 101 | *.vcxproj -text diff -merge 102 | *.vcxproj.filters -text diff -merge 103 | *.props -text diff -merge 104 | *.pbxproj -text diff -merge 105 | 106 | ##Resource files and UI design descriptions 107 | *.qrc text 108 | *.ui text 109 | *.rc text 110 | 111 | ## Diff/patch files 112 | *.diff text diff -merge 113 | *.patch text diff -merge 114 | 115 | ## XML and configuration 116 | *.xml text 117 | *.cfg text 118 | 119 | ## Self-reference =) 120 | .gitignore text 121 | .gitattributes text 122 | -------------------------------------------------------------------------------- /Code.v05-00/include/Util/PhysConstant.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* PhysConstant Header File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 7/26/2018 */ 10 | /* File : PhysConstant.hpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | 15 | #ifndef PHYSCONSTANT_H_INCLUDED 16 | #define PHYSCONSTANT_H_INCLUDED 17 | 18 | #include "ForwardDecl.hpp" 19 | 20 | #include "MolarWeights.hpp" 21 | 22 | /* Physical constants */ 23 | #ifndef PHYS_CONSTANTS 24 | #define PHYS_CONSTANTS 25 | 26 | namespace physConst 27 | { 28 | 29 | /* Defined physical parameters */ 30 | 31 | 32 | /* ABSOLUTE PHYSICAL CONSTANTS */ 33 | 34 | /* Double-precision value of \pi */ 35 | static constexpr double PI = 3.141592653589793238460; 36 | 37 | /* Avogadro number , Unit : [ molecules / mol ] */ 38 | static constexpr double Na = 6.022140857E+23; 39 | 40 | /* Boltzmann constant, Unit : [ J / K ] */ 41 | static constexpr double kB = 1.380648528E-23; 42 | 43 | /* Ideal gas constant, Unit : [ J / ( K.mol ) ] */ 44 | static constexpr double R = 8.314459848E+00; 45 | 46 | /* Specific gas constant, Unit : [ J / (K.kg) ] */ 47 | static constexpr double R_Air = R / MW_Air; 48 | 49 | 50 | /* THERMODYNAMIC QUANTITIES */ 51 | 52 | /* Specific heat capacity of air at 300K, Unit : [ kJ / ( kg K ) ] */ 53 | static constexpr double CP_Air = 1.005E+00; 54 | 55 | /* Heat capacity ratio of air, Unit : [ - ] */ 56 | static constexpr double GAMMA_Air = 1.4; 57 | 58 | 59 | /* MOLECULAR PROPERTIES */ 60 | 61 | /* Mass of one air molecule, Unit : [ kg ] */ 62 | static constexpr double M_Air = MW_Air / Na; 63 | 64 | /* Density of water, Unit : [ kg / m ^ 3 ] */ 65 | static constexpr double RHO_H2O = 1.000E+03; 66 | 67 | /* Density of ice, Unit : [ kg / m ^ 3 ] */ 68 | static constexpr double RHO_ICE = 9.167E+02; 69 | 70 | /* Density of ice, Unit : [ kg / m ^ 3 ] */ 71 | static constexpr double RHO_NAT = 1.626E+03; 72 | 73 | /* Density of sulfuric acid, Unit : [ kg / m ^ 3 ] */ 74 | static constexpr double RHO_SULF = 1.600E+03; 75 | 76 | /* Density of soot, Unit : [ kg / m ^ 3 ] */ 77 | static constexpr double RHO_SOOT = 2.000E+03; 78 | 79 | 80 | /* EARTH'S PHYSICAL PARAMETERS */ 81 | 82 | /* Acceleration due to gravity at the surface, Unit : [ m / s^2 ] */ 83 | static constexpr double g = 9.80665E+00; 84 | 85 | /* Pressure at sea level, Unit : [ Pa ] */ 86 | static constexpr double PRES_SL = 101325.0; 87 | 88 | /* 1 Atmosphere, Unit : [ Pa ] */ 89 | static constexpr double ATM = PRES_SL; 90 | 91 | /* Temperature at sea level, Unit : [ K ] */ 92 | static constexpr double TEMP_SL = 288.15; 93 | 94 | /* Reference temperature, Unit : [ K ] */ 95 | static constexpr double TEMP_REF = 273.15; 96 | 97 | 98 | /* ATMOSPHERIC PARAMETERS */ 99 | 100 | /* Adiabatic temperature lapse rate, Unit : [ K / km ] */ 101 | static constexpr double GAMMA_AD = -g / CP_Air; 102 | 103 | /* Turbulent dissipation rate, 104 | * Range : ( 1.0E-08 - 1.0E-02 ), 105 | * Unit : [ m ^ 2 / s ^ 3 ] 106 | * Source: U. Schumann, A contrail cirrus prediction model, Geo. Sc. Dev., 2012 */ 107 | static constexpr double EPSILON = 1.00E-05; 108 | 109 | } 110 | 111 | #endif /* PHYS_CONSTANTS */ 112 | 113 | #endif /* PHYSCONSTANT_H_INCLUDED */ 114 | -------------------------------------------------------------------------------- /Code.v05-00/include/Core/TimestepVarsWrapper.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #ifndef TIMESTEPVARSWRAPPER_H_INCLUDED 4 | #define TIMESTEPVARSWRAPPER_H_INCLUDED 5 | struct TimestepVarsWrapper 6 | { 7 | 8 | // DO NOT change the order of the variables declared here. 9 | // It may cause undefined behavior in the constructor. 10 | // - MX 11 | /* 12 | * - tEmission is the local emission time expressed in hours 13 | * (between 0.0 and 24.0) 14 | * - tInitial is the local time at which the simulation starts in hours 15 | * - simulationTime represents the simulation time (in hours) (now read from 16 | * input file) 17 | * - tFinal corresponds to the final time of the simulation expressed in hours 18 | */ 19 | 20 | /* Define emission and simulation time */ 21 | double tEmission_h; 22 | double tInitial_h; 23 | double tFinal_h; 24 | double tInitial_s; 25 | double tFinal_s; 26 | 27 | /* Current time in [s] */ 28 | double curr_Time_s; /* [s] */ 29 | /* Time step in [s] */ 30 | double dt; /* [s] */ 31 | 32 | /* Create time array */ 33 | 34 | /* Vector of time in [s] */ 35 | std::vector timeArray; 36 | 37 | /* Time counter [-] */ 38 | int nTime; 39 | 40 | bool LAST_STEP; 41 | bool ITS_TIME_FOR_TRANSPORT; 42 | bool ITS_TIME_FOR_CHEM; 43 | bool ITS_TIME_FOR_LIQ_COAGULATION; 44 | bool ITS_TIME_FOR_ICE_COAGULATION; 45 | bool ITS_TIME_FOR_ICE_GROWTH; 46 | bool ITS_TIME_FOR_TEMPPERTURB; 47 | 48 | double TRANSPORT_DT; // [s] 49 | double CHEMISTRY_DT; // [s] 50 | double COAG_DT; //[s] 51 | double TEMP_PERTURB_DT; //[s] 52 | double ICE_GROWTH_DT; // [s] 53 | 54 | double lastTimeTransport; 55 | double lastTimeChem; 56 | double lastTimeLiqCoag; 57 | double lastTimeIceCoag; 58 | double lastTimeIceGrowth; 59 | double lastTimeTempPerturb; 60 | 61 | double totalIceParticles_before; 62 | double totalIceMass_before; 63 | double totalIceParticles_initial; 64 | double totalIceMass_initial; 65 | double totalIceParticles_now; 66 | double totalIceMass_now; 67 | double totalIceParticles_last; 68 | double totalIceMass_last; 69 | double totalIceParticles_after; 70 | double totalIceMass_after; 71 | double totPart_lost; 72 | double totIce_lost; 73 | double ABORT_THRESHOLD; 74 | 75 | TimestepVarsWrapper() = default; 76 | TimestepVarsWrapper(const Input &input, const OptInput &Input_Opt); 77 | inline void setTimeArray(const Vector_1D &vec) 78 | { 79 | timeArray = vec; 80 | } 81 | inline bool checkLastStep() 82 | { 83 | LAST_STEP = (curr_Time_s + dt >= tFinal_s); 84 | return LAST_STEP; 85 | } 86 | inline bool checkTimeForTransport() 87 | { 88 | ITS_TIME_FOR_TRANSPORT = (((curr_Time_s + dt - lastTimeTransport) >= TRANSPORT_DT) || LAST_STEP); 89 | return ITS_TIME_FOR_TRANSPORT; 90 | } 91 | inline bool checkTimeForChem() 92 | { 93 | ITS_TIME_FOR_CHEM = (((curr_Time_s + dt - lastTimeChem) >= CHEMISTRY_DT) || LAST_STEP); 94 | return ITS_TIME_FOR_CHEM; 95 | } 96 | inline bool checkTimeForTempPerturb() 97 | { 98 | ITS_TIME_FOR_TEMPPERTURB = (((curr_Time_s + dt - lastTimeTempPerturb) >= TEMP_PERTURB_DT) || LAST_STEP); 99 | return ITS_TIME_FOR_TEMPPERTURB; 100 | } 101 | inline bool checkTimeForLiqCoag() 102 | { 103 | ITS_TIME_FOR_LIQ_COAGULATION = (((curr_Time_s + dt - lastTimeLiqCoag) >= COAG_DT) || LAST_STEP); 104 | return ITS_TIME_FOR_LIQ_COAGULATION; 105 | } 106 | inline bool checkTimeForIceCoag() 107 | { 108 | ITS_TIME_FOR_ICE_COAGULATION = (((curr_Time_s + dt - lastTimeIceCoag) >= COAG_DT) || LAST_STEP); 109 | return ITS_TIME_FOR_ICE_COAGULATION; 110 | } 111 | inline bool checkTimeForIceGrowth() 112 | { 113 | /* TODO: For now perform growth at every time step */ 114 | ITS_TIME_FOR_ICE_GROWTH = (((curr_Time_s + dt - lastTimeIceGrowth) >= ICE_GROWTH_DT) || LAST_STEP); 115 | return ITS_TIME_FOR_ICE_GROWTH; 116 | } 117 | }; 118 | 119 | #endif -------------------------------------------------------------------------------- /Code.v05-00/tests/test_nucleation.cpp: -------------------------------------------------------------------------------- 1 | #include "AIM/Nucleation.hpp" 2 | #include 3 | #include 4 | 5 | using namespace AIM; 6 | 7 | TEST_CASE ("Nucleation", "[single-file]" ) { 8 | 9 | SECTION( "Surface tension" ) { 10 | // All tests based on data from Figure 1, Vehkamaki et al. (2002) 11 | 12 | // x_m = 0.123 13 | REQUIRE( sigma(0.123, 192.767) == Catch::Approx(0.0866).margin(1e-4)); 14 | REQUIRE( sigma(0.123, 301.697) == Catch::Approx(0.0722).margin(1e-4)); 15 | 16 | // x_m = 0.503 17 | REQUIRE( sigma(0.503, 191.882) == Catch::Approx(0.0833).margin(1e-4)); 18 | REQUIRE( sigma(0.503, 302.583) == Catch::Approx(0.0757).margin(1e-4)); 19 | 20 | // x_m = 0.672 21 | REQUIRE( sigma(0.672, 190.774) == Catch::Approx(0.0789).margin(1e-4)); 22 | REQUIRE( sigma(0.672, 303.469) == Catch::Approx(0.0745).margin(1e-4)); 23 | } 24 | 25 | SECTION( "Density sulfuric acid solution" ) { 26 | // All tests based on data from Figure 2, Vehkamaki et al. (2002) 27 | // x_m = 0.123 28 | REQUIRE( rho(0.123, 192.289)/1000. == Catch::Approx(1.112).epsilon(1e-2) ); 29 | REQUIRE( rho(0.123, 304.971)/1000. == Catch::Approx(1.0776).epsilon(1e-2)); 30 | 31 | // x_m = 0.503 32 | REQUIRE( rho(0.503, 191.214)/1000. == Catch::Approx(1.482).epsilon(1e-2)); 33 | REQUIRE( rho(0.503, 304.046)/1000. == Catch::Approx(1.389).epsilon(1e-2)); 34 | 35 | // x_m = 0.765 36 | REQUIRE( rho(0.765, 190.520)/1000. == Catch::Approx(1.798).epsilon(1e-2)); 37 | REQUIRE( rho(0.765, 303.584)/1000. == Catch::Approx(1.682).epsilon(1e-2)); 38 | } 39 | 40 | SECTION( "Critical cluster mole fraction, sulfuric acid") { 41 | 42 | // When RH=1, sulfur_conc = 1, expression simplifies greatly 43 | REQUIRE(x_star(250.0, 1.0, 1.0) == Catch::Approx(0.740997 - 0.00266379*250.0)); 44 | 45 | // Regression test 46 | REQUIRE(x_star(250.0, 0.5, 1.0e10) == Catch::Approx(0.3136351646)); 47 | } 48 | 49 | SECTION( "H2SO4 Nucleation rate") { 50 | // Data obtained from Figure 2 in Maattanen et al. (2017) 51 | 52 | // [H2SO4] = 5e5 /cm3 53 | double x_m = x_star(200.0, 0.01e-2, 5.0e5); 54 | REQUIRE(nuclRate(200.0, x_m, 0.01e-2, 5.0e5) == Catch::Approx(0.000007315869129751891).epsilon(0.2)); 55 | x_m = x_star(191.4772, 0.01e-2, 5.0e5); 56 | REQUIRE(nuclRate(191.4772, x_m, 0.01e-2, 5.0e5) == Catch::Approx(0.026366508987303607).epsilon(0.2)); 57 | 58 | // [H2SO4] = 5e8 /cm3, 59 | x_m = x_star(241.12, 1.0, 5.0e8); 60 | 61 | // This test acts more like order of magnitude test 62 | // (I suspect the graphical data extraction method used is very sensitive 63 | // for a log plot like the one used) 64 | REQUIRE(nuclRate(241.12, x_m, 1.0, 5.0e8) == Catch::Approx(31084029.570249166).epsilon(0.5)); 65 | 66 | x_m = x_star(288.94, 1.0, 5.0e8); 67 | REQUIRE(nuclRate(288.94, x_m, 1.0, 5.0e8) == Catch::Approx(0.04859226736697418).epsilon(0.2)); 68 | 69 | 70 | // This test is based on data from Figure 8 in Vehkamaki et al. (2002) 71 | x_m = x_star(236.0, 0.55, 666084629.0809168); 72 | 73 | REQUIRE(nuclRate(236.0, x_m, 0.55, 666084629.0809168) == Catch::Approx( 142197696.75857794).epsilon(1e-1)); 74 | } 75 | 76 | SECTION ( "Critical cluster molecule number" ) { 77 | // This test is based on data from Figure 8 in Vehkamaki et al. (2002) 78 | // Some deviation is expected as the plot shows theoretical cluster size 79 | double x_m = x_star(236.0, 0.55, 666084629.0809168); 80 | REQUIRE(nTot(236.,x_m, 0.55, 4795689.579) == Catch::Approx(10.25).epsilon(1e-1)); 81 | } 82 | 83 | SECTION ( "Radius of cluster size" ) { 84 | // Regression test 85 | REQUIRE(radCluster(0.3, 1.0e9) == Catch::Approx(223.6e-9).epsilon(1e-4)); 86 | } 87 | 88 | SECTION ( "Treshold sulfuric acid concentration" ) { 89 | // Based on Figure 7 in Vehkamaki et al. (2002) 90 | REQUIRE(nThresh(190.15, 13.977e-2) == Catch::Approx(67728.15277441413).epsilon(0.1)); 91 | REQUIRE(nThresh(240.15, 97.14e-2) == Catch::Approx(2894266.1247167457).epsilon(0.1)); 92 | } 93 | } -------------------------------------------------------------------------------- /Code.v05-00/include/Core/MPMSimVarsWrapper.hpp: -------------------------------------------------------------------------------- 1 | #include "Core/Input_Mod.hpp" 2 | #include "Core/Input.hpp" 3 | 4 | #ifndef SIMVARSWRAPPER_H_INCLUDED 5 | #define SIMVARSWRAPPER_H_INCLUDED 6 | 7 | struct MPMSimVarsWrapper{ 8 | /* ======================================================================= */ 9 | /* --- Input options from the SIMULATION MENU ---------------------------- */ 10 | /* ======================================================================= */ 11 | 12 | bool RUN_BOXMODEL; 13 | bool BUILD_LUT; 14 | bool SAVE_FORWARD; 15 | bool ADJOINT; 16 | std::string BACKG_FILENAME; 17 | bool THREADED_FFT; 18 | bool USE_WISDOM; 19 | std::string FFTW_DIR; 20 | 21 | /* ======================================================================= */ 22 | /* ---- Input options from the TRANSPORT MENU ---------------------------- */ 23 | /* ======================================================================= */ 24 | 25 | bool TRANSPORT; 26 | bool FILLNEG; 27 | 28 | bool UPDRAFT; 29 | double UPDRAFT_TIME; 30 | double UPDRAFT_VEL; 31 | 32 | /* ======================================================================= */ 33 | /* ---- Input options from the CHEMISTRY MENU ---------------------------- */ 34 | /* ======================================================================= */ 35 | 36 | bool CHEMISTRY; 37 | bool HETCHEM; 38 | std::string JRATE_FOLDER; 39 | 40 | /* ======================================================================= */ 41 | /* ---- Input options from the AEROSOL MENU ------------------------------ */ 42 | /* ======================================================================= */ 43 | 44 | bool GRAVSETTLING; 45 | bool ICE_COAG; 46 | bool LIQ_COAG; 47 | bool ICE_GROWTH; 48 | 49 | /* ======================================================================= */ 50 | /* ---- Input options from the METEOROLOGY MENU -------------------------- */ 51 | /* ======================================================================= */ 52 | 53 | /* Input options from the METEOROLOGY MENU are read in the Meteorology 54 | * subroutine */ 55 | 56 | bool TEMP_PERTURB; 57 | double metDepth; 58 | 59 | /* ======================================================================= */ 60 | /* ---- Input options from the DIAGNOSTIC MENU --------------------------- */ 61 | /* ======================================================================= */ 62 | 63 | std::string DIAG_FILENAME; 64 | 65 | /* ======================================================================= */ 66 | /* ---- Input options from the TIMESERIES MENU --------------------------- */ 67 | /* ======================================================================= */ 68 | 69 | std::string TS_FOLDER; 70 | bool TS_SPEC; 71 | std::string TS_SPEC_FILEPATH; 72 | std::vector TS_SPEC_LIST; 73 | double TS_FREQ; 74 | 75 | bool TS_AERO; 76 | std::string TS_AERO_FILEPATH; 77 | std::vector TS_AERO_LIST; 78 | double TS_AERO_FREQ; 79 | 80 | /* ======================================================================= */ 81 | /* ---- Input options from the PROD & LOSS MENU -------------------------- */ 82 | /* ======================================================================= */ 83 | 84 | /* TODO: Implement PL rates */ 85 | bool SAVE_PL; 86 | bool SAVE_O3PL; 87 | 88 | /* If DIAG_OUTPUT is turned on, make sure that output timestep is a 89 | * multiple of the dynamic timestep */ 90 | 91 | double temperature_K; 92 | double pressure_Pa; 93 | double relHumidity_w; 94 | 95 | /* Compute relative humidity w.r.t ice */ 96 | double relHumidity_i; 97 | 98 | MPMSimVarsWrapper() = default; 99 | MPMSimVarsWrapper(const Input& input, const OptInput& Input_Opt, const double depth_estimate); 100 | inline int LA_MICROPHYSICS() const { return LA_MICROPHYSICS_; } 101 | inline int PA_MICROPHYSICS() const { return PA_MICROPHYSICS_; } 102 | inline bool TRANSPORT_LA() const { return TRANSPORT_LA_; } 103 | inline bool TRANSPORT_PA() const { return TRANSPORT_PA_; } 104 | 105 | // Making these private since these were const in the original PlumeModel 106 | private: 107 | int LA_MICROPHYSICS_; 108 | int PA_MICROPHYSICS_; 109 | bool TRANSPORT_LA_; 110 | bool TRANSPORT_PA_; 111 | 112 | 113 | }; 114 | #endif 115 | -------------------------------------------------------------------------------- /Code.v05-00/include/LAGRID/RemappingFunctions.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LAGRID_REMAPPINGFUNCTIONS_H 2 | #define LAGRID_REMAPPINGFUNCTIONS_H 3 | 4 | #include "LAGRID/FreeCoordBoxGrid.hpp" 5 | #include 6 | #include 7 | #include 8 | 9 | namespace LAGRID { 10 | 11 | struct Remapping { 12 | double x0; 13 | double y0; 14 | double dx; 15 | double dy; 16 | int nx; 17 | int ny; 18 | Remapping(double x0, double y0, double dx, double dy, int nx, int ny) 19 | : x0(x0), 20 | y0(y0), 21 | dx(dx), 22 | dy(dy), 23 | nx(nx), 24 | ny(ny) 25 | { 26 | 27 | } 28 | }; 29 | 30 | struct twoDGridVariable { 31 | twoDGridVariable() = delete; 32 | 33 | //A little bit of template / universal reference magic to minimize the # of copy operations on these huge vectors. 34 | //Enforces that Vec2D is of type Vector_2D and that Vec1D is of type Vec1D. And then we need the decay on the types because 35 | //with a forwarding reference, passing in a Vector_2D by value gets it deduced as a Vector_2D& 36 | //-Michael 37 | template , Vector_2D>>, 39 | typename = std::enable_if_t, Vector_1D>> 40 | > 41 | twoDGridVariable(Vec2D&& phi, Vec1D&& xCoords, Vec1D&& yCoords) : 42 | phi(std::forward(phi)), 43 | xCoords(std::forward(xCoords)), 44 | yCoords(std::forward(yCoords)), 45 | dx(this->xCoords[1] - this->xCoords[0]), 46 | dy(this->yCoords[1] - this->yCoords[0]) 47 | { 48 | } 49 | Vector_2D phi; 50 | Vector_1D xCoords; 51 | Vector_1D yCoords; 52 | double dx; 53 | double dy; 54 | void addBuffer(double bufLen_left, double bufLen_right, double bufLen_top, double bufLen_bot, double fillValue); 55 | }; 56 | 57 | inline double coveredArea(const Remapping& remapping, const MassBox& b, int i, int j) { 58 | //Breaks if the box and the gridcell don't overlap at all. 59 | double gridCell_topLeftX = remapping.x0 + remapping.dx * i; 60 | double gridCell_topLeftY = remapping.y0 + remapping.dy * (j + 1); 61 | double gridCell_botRightX = remapping.x0 + remapping.dx * (i + 1); 62 | double gridCell_botRightY = remapping.y0 + remapping.dy * j; 63 | 64 | //X,Y coords for the portion of the gridcell the box covers 65 | double boxCover_topLeftX = std::max(b.topLeftX, gridCell_topLeftX); 66 | double boxCover_topLeftY = std::min(b.topLeftY, gridCell_topLeftY); 67 | double boxCover_botRightX = std::min(b.botRightX, gridCell_botRightX); 68 | double boxCover_botRightY = std::max(b.botRightY, gridCell_botRightY); 69 | 70 | return (boxCover_botRightX - boxCover_topLeftX) * (boxCover_topLeftY - boxCover_botRightY); 71 | } 72 | 73 | FreeCoordBoxGrid rectToBoxGrid(const Vector_1D& dy_vec, double dx, double x0, double y0, const Vector_2D& phi, const vector>& mask); 74 | 75 | double diffusionLossFunctionExact(const FreeCoordBoxGrid& boxGrid, const Remapping& remapping); 76 | double diffusionLossFunctionBoundaryEstimate(const FreeCoordBoxGrid& boxGrid, const Remapping& remapping); 77 | twoDGridVariable mapToStructuredGrid(const FreeCoordBoxGrid& boxGrid, const Remapping& remapping); 78 | twoDGridVariable getUnusedFraction(const FreeCoordBoxGrid& boxGrid, const Remapping& remapping); 79 | 80 | Vector_2D initVarToGrid(double mass, const Vector_1D& xEdges, const Vector_1D& yEdges, 81 | std::function weightFunction, double logBinRatio = 1 ); 82 | 83 | Vector_2D initVarToGridRectangular(double mass, const Vector_1D& xEdges, const Vector_1D& yEdges, double x0, double y0, 84 | double width, double depth, double logBinRatio ); 85 | 86 | Vector_2D initVarToGridGaussian(double mass, const Vector_1D& xEdges, const Vector_1D& yEdges, double x0, double y0, 87 | double sigmaX, double sigmaY, double logBinRatio = 1); 88 | 89 | Vector_2D initVarToGridBimodalY(double mass, const Vector_1D& xEdges, const Vector_1D& yEdges, double x0, double y0, 90 | double width, double depth, double logBinRatio = 1); 91 | } 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /Code.v05-00/include/Core/Aircraft.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* Aircraft Header File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 7/26/2018 */ 10 | /* File : Aircraft.hpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #ifndef AIRCRAFT_H_INCLUDED 15 | #define AIRCRAFT_H_INCLUDED 16 | 17 | #include 18 | #include 19 | 20 | #include "Core/Input.hpp" 21 | #include "Core/Engine.hpp" 22 | #include "Core/Vortex.hpp" 23 | #include "Core/Meteorology.hpp" 24 | 25 | class Aircraft 26 | { 27 | public: 28 | 29 | /* Constructors */ 30 | 31 | Aircraft( ); 32 | Aircraft( const Input& input, std::string engineFilePath, std::string engineName = "GEnx-2B67B"); 33 | 34 | /* Debug */ 35 | void Debug( ) const; 36 | 37 | /* Compute vortex losses */ 38 | 39 | double VortexLosses( const double N_postjet, const double WV_exhaust, const double N0_ref,\ 40 | const double wingspan_ref ); 41 | 42 | /* Getters: */ 43 | 44 | /* Flight conditions */ 45 | inline double T_CA_K() const { return T_CA_K_; } 46 | inline double RHW_CA_PC() const { return RHW_CA_PC_; } 47 | inline double RHi_CA_PC() const { return RHi_CA_PC_; } 48 | inline double nBV_Hz() const { return nBV_Hz_; } 49 | inline double p_CA_Pa() const { return p_CA_Pa_; } 50 | /* Aircraft name */ 51 | inline std::string Name() const { return Name_; } 52 | /* Flight velocity */ 53 | inline double VFlight() const { return vFlight_ms_; } 54 | /* Mach number */ 55 | inline double Mach() const { return machNumber_; } 56 | /* Fuel consumption per distance */ 57 | inline double fuel_per_dist() const { return fuel_per_dist_; } 58 | /* Wingspan */ 59 | inline double Wingspan() const { return wingspan_; } 60 | /* Current mass */ 61 | inline double currMass() const { return currMass_; } 62 | /* Fuel flow */ 63 | inline double FuelFlow() const { return engine_.getFuelFlow() * engNumber_; } 64 | /* Engine number */ 65 | inline UInt EngNumber() const { return engNumber_; } 66 | /* Engine */ 67 | inline const Engine& engine() const { return engine_; } 68 | /* Vortex */ 69 | inline const Vortex& vortex() const { return vortex_; } 70 | 71 | /* Setters for engine properties */ 72 | void setEI_NOx(const double NOx); 73 | void setEI_CO(const double CO); 74 | void setEI_HC(const double HC); 75 | void setEI_Soot(const double Soot); 76 | void setSootRad(const double sootRad); 77 | void setFuelFlow(const double ff); 78 | void setVFlight(const double Vf, double temperature_K); 79 | void setEngNumber(const double nEng); 80 | void setWingspan(const double span); 81 | void setMass(double mass); 82 | 83 | /* Engine */ 84 | Engine engine_; 85 | 86 | protected: 87 | 88 | /* Flight conditions */ 89 | double T_CA_K_; 90 | double RHW_CA_PC_; 91 | double RHi_CA_PC_; 92 | double nBV_Hz_; 93 | double p_CA_Pa_; 94 | 95 | /* Aircraft name */ 96 | std::string Name_; 97 | 98 | /* Flight speed & mach Number */ 99 | double vFlight_ms_; 100 | double machNumber_; 101 | 102 | /* Fuel consumption */ 103 | double fuel_per_dist_; /* [kg/m] */ 104 | 105 | /* Dimensions */ 106 | double wingspan_; /* [m] */ 107 | 108 | /* Weight */ 109 | double currMass_; /* [kg] */ 110 | 111 | /* Number of engines */ 112 | UInt engNumber_; 113 | 114 | /* Vortex */ 115 | Vortex vortex_; 116 | 117 | private: 118 | 119 | }; 120 | 121 | #endif /* AIRCRAFT_H_INCLUDED */ 122 | -------------------------------------------------------------------------------- /Code.v05-00/include/Core/Parameters.hpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* Parameter Header File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 7/26/2018 */ 10 | /* File : Parameters.hpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #ifndef PARAMETERS_H_INCLUDED 15 | #define PARAMETERS_H_INCLUDED 16 | 17 | /* How to handle multithreading? 18 | * 1. Each cases are run in parallel (efficient for low-requirement runs) 19 | * 2. Each case is run one at a time on multiple CPUs (efficient for contrail 20 | * simulations) */ 21 | 22 | #define PARALLEL_CASES 0 23 | /* Grid parameters */ 24 | 25 | /* Aerosol Size Ratios */ 26 | #define LA_VRAT 1.80E+00 /* Size ratio between two consecutive bins */ 27 | #define PA_VRAT 1.80E+00 /* Size ratio between two consecutive bins */ 28 | 29 | /* Ring structure */ 30 | #define NRING 15 /* Number of rings */ 31 | 32 | /* Diffusion */ 33 | /* The following parameters are now passed as user input parameters */ 34 | //#define DH 1.5E+01 /* Steady-state horizontal diffusion parameter [m2/s] */ 35 | //#define DV 1.5E-01 /* Steady-state vertical diffusion parameter [m2/s] */ 36 | //#define DH0 1.7E+01 /* Initial horizontal diffusion parameter [m2/s] */ 37 | //#define DV0 1.1E-01 /* Initial vertical diffusion parameter [m2/s] */ 38 | #define tH0 7.8E+02 /* Timescale of initial enhanced horizontal diffusion [s] */ 39 | #define tV0 7.8E+02 /* Timescale of initial enhanced vertical diffusion [s] */ 40 | #define DPROF 1 /* Time profile of the initial diffusion parameter [0,1,2] 41 | * 0: Step 42 | * 1: Linear 43 | * 2: Exponential */ 44 | 45 | /* Advection */ 46 | #define VX 0.0E+00 /* Steady-state horizontal advection velocity [m/s] */ 47 | #define VY 0.0E+00 /* Steady-state vertical advection velocity [m/s] */ 48 | //T_SYN and V_SYN are now defined in the input file 49 | //#define T_SYN 3.6E+03 /* Timescale associated to synoptic lifting */ 50 | //#define V_SYN 5.0E-02 /* Velocity magnitude [m/s] */ 51 | #define SYNPROF 1 /* Time profile of the initial synoptic lifting [0,1] 52 | * 0: Step 53 | * 1: Exponential */ 54 | 55 | /* Chemistry parameters */ 56 | #define KPP_RTOLS 1.00E-03 /* Relative tolerances in KPP */ 57 | #define KPP_ATOLS 1.00E-03 /* Absolute tolerances in KPP */ 58 | #define KPPADJ_RTOLS 1.00E-05 /* Relative tolerances in KPP_Adjoint */ 59 | #define KPPADJ_ATOLS 1.00E-04 /* Absolute tolerances in KPP_Adjoint */ 60 | 61 | /* Aerosol parameters */ 62 | #define N_AER 3 /* Number of aerosols considered */ 63 | #define PSC_FULL 1 /* Allow PSC formaiton outsize of Kirner limits? */ 64 | #define LHOMNUCNAT 1 /* Allow homogeneous NAT? */ 65 | #define T_NAT_SUPERCOOL 3.0 /* NAT supercooling requirement [K] */ 66 | #define LSOLIDPSC 1 /* Online solid PSCs? */ 67 | 68 | /* Microphysics parameters */ 69 | #define LA_R_LOW 1.00E-10 /* Sulfates' lower bin radius [m] */ 70 | #define LA_R_HIG 5.00E-07 /* Sulfates' larger bin radius [m] */ 71 | #define PA_R_LOW 5.00E-08 /* Ice/NAT lower bin radius [m] */ 72 | #define PA_R_HIG 8.00E-05 /* Ice/NAT larger bin radius [m] */ 73 | 74 | /* Early plume integration */ 75 | #define VORTEX_SINKING 1 /* Consider vortex sinking? */ 76 | #define EPM_RTOLS 1.00E-05 /* Relative tolerances in EPM */ 77 | #define EPM_ATOLS 1.00E-07 /* Absolute tolerances in EPM */ 78 | 79 | #endif /* PARAMETERS_H_INCLUDED */ 80 | -------------------------------------------------------------------------------- /input_data/init.txt: -------------------------------------------------------------------------------- 1 | # BOF 2 | # 3 | # User input for background concentrations 4 | # 5 | # Lines starting with the "#" symbol are not read! Use it for writting comments. 6 | # 7 | # This file includes ambient conditions which are read by MLChem. 8 | # 9 | # Ambient gaseous mixing ratios are formatted in the following way: 10 | # ---------- 11 | # # SPC 12 | # Value 13 | # ---------- 14 | # where SPC is the species name and Value is the species' mixing ratio. 15 | # 16 | # Aerosol background conditions are formatted in the following way: 17 | # 18 | # ---------- 19 | # # Aer 20 | # Value 21 | # ---------- 22 | # where Aer is the aerosol name and Value is the aerosol's background concentration in [#/cm^3]. 23 | 24 | 25 | # Gaseous species: 26 | # CO2 27 | 3.600E-04 28 | # PPN 29 | 1.448E-11 30 | # BrNO2 31 | 1.230E-21 32 | # IEPOX 33 | 1.230E-21 34 | # PMNN 35 | 1.230E-21 36 | # N2O 37 | 3.208E-07 38 | # N 39 | 4.000E-21 40 | # PAN 41 | 6.630E-11 42 | # ALK4 43 | 6.003E-12 44 | # MAP 45 | 1.230E-21 46 | # MPN 47 | 1.230E-21 48 | # Cl2O2 49 | 1.230E-21 50 | # ETP 51 | 1.230E-21 52 | # HNO2 53 | 4.680E-13 54 | # C3H8 55 | 2.210E-11 56 | # RA3P 57 | 1.230E-21 58 | # RB3P 59 | 1.230E-21 60 | # OClO 61 | 1.230E-21 62 | # ClNO2 63 | 1.230E-21 64 | # ISOP 65 | 1.875E-21 66 | # HNO4 67 | 5.800E-11 68 | # MAOP 69 | 1.230E-21 70 | # MP 71 | 4.810E-12 72 | # ClOO 73 | 1.230E-21 74 | # RP 75 | 1.230E-21 76 | # BrCl 77 | 3.500E-18 78 | # PP 79 | 1.230E-21 80 | # PRPN 81 | 1.230E-21 82 | # SO4 83 | 1.000E-13 84 | # Br2 85 | 1.230E-21 86 | # ETHLN 87 | 1.230E-21 88 | # MVKN 89 | 1.230E-21 90 | # R4P 91 | 1.230E-21 92 | # C2H6 93 | 6.730E-10 94 | # RIP 95 | 1.230E-18 96 | # VRP 97 | 1.230E-21 98 | # ATOOH 99 | 1.230E-21 100 | # IAP 101 | 1.230E-21 102 | # DHMOB 103 | 1.230E-21 104 | # MOBA 105 | 1.230E-21 106 | # MRP 107 | 1.230E-21 108 | # N2O5 109 | 1.220E-11 110 | # ISNOHOO 111 | 1.230E-21 112 | # ISNP 113 | 1.230E-21 114 | # ISOPNB 115 | 1.230E-18 116 | # IEPOXOO 117 | 1.230E-21 118 | # MACRNO2 119 | 1.230E-21 120 | # ROH 121 | 1.230E-21 122 | # MOBAOO 123 | 1.230E-21 124 | # DIBOO 125 | 1.230E-18 126 | # PMN 127 | 5.440E-17 128 | # ISNOOB 129 | 1.230E-21 130 | # INPN 131 | 1.230E-21 132 | # H 133 | 4.000E-20 134 | # BrNO3 135 | 1.700E-13 136 | # PRPE 137 | 2.090E-14 138 | # MVKOO 139 | 1.230E-21 140 | # Cl2 141 | 1.230E-21 142 | # ISOPND 143 | 1.230E-18 144 | # HOBr 145 | 6.600E-14 146 | # A3O2 147 | 1.230E-21 148 | # PROPNN 149 | 1.230E-21 150 | # GLYX 151 | 1.230E-21 152 | # MAOPO2 153 | 1.230E-21 154 | # CH4 155 | 1.760E-06 156 | # GAOO 157 | 1.230E-20 158 | # B3O2 159 | 1.230E-21 160 | # ACET 161 | 5.120E-10 162 | # MACRN 163 | 1.230E-21 164 | # CH2OO 165 | 1.230E-21 166 | # MGLYOO 167 | 1.230E-21 168 | # VRO2 169 | 1.230E-21 170 | # MGLOO 171 | 1.230E-21 172 | # MACROO 173 | 1.230E-21 174 | # PO2 175 | 1.230E-21 176 | # CH3CHOO 177 | 1.230E-21 178 | # MAN2 179 | 1.230E-21 180 | # ISNOOA 181 | 1.230E-18 182 | # H2O2 183 | 2.140E-11 184 | # PRN1 185 | 1.230E-21 186 | # ETO2 187 | 1.230E-21 188 | # KO2 189 | 1.230E-21 190 | # RCO3 191 | 1.230E-21 192 | # HC5OO 193 | 1.230E-21 194 | # GLYC 195 | 1.230E-21 196 | # ClNO3 197 | 1.300E-12 198 | # RIO2 199 | 1.230E-18 200 | # R4N1 201 | 1.230E-21 202 | # HOCl 203 | 1.700E-13 204 | # ATO2 205 | 1.230E-21 206 | # HNO3 207 | 8.150E-11 208 | # ISN1 209 | 1.230E-21 210 | # MAO3 211 | 1.230E-21 212 | # MRO2 213 | 1.230E-21 214 | # INO2 215 | 1.230E-21 216 | # HAC 217 | 1.230E-21 218 | # HC5 219 | 1.230E-18 220 | # MGLY 221 | 1.230E-21 222 | # ISOPNBO2 223 | 1.230E-21 224 | # ISOPNDO2 225 | 1.230E-21 226 | # RO2 227 | 1.230E-21 228 | # R4N2 229 | 1.997E-12 230 | # BrO 231 | 1.300E-14 232 | # RCHO 233 | 4.710E-14 234 | # MEK 235 | 3.276E-12 236 | # ClO 237 | 1.000E-14 238 | # MACR 239 | 5.148E-16 240 | # SO2 241 | 7.250E-12 242 | # MVK 243 | 1.420E-21 244 | # ALD2 245 | 3.215E-12 246 | # MCO3 247 | 1.230E-21 248 | # CH2O 249 | 4.540E-11 250 | # H2O 251 | 3.840E-05 252 | # Br 253 | 9.100E-16 254 | # NO 255 | 4.410E-11 256 | # NO3 257 | 3.040E-15 258 | # Cl 259 | 1.600E-17 260 | # O 261 | 1.300E-16 262 | # O(1D) 263 | 1.000E-21 264 | # O3 265 | 5.500E-08 266 | # HO2 267 | 5.460E-12 268 | # NO2 269 | 5.880E-11 270 | # OH 271 | 2.000E-13 272 | # HBr 273 | 3.700E-14 274 | # HCl 275 | 3.160E-12 276 | # CO 277 | 4.260E-08 278 | # MO2 279 | 5.400E-12 280 | # ACTA 281 | 2.490E-11 282 | # EOH 283 | 1.230E-21 284 | # H2 285 | 2.700E-07 286 | # HCOOH 287 | 3.710E-11 288 | # MOH 289 | 3.860E-10 290 | # N2 291 | 7.808E-01 292 | # O2 293 | 2.095E-01 294 | # RCOOH 295 | 1.230E-21 296 | 297 | 298 | # Aerosols: 299 | # Soot 300 | 0.05 301 | 2.00E-08 302 | # Ice 303 | 0.00 304 | 1.00E-06 305 | # Sulfates 306 | 0.00 307 | 1.00E-07 308 | 309 | # EOF 310 | -------------------------------------------------------------------------------- /Code.v05-00/src/EPM/EPM.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "Core/Input_Mod.hpp" 5 | #include "EPM/EPM.hpp" 6 | 7 | #include "EPM/Models/Original.hpp" 8 | #include "EPM/Models/External.hpp" 9 | #include "EPM/Models/NewPhysics.hpp" 10 | 11 | namespace EPM { 12 | 13 | struct { 14 | std::string name; 15 | std::string units; 16 | double Output::*value; 17 | } scalar_vars[] = {{"finalTemp", "K", &Output::finalTemp}, 18 | {"iceRadius", "m", &Output::iceRadius}, 19 | {"iceDensity", "kg/m^3", &Output::iceDensity}, 20 | {"sootDensity", "kg/m^3", &Output::sootDensity}, 21 | {"H2O_mol", "molec/cm^3", &Output::H2O_mol}, 22 | {"SO4g_mol", "molec/cm^3", &Output::SO4g_mol}, 23 | {"SO4l_mol", "molec/cm^3", &Output::SO4l_mol}, 24 | {"area", "m^2", &Output::area}, 25 | {"bypassArea", "m^2", &Output::bypassArea}, 26 | {"coreExitTemp", "K", &Output::coreExitTemp}}; 27 | 28 | struct { 29 | std::string name; 30 | AIM::Aerosol Output::*value; 31 | } pdf_vars[] = { 32 | {"so4", &Output::SO4Aer}, 33 | {"ice", &Output::IceAer}}; 34 | 35 | void Output::write(std::string filename) const { 36 | NcFile nc(filename, NcFile::replace); 37 | 38 | // Scalar variables. 39 | 40 | for (auto &var : scalar_vars) { 41 | NcVar nc_var = nc.addVar(var.name, ncDouble); 42 | nc_var.putAtt("units", var.units); 43 | nc_var.putVar(&(this->*var.value)); 44 | } 45 | 46 | // PDF variables: keep the SO4 and ice bin dimensions separate for 47 | // generality. 48 | 49 | for (auto &var : pdf_vars) { 50 | const AIM::Aerosol &aerosol = this->*var.value; 51 | 52 | const NcDim r_dim = nc.addDim(var.name + "_r", aerosol.getBinCenters().size()); 53 | NcVar r_var = nc.addVar(var.name + "_r", ncDouble, r_dim); 54 | r_var.putAtt("units", "m"); 55 | r_var.putAtt("long_name", var.name + " aerosol bin center radius"); 56 | r_var.putVar(aerosol.getBinCenters().data()); 57 | 58 | const NcDim r_e_dim = nc.addDim(var.name + "_r_e", aerosol.getBinEdges().size()); 59 | NcVar r_e_var = nc.addVar(var.name + "_r_e", ncDouble, r_e_dim); 60 | r_e_var.putAtt("units", "m"); 61 | r_e_var.putAtt("long_name", var.name + " aerosol bin edge radius"); 62 | r_e_var.putVar(aerosol.getBinEdges().data()); 63 | 64 | NcVar pdf_var = nc.addVar(var.name + "_pdf", ncDouble, r_dim); 65 | pdf_var.putAtt("long_name", var.name + " aerosol particle size distribution"); 66 | pdf_var.putVar(aerosol.getPDF().data()); 67 | } 68 | } 69 | 70 | void Output::read(std::string filename) { 71 | NcFile nc(filename, NcFile::read); 72 | 73 | // Scalar variables. 74 | 75 | for (auto &var : scalar_vars) { 76 | const NcVar nc_var = nc.getVar(var.name); 77 | nc_var.getVar(&(this->*var.value)); 78 | } 79 | 80 | // PDF variables: keep the SO4 and ice bin dimensions separate for 81 | // generality. 82 | 83 | for (auto &var : pdf_vars) { 84 | const NcDim r_dim = nc.getDim(var.name + "_r"); 85 | const NcDim r_e_dim = nc.getDim(var.name + "_r_e"); 86 | 87 | Vector_1D binCenters(r_dim.getSize()); 88 | Vector_1D binEdges(r_e_dim.getSize()); 89 | Vector_1D pdf(r_dim.getSize()); 90 | 91 | const NcVar r_var = nc.getVar(var.name + "_r"); 92 | r_var.getVar(binCenters.data()); 93 | 94 | const NcVar r_e_var = nc.getVar(var.name + "_r_e"); 95 | r_e_var.getVar(binEdges.data()); 96 | 97 | const NcVar pdf_var = nc.getVar(var.name + "_pdf"); 98 | pdf_var.getVar(pdf.data()); 99 | 100 | AIM::Aerosol aerosol(binCenters, binEdges, pdf); 101 | this->*var.value = aerosol; 102 | } 103 | } 104 | 105 | std::unique_ptr make_epm( 106 | const OptInput &optInput, const Input &input, const Aircraft &aircraft, 107 | const Emission &EI, const Meteorology &met, 108 | const MPMSimVarsWrapper &simVars) { 109 | switch (optInput.SIMULATION_EPM_TYPE) { 110 | case epm_type::EPM_ORIGINAL: 111 | return std::make_unique(optInput, input, aircraft, EI, met, simVars); 112 | case epm_type::EPM_EXTERNAL: 113 | return std::make_unique(optInput, input, aircraft, EI, met, simVars); 114 | case epm_type::EPM_NEW_PHYSICS: 115 | throw std::invalid_argument("NEW PHYSICS EPM NOT YET IMPLEMENTED!"); 116 | // return std::make_unique(optInput, input, aircraft, EI, met, simVars); 117 | default: 118 | throw std::invalid_argument("Unknown EPM type specified in SIMULATION MENU."); 119 | } 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /Code.v05-00/tests/test_LAGRID.cpp: -------------------------------------------------------------------------------- 1 | #include "LAGRID/RemappingFunctions.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | TEST_CASE("FreeCoordBoxGrid and Remapping") { 7 | Vector_1D dy = {1, 2, 3, 4}; 8 | Vector_1D dx = {1, 2, 3, 4}; 9 | Vector_1D x0 = {7.5, 5, 2.5, 0}; 10 | Vector_2D phi = { 11 | {0, 0, 2, 0, 0}, 12 | {0, 1, 2, 1, 0}, 13 | {0, 1, 1, 1, 0}, 14 | {0, 0, 1, 0, 0} 15 | }; 16 | 17 | LAGRID::FreeCoordBoxGrid testgrid(dx, dy, phi, x0, 0, 0.5); 18 | 19 | SECTION("FreeCoordBoxGrid Constructor") { 20 | //basic sanity checks 21 | REQUIRE(testgrid.boxes.size() == 8); 22 | REQUIRE(testgrid.boundaryBoxIndices.size() == 6); 23 | 24 | //boundary node order 25 | REQUIRE(testgrid.boundaryBoxIndices[0] == 0); 26 | REQUIRE(testgrid.boundaryBoxIndices[1] == 1); 27 | REQUIRE(testgrid.boundaryBoxIndices[2] == 3); 28 | REQUIRE(testgrid.boundaryBoxIndices[4] == 6); 29 | 30 | //location and property of boxes 31 | REQUIRE(testgrid.boxes[0].topLeftY == 1); 32 | REQUIRE(testgrid.boxes[0].topLeftX == 9.5); 33 | REQUIRE(testgrid.boxes[0].botRightY == 0); 34 | REQUIRE(testgrid.boxes[0].botRightX == 10.5); 35 | 36 | REQUIRE(testgrid.boxes[3].topLeftY == 3); 37 | REQUIRE(testgrid.boxes[3].topLeftX == 11); 38 | REQUIRE(testgrid.boxes[3].botRightY == 1); 39 | REQUIRE(testgrid.boxes[3].botRightX == 13); 40 | 41 | REQUIRE(testgrid.boxes[4].topLeftY == 6); 42 | REQUIRE(testgrid.boxes[4].topLeftX == 5.5); 43 | REQUIRE(testgrid.boxes[4].botRightY == 3); 44 | REQUIRE(testgrid.boxes[4].botRightX == 8.5); 45 | 46 | //area function and mass 47 | REQUIRE(testgrid.boxes[4].area() == 9); 48 | REQUIRE(testgrid.boxes[4].mass == 9); 49 | } 50 | 51 | LAGRID::Remapping testremap = { -1, -1, 2, 2, 11, 6 }; 52 | SECTION("Diffusion Loss Function") { 53 | REQUIRE(LAGRID::diffusionLossFunctionExact(testgrid, testremap) == 6); 54 | 55 | //TODO: Test after faster algorithm is actually developed or deemed necessary through test runs 56 | //REQUIRE(LAGRID::diffusionLossFunctionBoundaryEstimate(testgrid, testremap) == 6); 57 | } 58 | 59 | auto twoDGrid = LAGRID::mapToStructuredGrid(testgrid, testremap); 60 | twoDGrid = LAGRID::mapToStructuredGrid(testgrid, testremap); 61 | double mass_before = std::accumulate(testgrid.boxes.begin(), testgrid.boxes.end(), 0.0, 62 | [](double sum, auto& b) -> double { 63 | return sum + b.mass; 64 | }); 65 | SECTION("Remapping") { 66 | REQUIRE(twoDGrid.yCoords.size() == 6); 67 | REQUIRE(twoDGrid.yCoords[0] == 0); 68 | REQUIRE(twoDGrid.yCoords[3] == 6); 69 | REQUIRE(twoDGrid.yCoords[5] == 10); 70 | REQUIRE(twoDGrid.xCoords.size() == 11); 71 | REQUIRE(twoDGrid.xCoords[0] == 0); 72 | REQUIRE(twoDGrid.xCoords[3] == 6); 73 | REQUIRE(twoDGrid.xCoords[10] == 20); 74 | 75 | double mass_after = 0; 76 | for (std::size_t j = 0; j < twoDGrid.phi.size(); j++){ 77 | for (std::size_t i = 0; i < twoDGrid.phi[0].size(); i++) { 78 | mass_after += twoDGrid.phi[j][i] * twoDGrid.dx * twoDGrid.dy; 79 | } 80 | } 81 | REQUIRE(std::abs(mass_before - mass_after) < 1e-12); 82 | 83 | // Uncomment / play around to verify that SFINAE for twoDGridVariable constructor works, this won't compile. 84 | // auto a = LAGRID::twoDGridVariable(Vector_2D(), 2, Vector_1D()); 85 | } 86 | 87 | SECTION("Adding Buffer") { 88 | twoDGrid.addBuffer(6, 10, 4, 8, 0.0); 89 | REQUIRE(twoDGrid.yCoords.size() == 12); 90 | REQUIRE(twoDGrid.xCoords.size() == 19); 91 | REQUIRE(twoDGrid.xCoords[0] == -6); 92 | REQUIRE(twoDGrid.yCoords[0] == -8); 93 | 94 | REQUIRE(twoDGrid.yCoords[3] == -2); 95 | REQUIRE(twoDGrid.yCoords[4] == 0); 96 | REQUIRE(twoDGrid.yCoords[11] == 14); 97 | 98 | REQUIRE(twoDGrid.xCoords[2] == -2); 99 | REQUIRE(twoDGrid.xCoords[3] == 0); 100 | REQUIRE(twoDGrid.xCoords[18] == 30); 101 | 102 | REQUIRE(twoDGrid.phi.size() == 12); 103 | REQUIRE(twoDGrid.phi[0].size() == 19); 104 | double mass = 0; 105 | for (std::size_t j = 0; j < twoDGrid.phi.size(); j++){ 106 | for (std::size_t i = 0; i < twoDGrid.phi[0].size(); i++) { 107 | mass += twoDGrid.phi[j][i] * twoDGrid.dx * twoDGrid.dy; 108 | } 109 | } 110 | REQUIRE(std::abs(mass_before - mass) < 1e-12); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /Code.v05-00/include/Core/LAGRIDPlumeModel.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LAGRIDPLUMEMODEL_H 2 | #define LAGRIDPLUMEMODEL_H 3 | 4 | #include 5 | #include "AIM/Aerosol.hpp" 6 | #include "LAGRID/RemappingFunctions.hpp" 7 | #include "FVM_ANDS/FVM_Solver.hpp" 8 | #include "EPM/EPM.hpp" 9 | #include "Core/Aircraft.hpp" 10 | #include "Core/Emission.hpp" 11 | #include "Core/Fuel.hpp" 12 | #include "Core/Diag_Mod.hpp" 13 | #include "Core/MPMSimVarsWrapper.hpp" 14 | #include "Core/TimestepVarsWrapper.hpp" 15 | #include "Core/Meteorology.hpp" 16 | #include "Core/Status.hpp" 17 | #include "Util/VectorUtils.hpp" 18 | 19 | class LAGRIDPlumeModel { 20 | public: 21 | static constexpr double NUM_FILTER_RATIO = 1e-5; 22 | static constexpr double TOP_BUFFER_SCALING = 1.5; 23 | static constexpr double BOT_BUFFER_SCALING = 1.1; 24 | static constexpr double LEFT_BUFFER_SCALING = 1.5; 25 | static constexpr double RIGHT_BUFFER_SCALING = 1.5; 26 | 27 | LAGRIDPlumeModel() = delete; 28 | LAGRIDPlumeModel(const OptInput &Input_Opt, Input &input); 29 | SimStatus runFullModel(); 30 | std::variant runEPM(); 31 | struct BufferInfo { 32 | double leftBuffer; 33 | double rightBuffer; 34 | double topBuffer; 35 | double botBuffer; 36 | }; 37 | private: 38 | const OptInput& optInput_; 39 | Input& input_; 40 | int numThreads_; 41 | Aircraft aircraft_; 42 | Fuel jetA_; 43 | Emission EI_; 44 | MPMSimVarsWrapper simVars_; 45 | TimestepVarsWrapper timestepVars_; 46 | AIM::Grid_Aerosol iceAerosol_; 47 | Meteorology met_; 48 | Vector_2D diffCoeffX_; 49 | Vector_2D diffCoeffY_; 50 | double survivalFrac_; 51 | Vector_1D yCoords_; 52 | Vector_1D yEdges_; 53 | Vector_1D xCoords_; 54 | Vector_1D xEdges_; 55 | Vector_2D H2O_; 56 | Vector_2D Contrail_; 57 | Vector_1D vFall_; 58 | double initNumParts_; 59 | double simTime_h_; 60 | double solarTime_h_; 61 | double shear_rep_; 62 | double WV_exhaust_; // Exhaust water vapour 63 | 64 | typedef std::pair>, VectorUtils::MaskInfo> MaskType; 65 | inline MaskType iceNumberMask(double cutoff_ratio = NUM_FILTER_RATIO) { 66 | Vector_2D iceTotalNum = iceAerosol_.TotalNumber(); 67 | double maxNum = VectorUtils::max(iceTotalNum); 68 | auto iceNumMaskFunc = [maxNum,cutoff_ratio](double val) { 69 | return val > maxNum * cutoff_ratio; 70 | }; 71 | return VectorUtils::mask(iceTotalNum, xEdges_, yEdges_, iceNumMaskFunc); 72 | } 73 | 74 | inline MaskType H2OMask() { 75 | Vector_2D metH2O = met_.H2O_field(); 76 | Vector_2D diffH2O = Vector_2D(yCoords_.size(), Vector_1D(xCoords_.size())); 77 | for (std::size_t j = 0; j < yCoords_.size(); j++) { 78 | for (std::size_t i = 0; i < xCoords_.size(); i++) { 79 | diffH2O[j][i] = std::abs(H2O_[j][i] - metH2O[j][i]); 80 | } 81 | } 82 | double maxDiff = 1.0e6; 83 | auto maskFunc = [maxDiff](double val) { 84 | return val > maxDiff; 85 | }; 86 | return VectorUtils::mask(diffH2O, xEdges_, yEdges_, maskFunc); 87 | } 88 | 89 | inline MaskType ContrailMask(double minVal=1.0e-2) { 90 | auto maskFunc = [minVal](double val) { 91 | return val > minVal; 92 | }; 93 | return VectorUtils::mask(Contrail_, xEdges_, yEdges_, maskFunc); 94 | } 95 | 96 | void createOutputDirectories(); 97 | void initializeGrid(const EPM::Output &epmOut); 98 | void saveTSAerosol(); 99 | void initH2O(); 100 | void updateDiffVecs(); 101 | void runTransport(double timestep); 102 | void remapAllVars(double remapTimestep, const std::vector>& mask, const VectorUtils::MaskInfo& maskInfo); 103 | std::pair remapVariable(const VectorUtils::MaskInfo& maskInfo, const BufferInfo& buffers, const Vector_2D& phi, const std::vector>& mask); 104 | double totalAirMass(); 105 | 106 | Eigen::SparseMatrix createRegriddingWeightsSparse(const VectorUtils::MaskInfo& maskInfo, const BufferInfo& buffers, const std::vector>& mask, Vector_1D& xEdgesNew, Vector_1D& yEdgesNew, Vector_1D& xCoordsNew, Vector_1D& yCoordsNew); 107 | Vector_2D applyWeights(const Eigen::SparseMatrix& weights, int nx_old, int ny_old, int nx_new, int ny_new, const Vector_2D& dataIn); 108 | 109 | void printVector2D(const std::string fieldName, const Vector_2D& dataIn); 110 | 111 | }; 112 | 113 | #endif 114 | -------------------------------------------------------------------------------- /Code.v05-00/src/Core/Fuel.cpp: -------------------------------------------------------------------------------- 1 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 2 | /* */ 3 | /* Aircraft Plume Chemistry, Emission and Microphysics Model */ 4 | /* (APCEMM) */ 5 | /* */ 6 | /* Fuel Program File */ 7 | /* */ 8 | /* Author : Thibaud M. Fritz */ 9 | /* Time : 7/26/2018 */ 10 | /* File : Fuel.cpp */ 11 | /* */ 12 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 13 | 14 | #include 15 | #include "Core/Fuel.hpp" 16 | 17 | Fuel::Fuel( ) 18 | { 19 | 20 | /* Default Constructor */ 21 | 22 | } /* End of Fuel::Fuel */ 23 | 24 | Fuel::Fuel( const char *fuelChem ) 25 | { 26 | 27 | /* Constructor */ 28 | getAtoms( fuelChem ); 29 | 30 | FSC = 1600; /* [ppm] */ 31 | 32 | std::string ChemFormula( fuelChem ); 33 | 34 | } /* End of Fuel::Fuel */ 35 | 36 | Fuel::Fuel( const Fuel &f ) 37 | { 38 | 39 | /* Constructor */ 40 | 41 | atomC = f.getAtomC(); 42 | atomH = f.getAtomH(); 43 | atomN = f.getAtomN(); 44 | atomS = f.getAtomS(); 45 | FSC = f.getFSC(); 46 | ChemFormula = f.getChemFormula(); 47 | 48 | } /* End of Fuel::Fuel */ 49 | 50 | Fuel& Fuel::operator=( const Fuel &f ) 51 | { 52 | 53 | if ( &f == this ) 54 | return *this; 55 | 56 | atomC = f.getAtomC(); 57 | atomH = f.getAtomH(); 58 | atomN = f.getAtomN(); 59 | atomS = f.getAtomS(); 60 | FSC = f.getFSC(); 61 | ChemFormula = f.getChemFormula(); 62 | 63 | return *this; 64 | 65 | } /* End of Fuel::operator= */ 66 | 67 | Fuel::~Fuel( ) 68 | { 69 | 70 | /* Destructor */ 71 | 72 | } /* End of Fuel::~Fuel */ 73 | 74 | void Fuel::getAtoms( const char *fuelChem ) 75 | { 76 | atomC = 0; 77 | atomH = 0; 78 | atomN = 0; 79 | atomS = 0; 80 | 81 | std::string fuelChem_low; 82 | 83 | char *temp = strdup(fuelChem); 84 | unsigned char *tptr = (unsigned char *)temp; 85 | while (*tptr) { 86 | if (((*tptr >= 'A') && (*tptr <= 'Z')) || ((*tptr >= 'a') && (*tptr <= 'z')) || ((*tptr >= '0') && (*tptr <= '9')) || (*tptr == '.')) { 87 | *tptr = tolower(*tptr); 88 | fuelChem_low += *tptr; 89 | } 90 | tptr++; 91 | } 92 | 93 | free((char*) temp); temp = NULL; 94 | // free((unsigned char*) tptr); tptr = NULL; 95 | 96 | const char *atoms = {"hcns"}; 97 | std::size_t found, next_found; 98 | 99 | found = fuelChem_low.find_first_of( atoms ); 100 | 101 | std::string substr; 102 | std::string::size_type sz; 103 | while (found != std::string::npos) { 104 | next_found = fuelChem_low.find_first_of( atoms, found+1 ); 105 | substr = fuelChem_low.substr(found+1, next_found-1); 106 | if (fuelChem_low[found] == 'c') { 107 | atomC = std::stod(substr, &sz); 108 | } 109 | if (fuelChem_low[found] == 'h') { 110 | atomH = std::stod(substr, &sz); 111 | } 112 | if (fuelChem_low[found] == 'n') { 113 | atomN = std::stod(substr, &sz); 114 | } 115 | if (fuelChem_low[found] == 's') { 116 | atomS = std::stod(substr, &sz); 117 | } 118 | found = fuelChem_low.find_first_of( atoms, found+1 ); 119 | } 120 | 121 | if ( atomC == 0 ) { 122 | std::cout << "Fuel doesn't contain any carbon: " << fuelChem << std::endl; 123 | return; 124 | } 125 | if ( atomH == 0 ) { 126 | std::cout << "Fuel doesn't contain any hydrogen: " << fuelChem << std::endl; 127 | return; 128 | } 129 | 130 | } /* End of Fuel::getAtoms */ 131 | 132 | double Fuel::getAtomC() const 133 | { 134 | 135 | return atomC; 136 | 137 | } /* End of Fuel::getAtomC */ 138 | 139 | double Fuel::getAtomH() const 140 | { 141 | 142 | return atomH; 143 | 144 | } /* End of Fuel::getAtomH */ 145 | 146 | double Fuel::getAtomN() const 147 | { 148 | 149 | return atomN; 150 | 151 | } /* End of Fuel::getAtomN */ 152 | 153 | double Fuel::getAtomS() const 154 | { 155 | 156 | return atomS; 157 | 158 | } /* End of Fuel::getAtomS */ 159 | 160 | double Fuel::getFSC() const 161 | { 162 | 163 | return FSC; 164 | 165 | } /* End of Fuel::getFSC */ 166 | 167 | void Fuel::setFSC( const double FSC_ ) 168 | { 169 | 170 | if ( FSC_ > 0.0E+00 ) 171 | FSC = FSC_; 172 | 173 | } /* End of Fuel::setFSC */ 174 | 175 | std::string Fuel::getChemFormula() const 176 | { 177 | 178 | return ChemFormula; 179 | 180 | } /* End of Fuel::getChemFormula */ 181 | 182 | 183 | /* End of Fuel.cpp */ 184 | 185 | -------------------------------------------------------------------------------- /Code.v05-00/include/FVM_ANDS/FVM_Solver.hpp: -------------------------------------------------------------------------------- 1 | #include "FVM_ANDS/AdvDiffSystem.hpp" 2 | #include 3 | #include 4 | #ifndef FVM_ANDS_SOLVER_H 5 | #define FVM_ANDS_SOLVER_H 6 | namespace FVM_ANDS{ 7 | class FVM_Solver{ 8 | public: 9 | FVM_Solver(const AdvDiffParams& params, const Vector_1D xCoords, const Vector_1D yCoords, const BoundaryConditions& bc, const Eigen::VectorXd& phi_init, bool useDiagPreCond = false, int maxIters_ = 1000, double convergenceThres_ = 1e-5); 10 | const Eigen::VectorXd& solve(); 11 | const Eigen::VectorXd& solve(const Eigen::VectorXd& source); 12 | const Eigen::VectorXd& explicitSolve(); 13 | const Eigen::VectorXd& explicitSolve(const Eigen::VectorXd& source); 14 | 15 | const Eigen::VectorXd& operatorSplitSolve(bool parallelAdvection = false, double courant_max = 0.5); 16 | void operatorSplitSolve2DVec(Vector_2D& vec, const BoundaryConditions& bc, bool parallelAdvection = false, double courant_max = 0.5); 17 | 18 | void advectionHalfTimestepSolve(Vector_2D& vec, const BoundaryConditions& bc, double courant_max = 0.5); 19 | 20 | void buildCoeffMatrix(bool operatorSplit = false){ 21 | advDiffSys_.buildCoeffMatrix(operatorSplit); 22 | } 23 | inline void updateTimestep(double dt){ 24 | advDiffSys_.updateTimestep(dt); 25 | } 26 | inline void updateDiffusion(double Dh, double Dv){ 27 | advDiffSys_.updateDiffusion(Dh, Dv); 28 | } 29 | inline void updateDiffusion(const Vector_2D& Dh, const Vector_2D& Dv){ 30 | advDiffSys_.updateDiffusion(Dh, Dv); 31 | } 32 | inline void updateAdvection(double u, double v, double shear){ 33 | advDiffSys_.updateAdvection(u, v, shear); 34 | } 35 | inline void setConvergenceThres(double tol){ 36 | convergenceThres_ = tol; 37 | } 38 | inline void setMaxIters(int iters){ 39 | maxIters_ = iters; 40 | } 41 | inline void updateBoundaryCondition(const BoundaryConditions& bc){ 42 | advDiffSys_.updateBoundaryCondition(bc); 43 | } 44 | inline void updatePhi(const Eigen::VectorXd& phi){ 45 | advDiffSys_.updatePhi(phi); 46 | } 47 | inline void updateSpacing(const Vector_1D& yCoords_new, double dx_new, int nx_new) { 48 | advDiffSys_.updateSpacing(yCoords_new, dx_new, nx_new); 49 | } 50 | inline const Eigen::VectorXd& phi(){ 51 | return advDiffSys_.phi(); 52 | } 53 | inline const Eigen::SparseMatrix& coefMatrix(){ 54 | return advDiffSys_.getCoefMatrix(); 55 | } 56 | inline const std::vector>& points(){ 57 | return advDiffSys_.points(); 58 | } 59 | const Eigen::VectorXd& calcRHS(){ 60 | return advDiffSys_.calcRHS(); 61 | } 62 | inline int numIters(){ 63 | return solver_.iterations(); 64 | } 65 | inline double error(){ 66 | return solver_.error(); 67 | } 68 | //For some weird reason, Eigen uses FLOAT accuracy to calcuate norms. 69 | //Therefore with the extremely small numbers we have in some bins at the start, 70 | //squaredNorm() or lpNorm<2>() will return zero. 71 | static double eigenSqVectorNorm_double(const Eigen::VectorXd& vec) { 72 | double sum = 0; 73 | for(int i = 0; i < vec.rows(); i++){ 74 | sum += vec[i] * vec[i]; 75 | } 76 | sum = sqrt(sum); 77 | return sum; 78 | } 79 | static double eigenSqVectorNorm_double(const Vector_2D& vec) { 80 | double sum = 0; 81 | for (std::size_t j = 0; j < vec.size(); j++) { 82 | for (std::size_t i = 0; i < vec[0].size(); i++) { 83 | if(isnan(vec[j][i])){ 84 | //std::cout << j << " " << i << std::endl; 85 | } 86 | sum += vec[j][i] * vec[j][i]; 87 | } 88 | } 89 | sum = sqrt(sum); 90 | return sum; 91 | } 92 | private: 93 | int maxIters_; 94 | double convergenceThres_; 95 | AdvDiffSystem advDiffSys_; 96 | bool useDiagPreCond_; 97 | Eigen::DiagonalMatrix diagPreCond; 98 | Eigen::DiagonalMatrix diagPreCond_inv; 99 | Eigen::BiCGSTAB, Eigen::DiagonalPreconditioner > solver_; 100 | }; 101 | } 102 | #endif --------------------------------------------------------------------------------