Skip to content

Commit 67c7f05

Browse files
author
Matt Dawson
committed
Merge branch 'main' into release
2 parents 10734ef + 9a6ce8a commit 67c7f05

File tree

6 files changed

+82
-9
lines changed

6 files changed

+82
-9
lines changed

CITATION.cff

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
cff-version: 1.2.0
22
message: If you use this software, please cite it as below.
33
title: MusicBox
4-
version: v2.5.0
4+
version: v2.5.5
55
authors:
66
- family-names: Dawson
77
given-names: Matthew

pyproject.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ dependencies = [
2626
"colorlog",
2727
"pandas",
2828
"tqdm",
29-
"netcdf4"
29+
"netcdf4",
30+
"matplotlib",
31+
"mplcursors"
3032
]
3133

3234
[project.urls]

src/acom_music_box/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
This package contains modules for handling various aspects of a music box,
55
including species, products, reactants, reactions, and more.
66
"""
7-
__version__ = "2.5.4"
7+
__version__ = "2.5.5"
88

99
from .utils import convert_time, convert_pressure, convert_temperature, convert_concentration
1010
from .model_options import BoxModelOptions

src/acom_music_box/examples/configs/ts1/my_config.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,15 @@
411411
},
412412
"TEPOMUC": {
413413
"initial value [mol m-3]": 1.86716E-11
414+
},
415+
"O2": {
416+
"initial value [mol m-3]": 8.368900382
417+
},
418+
"N2": {
419+
"initial value [mol m-3]": 31.08448713
420+
},
421+
"H2O": {
422+
"initial value [mol m-3]": 1.195557197
414423
}
415424
},
416425
"environmental conditions": {

src/acom_music_box/main.py

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import subprocess
77
import sys
88
import tempfile
9+
import matplotlib.pyplot as plt
10+
import mplcursors
911
from acom_music_box import MusicBox, Examples, __version__
1012

1113

@@ -55,6 +57,13 @@ def parse_arguments():
5557
type=str,
5658
help='Plot a comma-separated list of species if gnuplot is available (e.g., CONC.A,CONC.B).'
5759
)
60+
parser.add_argument(
61+
'--plot-tool',
62+
type=str,
63+
choices=['gnuplot', 'matplotlib'],
64+
default='matplotlib',
65+
help='Choose plotting tool: gnuplot or matplotlib (default: matplotlib).'
66+
)
5867
return parser.parse_args()
5968

6069

@@ -119,6 +128,33 @@ def plot_with_gnuplot(data, species_list):
119128
os.remove(data_file_path)
120129

121130

131+
def plot_with_matplotlib(data, species_list):
132+
# Prepare columns and data for plotting
133+
indexed = data.set_index('time')
134+
135+
fig, ax = plt.subplots()
136+
indexed[species_list].plot(ax=ax)
137+
138+
ax.set(xlabel='Time [s]', ylabel='Concentration [mol m-3]', title='Time vs Species')
139+
140+
ax.spines[:].set_visible(False)
141+
ax.spines['left'].set_visible(True)
142+
ax.spines['bottom'].set_visible(True)
143+
144+
ax.grid(alpha=0.5)
145+
ax.legend()
146+
147+
# Enable interactive data cursors with hover functionality
148+
cursor = mplcursors.cursor(hover=True)
149+
150+
# Customize the annotation format
151+
@cursor.connect("add")
152+
def on_add(sel):
153+
sel.annotation.set_text(f'Time: {sel.target[0]:.2f}\nConcentration: {sel.target[1]:1.2e}')
154+
155+
plt.show()
156+
157+
122158
def main():
123159
start = datetime.datetime.now()
124160

@@ -159,8 +195,10 @@ def main():
159195
print(result.to_csv(index=False))
160196

161197
if plot_species_list:
162-
# Prepare data for plotting
163-
plot_with_gnuplot(result, plot_species_list)
198+
if args.plot_tool == 'gnuplot':
199+
plot_with_gnuplot(result, plot_species_list)
200+
elif args.plot_tool == 'matplotlib':
201+
plot_with_matplotlib(result, plot_species_list)
164202

165203
end = datetime.datetime.now()
166204
logger.info(f"End time: {end}")

src/acom_music_box/tools/waccmToMusicBox.py

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,17 @@ def readWACCM(waccmMusicaDict, latitude, longitude,
220220
return (musicaDict)
221221

222222

223+
# Add molecular Nitrogen, Oxygen, and Argon to dictionary.
224+
# varValues = already read from WACCM, contains (name, concentration, units)
225+
# return varValues with N2, O2, and Ar added
226+
def addStandardGases(varValues):
227+
varValues["N2"] = ("N2", 0.78084, "mol/mol") # standard fraction by volume
228+
varValues["O2"] = ("O2", 0.20946, "mol/mol")
229+
varValues["Ar"] = ("Ar", 0.00934, "mol/mol")
230+
231+
return (varValues)
232+
233+
223234
# set up indexes for the tuple
224235
musicaIndex = 0
225236
valueIndex = 1
@@ -268,7 +279,7 @@ def writeInitCSV(initValues, filename):
268279
else:
269280
fp.write(",")
270281

271-
fp.write(key)
282+
fp.write("{} [{}]".format(key, value[unitIndex]))
272283
fp.write("\n")
273284

274285
# write the variable values
@@ -404,9 +415,19 @@ def main():
404415
if ("longitude" in myArgs):
405416
lon = safeFloat(myArgs.get("longitude"))
406417

418+
# get the requested (diagnostic) output
419+
outputCSV = False
420+
outputJSON = False
421+
if ("output" in myArgs):
422+
# parameter is like: output=CSV,JSON
423+
outputFormats = myArgs.get("output").split(",")
424+
outputFormats = [lowFormat.lower() for lowFormat in outputFormats]
425+
outputCSV = "csv" in outputFormats
426+
outputJSON = "json" in outputFormats
427+
428+
# locate the WACCM output file
407429
when = datetime.datetime.strptime(
408430
f"{dateStr} {timeStr}", "%Y%m%d %H:%M")
409-
410431
waccmFilename = f"f.e22.beta02.FWSD.f09_f09_mg17.cesm2_2_beta02.forecast.001.cam.h3.{when.year:4d}-{when.month:02d}-{when.day:02}-00000.nc"
411432

412433
# read and glean chemical species from WACCM and MUSICA
@@ -425,16 +446,19 @@ def main():
425446
lat, lon, when, waccmDir, waccmFilename)
426447
logger.info(f"Original WACCM varValues = {varValues}")
427448

449+
# add molecular Nitrogen, Oxygen, and Argon
450+
varValues = addStandardGases(varValues)
451+
428452
# Perform any conversions needed, or derive variables.
429453
varValues = convertWaccm(varValues)
430454
logger.info(f"Converted WACCM varValues = {varValues}")
431455

432-
if (False):
456+
if (outputCSV):
433457
# Write CSV file for MusicBox initial conditions.
434458
csvName = os.path.join(musicaDir, "initial_conditions.csv")
435459
writeInitCSV(varValues, csvName)
436460

437-
if (False):
461+
if (outputJSON):
438462
# Write JSON file for MusicBox initial conditions.
439463
jsonName = os.path.join(musicaDir, "initial_config.json")
440464
writeInitJSON(varValues, jsonName)

0 commit comments

Comments
 (0)