# Module to call matlab gsw functions from python..
# The function generic_gsw_caller can handle calling any single variable output
# gsw functions.
# The _call_... python functions have been replaced by generic_gsw_caller()
import logging
import os
import shlex
import subprocess as sp
import numpy as np
logger = logging.getLogger(__name__)
logger.addHandler(logging.NullHandler())
[docs]
def generic_gsw_caller(
gsw_function_name,
input_vars,
matlab_gsw_dir="/ocean/rich/home/matlab/gsw3",
):
"""A generic function for calling matlab gsw functions. Only works with
gsw functions that have a single variable as output.
:arg str gsw_function_name: The name of the matlab gsw function.
e.g. gsw_p_from_z.m
:arg input_vars: A list of the input variables in the same order as
expected from the gsw matlab function.
:type input_vars: list of numpy arrays
:arg str matlab_gsw_dir: The directory where the matlab gsw scripts are
stored.
:returns: A numpy array containing the output from call to gsw function.
"""
# save inputs to a file for reading into matlab
tmp_files = []
for count, var_data in enumerate(input_vars):
tmp_fname = "input{}".format(count)
tmp_files.append(tmp_fname)
np.savetxt(tmp_fname, var_data.flatten(), delimiter=",")
shape = input_vars[0].shape
# create matlab wrapper
gsw_function_name = (
gsw_function_name
if gsw_function_name.endswith(".m")
else "{}.m".format(gsw_function_name)
)
output = "output_file"
matlab_wrapper_name = _create_matlab_wrapper(
gsw_function_name, output, tmp_files, matlab_gsw_dir
)
# create string of input arguments
arg_strings = "('{}'".format(output)
for tmp_fname in tmp_files:
arg_strings += ",'{}'".format(tmp_fname)
arg_strings += ");exit"
# create string for calling matlab
functioncall = "{}{}".format(matlab_wrapper_name[:-2], arg_strings)
_run_matlab(functioncall)
# load output from matlab
output_data = np.loadtxt(output, delimiter=",")
# remove tmp files
for f in tmp_files:
os.remove(f)
os.remove(output)
os.remove(matlab_wrapper_name)
return output_data.reshape(shape)
def _create_matlab_wrapper(
gsw_function_name,
outfile,
input_files,
matlab_gsw_dir,
):
# Create a matlab wrapper file
wrapper_file_name = "mw_{}".format(gsw_function_name)
f = open(wrapper_file_name, "w")
header = "function [] = {}({},".format(wrapper_file_name[:-2], outfile)
for input_file in input_files:
header += "{},".format(input_file)
header = header[:-1] + ")\n"
f.write(header)
# Add directories to matlab path
f.write("addpath {}\n".format(matlab_gsw_dir))
for subdir in ["html", "library", "thermodynamics_from_t", "pdf"]:
f.write("addpath {}\n".format(os.path.join(matlab_gsw_dir, subdir)))
# reading input files
input_args = ""
for count, input_file in enumerate(input_files):
f.write("in{} = dlmread({},',');\n".format(count, input_file))
input_args += "in{},".format(count)
# call matlab gsw function
f.write("y = {}({});\n".format(gsw_function_name[:-2], input_args[:-1]))
f.write("dlmwrite({},y,',');\n".format(outfile))
return wrapper_file_name
def _run_matlab(functioncall):
cmd = shlex.split("matlab -nosplash -nodesktop -nodisplay -nojvm -r")
cmd.append(functioncall)
logger.debug("executing {}".format(cmd))
try:
cmd_output = sp.check_output(cmd, stderr=sp.STDOUT, universal_newlines=True)
except sp.CalledProcessError as e:
logger.error("matlab command failed with return code {.returncode}".format(e))
cmd_output = e.output
finally:
for line in cmd_output.splitlines():
line = line.strip()
if line:
logger.debug(line)
def _call_p_from_z(z, lat):
fname = "'pout'"
zfile = "'zfile'"
latfile = "'latfile'"
for f, var in zip([zfile, latfile], [z, lat]):
np.savetxt(f[1:-1], var.flatten(), delimiter=",")
shape = z.shape
functioncall = "mw_gsw_p_from_z({},{},{});exit".format(fname, zfile, latfile)
_run_matlab(functioncall)
pressure = np.loadtxt(fname[1:-1], delimiter=",")
for f in [fname, zfile, latfile]:
os.remove(f[1:-1])
return pressure.reshape(shape)
def _call_SR_from_SP(SP):
fname = "'SRout'"
SPfile = "'SPfile'"
for f, var in zip(
[
SPfile,
],
[
SP,
],
):
np.savetxt(f[1:-1], var.flatten(), delimiter=",")
shape = SP.shape
functioncall = "mw_gsw_SR_from_SP({},{});exit".format(
fname,
SPfile,
)
_run_matlab(functioncall)
sal_ref = np.loadtxt(fname[1:-1], delimiter=",")
for f in [
fname,
SPfile,
]:
os.remove(f[1:-1])
return sal_ref.reshape(shape)
def _call_SA_from_SP(SP, p, long, lat):
fname = "'SAout'"
SPfile = "'SPfile'"
pfile = "'pfile'"
longfile = "'longfile'"
latfile = "'latfile'"
for f, var in zip([SPfile, pfile, longfile, latfile], [SP, p, long, lat]):
np.savetxt(f[1:-1], var.flatten(), delimiter=",")
shape = SP.shape
functioncall = "mw_gsw_SA_from_SP({},{},{},{},{});exit".format(
fname, SPfile, pfile, longfile, latfile
)
_run_matlab(functioncall)
SA = np.loadtxt(fname[1:-1], delimiter=",")
for f in [fname, SPfile, pfile, longfile, latfile]:
os.remove(f[1:-1])
return SA.reshape(shape)
def _call_CT_from_PT(SA, PT):
fname = "'CTout'"
SAfile = "'SAfile'"
PTfile = "'PTfile'"
for f, var in zip([SAfile, PTfile], [SA, PT]):
np.savetxt(f[1:-1], var.flatten(), delimiter=",")
shape = PT.shape
functioncall = "mw_gsw_CT_from_pt({},{},{});exit".format(fname, SAfile, PTfile)
_run_matlab(functioncall)
CT = np.loadtxt(fname[1:-1], delimiter=",")
for f in [fname, SAfile, PTfile]:
os.remove(f[1:-1])
return CT.reshape(shape)