Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,31 @@
echo "LD_PRELOAD=$LIB_STDCXX:$LIB_OPENBLAS:$LIB_LAPACK" >> $GITHUB_ENV
- name: Set up MATLAB
uses: matlab-actions/setup-matlab@718d4320188c73c86eb94ce76b553cbf89778487 # v2.5.0
- name: Set MATLAB search paths for tests and build MLTBX toolbox
uses: matlab-actions/run-command@v2

Check failure

Code scanning / zizmor

action is not pinned to a hash (required by blanket policy) Error

action is not pinned to a hash (required by blanket policy)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please address this CI error by using a hash.

Copy link
Member

@ischoegl ischoegl Aug 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be addressed (see comment above).

with:
command: |
toolboxPath = fullfile(getenv('CANTERA_ROOT'));
libPath = fullfile(toolboxPath, 'build', 'lib');
includePath = fullfile(toolboxPath, 'include');
addpath(fullfile(toolboxPath, 'interfaces', 'matlab_experimental', 'Utility'));
ctPaths(libPath, includePath, toolboxPath);
buildToolbox;
- name: Run tests
uses: matlab-actions/run-tests@f9fc3d8ca29fadef6227fa52884b144b9011fa2f # v2.1.1
with:
select-by-folder: /home/runner/work/cantera/cantera/test/matlab_experimental
- name: Upload Toolbox Artifact
uses: actions/upload-artifact@v4
with:
name: Cantera_MATLAB_toolbox
path: interfaces/matlab_experimental/*.mltbx
retention-days: 14
# MLTBX test is disabled until we can download packaged binaries and header files
# - name: Test the MLTBX toolbox
# uses: matlab-actions/run-tests@v2
# with:
# select-by-folder: /home/runner/work/cantera/cantera/test/matlab_experimental

ubuntu-multiple-pythons:
name: ${{ matrix.os }} with Python ${{ matrix.python-version }}, Numpy ${{ matrix.numpy || 'latest' }}, Cython ${{ matrix.cython || 'latest' }}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
419f9e5f-b8d1-4265-b17a-239b6536fdd2
106 changes: 106 additions & 0 deletions interfaces/matlab_experimental/Setup/buildToolbox.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
function buildToolbox(arg)
arguments
arg.version (1,:) char = '0.0.0';
arg.ctRoot (1,:) char = pwd;
end

ver = regexp(arg.version, '^\d+\.\d+\.\d+', 'match', 'once');

fprintf('Building toolbox version: %s\n', ver);

% Read the UUID for the toolbox
uuidFile = fullfile(arg.ctRoot, 'interfaces', 'matlab_experimental', 'Setup', ...
'Cantera_MATLAB_Toolbox.uuid');
if isfile(uuidFile)
guid = strtrim(fileread(uuidFile));
fprintf('The unique identifier for the toolbox is: %s\n', guid);
else
error('A unique identifier for the toolbox does not exist!');
end

% Define output file
outputFile = fullfile(arg.ctRoot, 'interfaces', 'matlab_experimental', ...
['Cantera_MATLAB_Toolbox_', ver, '.mltbx']);

% Create temporary folder for reorganizing and faster execution
tmpDir = fullfile(arg.ctRoot, 'build', 'mltbx');
mkdir(tmpDir);
mapping = {
'interfaces/matlab_experimental', 'toolbox';
'samples/matlab_experimental', 'samples';
'test/matlab_experimental', 'test/matlab_toolbox';
'test/data', 'test/data';
'data', 'data'
};

% Move all files to temporary folder
allFiles = {};
for i = 1:size(mapping, 1)
src = fullfile(arg.ctRoot, mapping{i, 1});
dest = fullfile(tmpDir, mapping{i, 2});
copyfile(src, dest);
files = dir(fullfile(dest, '**', '*'));
files = files(~[files.isdir]);
filesList = fullfile({files.folder}, {files.name})';
allFiles = [allFiles; filesList];
end

% Get relative paths
allPaths = strsplit(genpath(tmpDir), pathsep);
relPaths = cellfun(@(p) erase(p, [arg.ctRoot filesep]), allPaths, 'UniformOutput', false);
relPaths = relPaths(~cellfun(@isempty, relPaths));

% Get path to the icon file
iconFile = fullfile(arg.ctRoot, 'doc', 'sphinx', '_static', 'images', 'cantera-logo.png');

% Set up toolbox options
opts = matlab.addons.toolbox.ToolboxOptions(tmpDir, guid);
opts.ToolboxName = 'Cantera MATLAB Toolbox';
opts.ToolboxVersion = ver;
opts.Summary = 'MATLAB interface for Cantera.';
opts.Description = [
'Cantera is an open-source suite of tools for problems involving', ...
'involving chemical kinetics, thermodynamics, and transport processes.', ...
'This toolbox includes the MATLAB interface for Cantera, example scripts, and data files.'
];
opts.AuthorName = 'Cantera Developers'; % placeholder
opts.AuthorEmail = '[email protected]'; % placeholder
opts.ToolboxFiles = allFiles;
opts.ToolboxMatlabPath = relPaths;
opts.ToolboxImageFile = iconFile;
opts.MinimumMatlabRelease = 'R2014b';
opts.OutputFile = outputFile;
opts.SupportedPlatforms.Win64 = true;
opts.SupportedPlatforms.Glnxa64 = true;
opts.SupportedPlatforms.Maci64 = true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this support Apple Silicon?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MATLAB will run through Rosetta 2 on Apple Silicon for releases after R2020b so even though the option is called Maci64 it should support Apple Silicon.

Earlier releases will only support Mac with Intel processors.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Versions 2023b and up have native support … https://www.mathworks.com/support/requirements/apple-silicon.html

opts.SupportedPlatforms.MatlabOnline = false;
% These options will be enabled when we host Cantera binaries somewhere
% opts.RequiredAdditionalSoftware = [
% struct( ...
% "Name", "CanteraBinaries", ...
% "Platform", "win64", ...
% "DownloadURL", "placeholder for download url", ...
% "LicenseURL", "placeholder for license url"),
% struct( ...
% "Name", "CanteraBinaries", ...
% "Platform", "maci64", ...
% "DownloadURL", "placeholder for download url", ...
% "LicenseURL", "placeholder for license url"),
% struct( ...
% "Name", "CanteraBinaries", ...
% "Platform", "glnxa64", ...
% "DownloadURL", "placeholder for download url", ...
% "LicenseURL", "placeholder for license url"),
% ];

% Package the toolbox
try
matlab.addons.toolbox.packageToolbox(opts);
fprintf('✅ Toolbox built successfully!\n');
catch ME
fprintf('❌ Toolbox build failed: %s\n', ME.message);
end

% Remove the temporary folder
rmdir(tmpDir, 's');
end
36 changes: 36 additions & 0 deletions interfaces/matlab_experimental/Setup/downloadDependencies.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
function downloadDependencies()
% This file may not be necessary once we set up the MLTBX properly

os = lower(computer);
% Get platform-specific binaries
switch os
case {'pcwin64', 'pcwin'}
platform = 'windows';
case {'maci64'}
platform = 'macos';
case {'glnxa64', 'glnx86'}
platform = 'linux';
otherwise
error('Unsupported platform: %s', os);
end

% Placeholder URL for ZIP files containing the binaries and headers
baseUrl = 'https://cantera.com/downloads';
zipName = sprintf('cantera-binaries-%s.zip', platform);
url = fullfile(baseUrl, zipName);

% Set target install folder in user path
installDir = fullfile(userpath, 'Dependencies');
if ~isfolder(installDir)
fprintf('Downloading dependencies for %s...\n', platform);
zipFile = fullfile(tempdir, zipName);
websave(zipFile, url);
unzip(zipFile, installDir);
fprintf('Installed to: %s\n', installDir);
else
fprintf('Dependencies already installed at: %s\n', installDir);
end

% Add to path
addpath(genpath(installDir));
end
41 changes: 24 additions & 17 deletions interfaces/matlab_experimental/Utility/ctLoad.m
Original file line number Diff line number Diff line change
@@ -1,32 +1,39 @@
function ctLoad()
% ctLoad
% Load the Cantera C Library into Memory

paths = ctPaths();

if any(cellfun(@isempty, {paths.libPath, paths.includePath, paths.toolboxPath}))
error('ctLoad:MissingPath', ...
'Library, header, and toolbox paths must be configured with ctPaths(libPath,includePath, toolboxPath).');
end

if ispc
ctName = '/bin/cantera_shared.dll';
libName = 'cantera_shared.dll';
elseif ismac
ctName = '/Lib/libcantera_shared.dylib';
libName = 'libcantera_shared.dylib';
elseif isunix
ctName = '/lib/libcantera_shared.so';
libName = 'libcantera_shared.so';
else
error('Operating System Not Supported!');
return;
error('ctLoad:UnsupportedPlatform', 'Operating system not supported.');
end

root = ctRoot;
if ispc
root = [ctRoot, '/Library'];
end
fullLibPath = fullfile(paths.libPath, libName);
fullHeaderPath = fullfile(paths.includePath, 'cantera', 'clib', 'ctmatlab.h');

if ~libisloaded(ctLib)
[~, warnings] = loadlibrary([root, ctName], ...
[root, '/include/cantera/clib/ctmatlab.h'], ...
'includepath', [root, '/include'], ...
'addheader', 'ct', 'addheader', 'ctfunc', ...
'addheader', 'ctmultiphase', 'addheader', ...
'ctonedim', 'addheader', 'ctreactor', ...
'addheader', 'ctrpath', 'addheader', 'ctsurf');
[~, warnings] = loadlibrary(fullLibPath, fullHeaderPath, ...
'includepath', paths.includePath, ...
'addheader', 'ct', ...
'addheader', 'ctfunc', ...
'addheader', 'ctmultiphase', ...
'addheader', 'ctonedim', ...
'addheader', 'ctreactor', ...
'addheader', 'ctrpath', ...
'addheader', 'ctsurf');
end

disp(sprintf('Cantera %s is ready for use.', ctVersion))
fprintf('Cantera %s is ready for use.\n', ctVersion);

end
73 changes: 73 additions & 0 deletions interfaces/matlab_experimental/Utility/ctPaths.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
function paths = ctPaths(varargin)
% ctPaths ::
% Configure or retrieve the library/header/toolbox paths for Cantera.
% The paths are stored as MATLAB preferences.
%
% >> ctPaths() % Get current config as struct
% >> ctPaths(libPath, includePath) % Set library/header/toolbox paths
% >> ctPaths('clear') % Clear saved paths
%
% :return:
% paths: struct with fields 'libPath', 'includePath', and
% 'toolboxPath'

if nargin == 1 && strcmp(varargin{1}, 'clear')
if ispref('Cantera', 'Paths')
paths = getpref('Cantera', 'Paths');
subDirs = strsplit(genpath(paths.toolboxPath), pathsep);
currentPaths = strsplit(path, pathsep);
subdirsToRemove = intersect(subDirs, currentPaths);
if ~isempty(subdirsToRemove)
rmpath(subdirsToRemove{:});
end
rmpref('Cantera', 'Paths');
end
paths = struct('libPath', '', 'includePath', '', 'toolboxPath', '');
return
elseif nargin == 3 && all(cellfun(@ischar, varargin))
paths = struct('libPath', varargin{1}, ...
'includePath', varargin{2}, ...
'toolboxPath', varargin{3});
setpref('Cantera', 'Paths', paths);
else
% Load from saved preferences if available
if ispref('Cantera', 'Paths')
paths = getpref('Cantera', 'Paths');
return
else
paths = struct('libPath', '', 'includePath', '', 'toolboxPath', '');
end
end

if any(cellfun(@isempty, {paths.libPath, paths.includePath, paths.toolboxPath}))
error('ctPaths:MissingPath', ...
'Library, header, and toolbox paths must be configured with ctPaths(libPath,includePath, toolboxPath).');
end

mapping = {
'interfaces/matlab_experimental', 'toolbox';
'samples/matlab_experimental', 'samples';
'test/matlab_experimental', 'test/matlab_toolbox';
'test/data', 'test/data';
'data', 'data'
};

% Check whether user is using Cantera source code or MLTBX based on folder structure
if isfolder(fullfile(paths.toolboxPath, 'interfaces'))
col = 1;
else
col = 2;
end

for i = 1:size(mapping, 1)
subdir = fullfile(paths.toolboxPath, mapping{i, col});
if isfolder(subdir)
addpath(genpath(subdir));
else
warning('ctPaths:MissingDirectory', ...
'Directory not found: %s', subdir);
end
end

savepath();
end
23 changes: 0 additions & 23 deletions test/matlab_experimental/ctTestPath.m

This file was deleted.

25 changes: 2 additions & 23 deletions test/matlab_experimental/ctTestSetUp.m
Original file line number Diff line number Diff line change
@@ -1,24 +1,3 @@
clear all

% Copy library to test folder
ctTestPath;

if ispc
ctName = '/build/lib/cantera_shared.dll';
elseif ismac
ctName = '/build/lib/libcantera_shared.dylib';
elseif isunix
ctName = '/build/lib/libcantera_shared.so';
function ctTestSetUp()
ctLoad();
end
% Load Cantera
if ~libisloaded('libcantera_shared')
[~, warnings] = loadlibrary([cantera_root, ctName], ...
[cantera_root, '/include/cantera/clib/ctmatlab.h'], ...
'includepath', [cantera_root, '/include'], ...
'addheader', 'ct', 'addheader', 'ctfunc', ...
'addheader', 'ctmultiphase', 'addheader', ...
'ctonedim', 'addheader', 'ctreactor', ...
'addheader', 'ctrpath', 'addheader', 'ctsurf');
end

disp('Cantera is loaded for test');
11 changes: 2 additions & 9 deletions test/matlab_experimental/ctTestTearDown.m
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
clear all
% Unload Cantera
if ispc
lib = 'cantera_shared';
else
lib = 'libcantera_shared';
function ctTestTearDown()
ctUnload();
end

unloadlibrary(lib);
disp('Cantera has been unloaded');
Loading