1 /* simulate_radiances.cpp - provides a function taking inactive arguments that returns also Jacobian matrices
2
3 Copyright (C) 2012-2014 The University of Reading
4
5 Copying and distribution of this file, with or without modification,
6 are permitted in any medium without royalty provided the copyright
7 notice and this notice are preserved. This file is offered as-is,
8 without any warranty.
9 */
10
11 #include "adept.h"
12 #include "simulate_radiances.h"
13
14 using adept::aReal;
15 using adept::Real;
16
17 // Simulate a single radiance (W sr-1 m-3) given the wavelength (m),
18 // emissivity profile, surface temperature (K) and temperature profile
19 // (K), where the profile data are located at n points with spacing
20 // 1000 m. This function uses active arguments. It is accessible only
21 // from within this file; the public interface is the
22 // simulate_radiance function.
23 static
24 aReal
simulate_radiance_private(int n,Real wavelength,const Real * emissivity,const aReal & surface_temperature,const aReal * temperature)25 simulate_radiance_private(int n,
26 Real wavelength,
27 const Real* emissivity,
28 const aReal& surface_temperature,
29 const aReal* temperature)
30 {
31 static const Real BOLTZMANN_CONSTANT = 1.380648813e-23;
32 static const Real SPEED_OF_LIGHT = 299792458.0;
33
34 int i;
35 aReal bt = surface_temperature; // Brightness temperature in K
36 // Loop up through the atmosphere working out the contribution from
37 // each layer
38 for (i = 0; i < n; i++) {
39 bt = bt*(1.0-emissivity[i]) + emissivity[i]*temperature[i];
40 }
41 // Convert from brightness temperature to radiance using
42 // Rayleigh-Jeans approximation
43 return 2.0*SPEED_OF_LIGHT*BOLTZMANN_CONSTANT*bt
44 /(wavelength*wavelength*wavelength*wavelength);
45 }
46
47 // Simulate two radiances (W sr-1 m-3) given the surface temperature
48 // (K) and temperature profile (K), where the profile data are located
49 // at n points with spacing 1000 m. This function uses inactive
50 // arguments.
51 void
simulate_radiances(int n,Real surface_temperature,const Real * temperature,Real radiance[2],Real dradiance_dsurface_temperature[2],Real * dradiance_dtemperature)52 simulate_radiances(int n, // Size of temperature array
53 // Input variables:
54 Real surface_temperature,
55 const Real* temperature,
56 // Output variables:
57 Real radiance[2],
58 // Output Jacobians:
59 Real dradiance_dsurface_temperature[2],
60 Real* dradiance_dtemperature)
61 {
62 // First temporarily deactivate any existing Adept stack used by the
63 // calling function
64 adept::Stack* caller_stack = adept::active_stack();
65 if (caller_stack != 0) {
66 caller_stack->deactivate();
67 }
68
69 // Within the scope of these curly brackets, another Adept stack
70 // will be used
71 {
72 // Ficticious oxygen channels around 60 GHz: wavelength in m
73 static const Real wavelength[2] = {0.006, 0.0061};
74 // Mass absorption coefficient of oxygen in m2 kg-1
75 static const Real mass_abs_coefft[2] = {3.0e-5, 3.0e-3};
76 // Layer thickness in m
77 static const Real dz = 1000.0;
78
79 // Density of oxygen in kg m-3
80 std::vector<Real> density_oxygen(n);
81 // Emissivity at a particular microwave wavelength
82 std::vector<Real> emissivity(n);
83
84 // Start a new stack
85 adept::Stack s;
86
87 // Create local active variables: surface temperature, temperature
88 // and radiance
89 aReal st = surface_temperature;
90 std::vector<aReal> t(n);
91 aReal r[2];
92
93 // Initialize the oxygen density and temperature
94 for (int i = 0; i < n; i++) {
95 Real altitude = i*dz;
96 // Oxygen density uses an assumed volume mixing ratio with air
97 // of 21%, molecular mass of 16 (compared to 29 for air), a
98 // surface air density of 1.2 kg m-3 and an atmospheric scale
99 // height of 8000 m
100 density_oxygen[i] = 1.2*0.21*(16.0/29.0)*exp(-altitude/8000.0);
101 t[i] = temperature[i];
102 }
103
104 // Start recording derivative information
105 s.new_recording();
106
107 // Loop through the two channels
108 for (int ichan = 0; ichan < 2; ichan++) {
109 // Compute the emissivity profile
110 for (int i = 0; i < n; i++) {
111 emissivity[i] = 1.0-exp(-density_oxygen[i]*mass_abs_coefft[ichan]*dz);
112 }
113 // Simulate the radiance
114 r[ichan] = simulate_radiance_private(n, wavelength[ichan],
115 &emissivity[0], st, &t[0]);
116 // Copy the aReal variable to the Real variable
117 radiance[ichan] = r[ichan].value();
118 }
119
120 // Declare independent (x) and dependent (y) variables for
121 // Jacobian matrix
122 s.independent(st);
123 s.independent(&t[0], n);
124 s.dependent(r, 2);
125
126 // Compute Jacobian matrix
127 std::vector<Real> jacobian((n+1)*2);
128 s.jacobian(&jacobian[0]);
129
130 // Copy elements of Jacobian matrix into the calling arrays
131 for (int ichan = 0; ichan < 2; ichan++) {
132 dradiance_dsurface_temperature[ichan] = jacobian[ichan];
133 for (int i = 0; i < n; i++) {
134 dradiance_dtemperature[i*2+ichan] = jacobian[2+i*2+ichan];
135 }
136 }
137
138 // At the following curly bracket, the local Adept stack will be
139 // destructed
140 }
141
142 // Reactivate the Adept stack of the calling function
143 if (caller_stack != 0) {
144 caller_stack->activate();
145 }
146 }
147