11import re
22from .constants import GAS_CONSTANT , AVOGADRO_CONSTANT
3-
3+ import numpy as np
4+
5+ # The possible units we can convert to and from
6+ # functions that do conversions update this dictionary for their units in
7+ # the appropriate way
8+ unit_conversions = {
9+ 'mol m-3' : 0 ,
10+ 'mol cm-3' : 0 ,
11+ 'molec m-3' : 0 ,
12+ 'molecule m-3' : 0 ,
13+ 'molec cm-3' : 0 ,
14+ 'molecule cm-3' : 0 ,
15+ 'ppth' : 0 ,
16+ 'ppm' : 0 ,
17+ 'ppb' : 0 ,
18+ 'ppt' : 0 ,
19+ 'mol mol-1' : 0
20+ }
421
522def extract_unit (data , key ):
623 """Extract the value and unit from the key in data."""
@@ -87,6 +104,7 @@ def convert_temperature(data, key):
87104def convert_concentration (data , key , temperature , pressure ):
88105 """
89106 Convert the concentration from the input data to moles per cubic meter.
107+ This function assumes you are passing data from a music box configuration.
90108
91109 Args:
92110 data (dict): The input data.
@@ -97,36 +115,112 @@ def convert_concentration(data, key, temperature, pressure):
97115 float: The concentration in moles per cubic meter.
98116 """
99117 concentration_value , unit = extract_unit (data , key )
118+ return convert_to_number_density (concentration_value , unit , temperature , pressure )
119+
120+
121+ def convert_to_number_density (data , input_unit , temperature , pressure ):
122+ """
123+ Convert from some other units to mol m-3
124+
125+ Args:
126+ data (float): The data to convert in the input unit.
127+ input_unit (str): The input units
128+ temperature (float): The temperature in Kelvin.
129+ pressure (float): The pressure in Pascals.
130+ Returns:
131+ float: The data in the output unit.
132+ """
133+
100134 air_density = calculate_air_density (temperature , pressure )
101135
102- unit_conversions = {
136+ conversions = {a : b for a , b in unit_conversions .items ()}
137+ conversions .update ({
103138 'mol m-3' : 1 , # mol m-3 is the base unit
104139 'mol cm-3' : 1e6 , # cm3 m-3
105140 'molec m-3' : 1 / AVOGADRO_CONSTANT , # mol
106141 'molecule m-3' : 1 / AVOGADRO_CONSTANT , # mol
107142 'molec cm-3' : 1e6 / AVOGADRO_CONSTANT , # mol cm3 m-3
108143 'molecule cm-3' : 1e6 / AVOGADRO_CONSTANT , # mol cm3 m-3
109- 'ppth' : 1e-3 * air_density , # moles / m^3
110- 'ppm' : 1e-6 * air_density , # moles / m^3
111- 'ppb' : 1e-9 * air_density , # moles / m^3
112- 'ppt' : 1e-12 * air_density , # moles / m^3
113- 'mol mol-1' : 1 * air_density # moles / m^3
114- }
115-
116- if unit in unit_conversions :
117- return concentration_value * unit_conversions [unit ]
144+ 'ppth' : 1e-3 * air_density , # m3 mol-1
145+ 'ppm' : 1e-6 * air_density , # m3 mol-1
146+ 'ppb' : 1e-9 * air_density , # m3 mol-1
147+ 'ppt' : 1e-12 * air_density , # m3 mol-1
148+ 'mol mol-1' : 1 * air_density # m3 mol-1
149+ })
150+
151+ if input_unit not in conversions :
152+ raise ValueError (f"Unable to convert from { input_unit } to mol m-3" )
153+
154+ conversion_factor = conversions .get (input_unit )
155+
156+ if isinstance (data , np .ndarray ):
157+ return data * conversion_factor
158+ elif isinstance (data , list ):
159+ return [x * conversion_factor for x in data ]
118160 else :
119- raise ValueError (f"Unsupported concentration unit: { unit } " )
161+ return data * conversion_factor
162+
163+
164+ def convert_from_number_density (data , output_unit , temperature , pressure ):
165+ """
166+ Convert from mol m-3 to some other units
167+
168+ Args:
169+ data (float): The data to convert in mol m-3.
170+ output_unit (str): The output units
171+ temperature (float): The temperature in Kelvin.
172+ pressure (float): The pressure in Pascals.
173+ Returns:
174+ float: The data in the output unit.
175+ """
120176
177+ air_density = calculate_air_density (temperature , pressure )
178+
179+ conversions = {a : b for a , b in unit_conversions .items ()}
180+ conversions .update ({
181+ 'mol m-3' : 1 , # mol m-3 is the base unit
182+ 'mol cm-3' : 1e-6 , # m3 cm-3
183+ 'molec m-3' : 1 * AVOGADRO_CONSTANT , # mol-1
184+ 'molecule m-3' : 1 * AVOGADRO_CONSTANT , # mol-1
185+ 'molec cm-3' : 1e-6 * AVOGADRO_CONSTANT , # m3 cm-3 mol-1
186+ 'molecule cm-3' : 1e-6 * AVOGADRO_CONSTANT , # m3 cm-3 mol-1
187+ 'ppth' : 1e3 / air_density , # unitless
188+ 'ppm' : 1e6 / air_density , # unitless
189+ 'ppb' : 1e9 / air_density , # unitless
190+ 'ppt' : 1e12 / air_density , # unitless
191+ 'mol mol-1' : 1 / air_density # unitless
192+ })
193+
194+ if output_unit not in conversions :
195+ raise ValueError (f"Unable to convert from mol m-3 to { output_unit } " )
196+
197+ conversion_factor = conversions .get (output_unit )
198+
199+ if isinstance (data , np .ndarray ):
200+ return data * conversion_factor
201+ elif isinstance (data , list ):
202+ return [x * conversion_factor for x in data ]
203+ else :
204+ return data * conversion_factor
121205
122206def calculate_air_density (temperature , pressure ):
123207 """
124- Calculate the air density in moles/m^3.
208+ Calculate the air density in moles m-3
125209
126210 Args:
127211 temperature (float): The temperature in Kelvin.
128212 pressure (float): The pressure in Pascals.
129213 Returns:
130- float: The air density in moles/m^3.
214+ float: The air density in moles m-3
131215 """
132216 return pressure / (GAS_CONSTANT * temperature )
217+
218+
219+ def get_available_units ():
220+ """
221+ Get the list of available units for conversion.
222+
223+ Returns:
224+ list: The list of available units.
225+ """
226+ return list (unit_conversions .keys ())
0 commit comments