Skip to content

Commit

Permalink
Merge pull request #19 from GMLC-TDC/feature/octaveBindings
Browse files Browse the repository at this point in the history
Feature/octave bindings
  • Loading branch information
phlptp authored May 6, 2024
2 parents f3bc6d6 + 5091afa commit 0cf3ec2
Show file tree
Hide file tree
Showing 15 changed files with 1,207 additions and 136 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [3.5.2][] ~ 2023-05-09

- update to HELICS [3.5.2](https://github.com/GMLC-TDC/HELICS/releases/tag/v3.5.2) release
- add some code for Octave support

## [3.4.0][] ~ 2023-01-24

- update to HELICS [3.4.0](https://github.com/GMLC-TDC/HELICS/releases/tag/v3.4.0) release
Expand Down
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,13 @@ The `buildHelicsInterface` function also has an option to generate the package f

This is a new process for building a Matlab interface, it is tested but not extensively and not on a large variety of platforms if you run into issues please let us know.

#### Building with Octave

The instructions for building with newer octave are identical. This will work for octave 8.4 or newer. Octave 9.1 on Windows does not work directly due to a bug with mingw 13.2 on windows. This is not an issue with Octave, so if a helics version was build with mingw it could be made to work, but the scripts use the visual studio version, which works fine with older versions of the library and likely subsequent ones as well as the bug is reportedly fixed. But this will likely require a new version of octave with a newer mingw release.

### Requirements

Matlab 2018a or greater.
Matlab 2018a or greater. Octave 8.4 or greater.
intalled compatible compiler to build the mex file

### building with custom HELICS version
Expand All @@ -65,6 +69,10 @@ If it is necessary to run on an older version of Matlab prior to 2018a, some min

Versions prior to Matlab 2015 will require more extensive modifications. And may be better served by using the Swig based matlab build from Helics version 3.2 which should be compatible with other HELICS versions in the 3.X series.

### Older versions of octave

Older versions of octave can use the SWIG generate interface. This version will be deprecated as of HELICS 3.6, but HELICS is generally backwards compatible for federates, that don't use the latest features.

## Source Repo

The matHelics source code is hosted on GitHub: [https://github.com/GMLC-TDC/matHelics](https://github.com/GMLC-TDC/matHELICS)
Expand Down
235 changes: 134 additions & 101 deletions buildHelicsInterface.m
Original file line number Diff line number Diff line change
@@ -1,146 +1,179 @@
function buildHelicsInterface(targetPath,makePackage)
% buildHelicsInterface(targetPath,makePackage) will generate the files
% necessary for the Matlab HELICS interface. It will download additional
% files from github if needed.
% buildHelicsInterface() will generate the package files in the current
% directory
% buildHelicsInterface(targetPath) will create the package files in the
% specified targetPath directory
% buildHelicsInterface('') is equivalent to buildHelicsInterface()
% buildHelicsInterface(targetPath,makePackage) will if makePackage is set
% to true generate a zip/tar.gz file with all the files that can be copied
% and extracted on a similar system.
%
% To make the helics library accessible anywhere on the matlab path the
% targetPath folder should be added to the matlab path. (NOTE: it should
% not be added with subfolders as all required matlab code is in the main
% folder or in the +helics folder which matlab will recognize as a
% package).
%
% this file requires matlab 2018a or higher.
if (nargin==0)
% buildHelicsInterface(targetPath,makePackage) will generate the files
% necessary for the Matlab HELICS interface. It will download additional
% files from github if needed.
% buildHelicsInterface() will generate the package files in the current
% directory
% buildHelicsInterface(targetPath) will create the package files in the
% specified targetPath directory
% buildHelicsInterface('') is equivalent to buildHelicsInterface()
% buildHelicsInterface(targetPath,makePackage) will if makePackage is set
% to true generate a zip/tar.gz file with all the files that can be copied
% and extracted on a similar system.
%
% To make the helics library accessible anywhere on the matlab path the
% targetPath folder should be added to the matlab path. (NOTE: it should
% not be added with subfolders as all required matlab code is in the main
% folder or in the +helics folder which matlab will recognize as a
% package).
%
% this file requires matlab 2018a or higher.
if (nargin==0)
targetPath=fileparts(mfilename('fullpath'));
end
if (nargin<2)
end
if (nargin<2)
makePackage=false;
end
if (isempty(targetPath))
end
if (isempty(targetPath))
targetPath=fileparts(mfilename('fullpath'));
end
if (~exist(targetPath,'dir'))
end
if (~exist(targetPath,'dir'))
mkdir(targetPath);
end
if (makePackage)
end
if (makePackage)
if (isequal(targetPath,fileparts(mfilename('fullpath'))))
warning('cannot makePackage if target location is the same as the file origin');
makePackage=false;
warning('cannot makePackage if target location is the same as the file origin');
makePackage=false;
end
end
inputPath=fileparts(mfilename('fullpath'));
HelicsVersion='3.5.2';
% set up platform specific names and locations
targetTarFile=fullfile(targetPath,['helicsTar',HelicsVersion,'.tar.gz']);
if ismac
end
inputPath=fileparts(mfilename('fullpath'));
isOctave = (exist('OCTAVE_VERSION', 'builtin') ~= 0);
HelicsVersion='3.5.2';
% set up platform specific names and locations
targetTarFile=fullfile(targetPath,['helicsTar',HelicsVersion,'.tar.gz']);
if ismac
basePath=fullfile(targetPath,['Helics-',HelicsVersion,'-macOS-universal2']);
baseFile=['Helics-shared-',HelicsVersion,'-macOS-universal2.tar.gz'];
targetFile=fullfile(basePath,'lib','libhelics.dylib');
% download the helics library if needed
if (~exist(fullfile(basePath,'include/helics/helics.h'),'file'))
if (~exist(targetTarFile,'file'))
fprintf('downloading helics binary package\n')
websave(targetTarFile,['https://github.com/GMLC-TDC/HELICS/releases/download/v',HelicsVersion,'/',baseFile]);
if (~exist(targetTarFile,'file'))
fprintf('downloading helics binary package\n');
if isOctave
urlwrite(["https://github.com/GMLC-TDC/HELICS/releases/download/v",HelicsVersion,"/",baseFile],targetTarFile);
else
websave(targetTarFile,['https://github.com/GMLC-TDC/HELICS/releases/download/v',HelicsVersion,'/',baseFile]);
end
fprintf('extracting helics binary package\n')
system(['tar xf ',targetTarFile,' -C ',targetPath]);
end
fprintf('extracting helics binary package\n');
system(['tar xf ',targetTarFile,' -C ',targetPath]);
end
%actually build the mex file
fprintf('building helics mex target\n')
mex('-lhelics','-R2018a',['-I',basePath,'/include/'],['-L',basePath,'/lib'],['LDFLAGS=$LDFLAGS -Wl,-rpath,$ORIGIN/lib,-rpath,',basePath,'/lib',',-rpath,',basePath,'/lib64'],fullfile(inputPath,'helicsMex.cpp'),'-outdir',targetPath)
elseif isunix
fprintf('building helics mex target\n');
if isOctave
mex("-lhelics","-DMX_HAS_INTERLEAVED_COMPLEX",["-I",basePath,"/include/"],["-L",basePath,"/lib"],["-Wl,-rpath,$ORIGIN/lib:",basePath,"/lib",":",basePath,"/lib64"],"-o helicsMex.mex",fullfile(inputPath,"helicsMex.cpp"));
else
mex('-lhelics','-R2018a',['-I',basePath,'/include/'],['-L',basePath,'/lib'],['LDFLAGS=$LDFLAGS -Wl,-rpath,$ORIGIN/lib,-rpath,',basePath,'/lib',',-rpath,',basePath,'/lib64'],fullfile(inputPath,'helicsMex.cpp'),'-outdir',targetPath);
end
elseif isunix
basePath=fullfile(targetPath,['Helics-',HelicsVersion,'-Linux-x86_64']);
baseFile=['Helics-shared-',HelicsVersion,'-Linux-x86_64.tar.gz'];
targetFile=fullfile(basePath,'lib64','libhelics.so');
% download the helics library if needed
if (~exist(fullfile(basePath,'include/helics/helics.h'),'file'))
if (~exist(targetTarFile,'file'))
fprintf('downloading helics binary package\n')
websave(targetTarFile,['https://github.com/GMLC-TDC/HELICS/releases/download/v',HelicsVersion,'/',baseFile]);
if (~exist(targetTarFile,'file'))
fprintf('downloading helics binary package\n');
if isOctave
urlwrite(["https://github.com/GMLC-TDC/HELICS/releases/download/v",HelicsVersion,"/",baseFile],targetTarFile);
else
websave(targetTarFile,['https://github.com/GMLC-TDC/HELICS/releases/download/v',HelicsVersion,'/',baseFile]);
end
fprintf('extracting helics binary package\n')
system(['tar xf ',targetTarFile,' -C ',targetPath]);
end
fprintf('extracting helics binary package\n');
system(['tar xf ',targetTarFile,' -C ',targetPath]);
end
%actually build the mex file
fprintf('building helics mex target\n')
mex('-lhelics','-R2018a',['-I',basePath,'/include/'],['-L',basePath,'/lib'],['-L',basePath,'/lib64'],['LDFLAGS=$LDFLAGS -Wl,-rpath,$ORIGIN/lib,-rpath,',basePath,'/lib',',-rpath,',basePath,'/lib64'],fullfile(inputPath,'helicsMex.cpp'),'-outdir',targetPath)
elseif ispc
if isequal(computer,'PCWIN64')
basePath=fullfile(targetPath,['Helics-',HelicsVersion,'-win64']);
baseFile=['Helics-shared-',HelicsVersion,'-win64.tar.gz'];
targetFile='helics.dll';
fprintf('building helics mex target\n');
if isOctave
mex("-lhelics","-DMX_HAS_INTERLEAVED_COMPLEX",["-I",basePath,"/include/"],["-L",basePath,"/lib"],['-L',basePath,'/lib64'],["-Wl,-rpath,$ORIGIN/lib:",basePath,"/lib",":",basePath,"/lib64"],"-o helicsMex.mex",fullfile(inputPath,"helicsMex.cpp"));
else
mex('-lhelics','-R2018a',['-I',basePath,'/include/'],['-L',basePath,'/lib'],['-L',basePath,'/lib64'],['LDFLAGS=$LDFLAGS -Wl,-rpath,$ORIGIN/lib,-rpath,',basePath,'/lib',',-rpath,',basePath,'/lib64'],fullfile(inputPath,'helicsMex.cpp'),'-outdir',targetPath);
end
elseif ispc
if isOctave || isequal(computer,'PCWIN64')
basePath=fullfile(targetPath,['Helics-',HelicsVersion,'-win64']);
baseFile=['Helics-shared-',HelicsVersion,'-win64.tar.gz'];
targetFile='helics.dll';
else
basePath=fullfile(targetPath,['Helics-',HelicsVersion,'-win32']);
baseFile=['Helics-shared-',HelicsVersion,'-win32.tar.gz'];
targetFile='helics.dll';
basePath=fullfile(targetPath,['Helics-',HelicsVersion,'-win32']);
baseFile=['Helics-shared-',HelicsVersion,'-win32.tar.gz'];
targetFile='helics.dll';
end
% download the helics library if needed
if (~exist(fullfile(basePath,'include/helics/helics.h'),'file'))
if (~exist(targetTarFile,'file'))
fprintf('downloading helics binary package\n')
websave(targetTarFile,['https://github.com/GMLC-TDC/HELICS/releases/download/v',HelicsVersion,'/',baseFile]);
if (~exist(targetTarFile,'file'))
fprintf('downloading helics binary package\n');
if isOctave
urlwrite(["https://github.com/GMLC-TDC/HELICS/releases/download/v",HelicsVersion,"/",baseFile],targetTarFile);
else
websave(targetTarFile,['https://github.com/GMLC-TDC/HELICS/releases/download/v',HelicsVersion,'/',baseFile]);
end
fprintf('extracting helics binary package\n')
untar(targetTarFile,targetPath);

end
fprintf('extracting helics binary package\n');
untar(targetTarFile,targetPath);
end
%actually build the mex file
fprintf('building helics mex target\n')
mex('-lhelics','-R2018a',['-I',basePath,'/include/'],['-L',basePath,'/lib'],['-L',basePath,'/bin'],fullfile(inputPath,'helicsMex.cpp'),'-outdir',targetPath)
fprintf('building helics mex target\n');
if isOctave
mex("-lhelics","-DMX_HAS_INTERLEAVED_COMPLEX",["-I",basePath,"/include/"],["-L",basePath,"/lib"],["-Wl,-rpath,$ORIGIN/bin:",basePath,"/lib",":",basePath,"/lib64"],"-o helicsMex.mex",fullfile(inputPath,"helicsMex.cpp"));
else
mex('-lhelics','-R2018a',['-I',basePath,'/include/'],['-L',basePath,'/lib'],['-L',basePath,'/bin'],fullfile(inputPath,'helicsMex.cpp'),'-outdir',targetPath);
end
%copy the needed dll file if on windows
if ispc
if (~exist(fullfile(targetPath,targetFile),'file'))
copyfile(fullfile(basePath,'bin',targetFile),fullfile(targetPath,targetFile));
copyfile(fullfile(basePath,'bin','*.dll'),targetPath);
if (~exist(fullfile(targetPath,targetFile),'file'))
if ~isOctave
copyfile(fullfile(basePath,'bin',targetFile),fullfile(targetPath,targetFile));
copyfile(fullfile(basePath,'bin','*.dll'),targetPath);
else
success1=copyfile(fullfile(basePath,'bin',targetFile),fullfile(targetPath,targetFile));
if (success1)
[success2,msg,id]=copyfile(fullfile(basePath,'bin','*.dll'),targetPath);
if (~success2)
printf('files not copied%s',msg);
end
end

end
end
end
else
else
error('Platform not supported');
end

%% now build the interface directory and copy files
fprintf('copying required files\n')
copyfile(fullfile(inputPath,'matlabBindings','+helics'),fullfile(targetPath,'+helics'));
copyfile(fullfile(inputPath,'extra_m_codes'),fullfile(targetPath,'+helics'));
% copy the include directory with the C headers
if (~exist(fullfile(targetPath,'include'),'dir'))
end
%% now build the interface directory and copy files
fprintf('copying required files\n');
copyfile(fullfile(inputPath,'matlabBindings','+helics'),fullfile(targetPath,'+helics'));
copyfile(fullfile(inputPath,'extra_m_codes/*'),fullfile(targetPath,'+helics'));
% copy the include directory with the C headers
if (~exist(fullfile(targetPath,'include'),'dir'))
mkdir(fullfile(targetPath,'include'));
end
copyfile(fullfile(inputPath,'helics_minimal.h'),fullfile(targetPath,'include','helics_minimal.h'));
if (ismac)
end
copyfile(fullfile(inputPath,'helics_minimal.h'),fullfile(targetPath,'include','helics_minimal.h'));
if (ismac)
[status, result]=system(['cp -R ',fullfile(basePath,'lib'),' ',fullfile(targetPath,'lib')]);
if (status~=0)
disp(result);
disp(result);
end
elseif (isunix)
elseif (isunix)
[status, result]=system(['cp -R ',fullfile(basePath,'lib64'),' ',fullfile(targetPath,'lib')]);
if (status~=0)
disp(result);
if (status~=0)
disp(result);
end
else
else
copyfile(fullfile(basePath,'bin'),fullfile(targetPath,'bin'));
end

%% generate a startup script to load the library

end
%% generate a startup script to load the library
if (isOctave == 0)
fid=fopen(fullfile(targetPath,'helicsStartup.m'),'w');
fprintf(fid,'function helicsStartup(libraryName,headerName)\n');
fprintf(fid,'%% function to load the helics library prior to execution\n');
fprintf(fid,'if (nargin==0)\n');
fprintf(fid,'\tcpath=fileparts(mfilename(''fullpath''));\n');
if (ispc)
fprintf(fid,'\tlibraryName=''%s'';\n',targetFile);
fprintf(fid,'\tlibraryName=''%s'';\n',targetFile);
else
[~,tname,ext]=fileparts(targetFile);
fprintf(fid,'\tlibraryName=fullfile(cpath,''lib'',''%s%s'');\n',tname,ext);
[~,tname,ext]=fileparts(targetFile);
fprintf(fid,'\tlibraryName=fullfile(cpath,''lib'',''%s%s'');\n',tname,ext);
end
fprintf(fid,'end\n\n');
fprintf(fid,'');
Expand All @@ -158,19 +191,19 @@ function buildHelicsInterface(targetPath,makePackage)
fprintf(fid,'\tdisp(''Unable to find library for HELICS'')\n');
fprintf(fid,'end\n');
fclose(fid);

if (makePackage)
fprintf('generating helics matlab binary package file\n')
end
if (makePackage)
fprintf('generating helics matlab binary package file\n');
rmdir(basePath,'s');
delete(targetTarFile);
if ismac || isunix
system(['tar czf matHELICS.tar.gz ',fullfile(targetPath,'*')]);
system(['tar czf matHELICS.tar.gz ',fullfile(targetPath,'*')]);
elseif ispc
zip('matHELICS','*',targetPath);
zip('matHELICS','*',targetPath);
else
warning('unrecognized platform for making package');
warning('unrecognized platform for making package');
end
end
end



24 changes: 17 additions & 7 deletions examples/pireceiver.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,25 @@
% if the condition is true and if so continues. If false, execution stops.

%% Initialize HELICS library in MATLAB
helicsStartup()
%helicsStartup()
%HELICS_PATH = 'C:\Users\mukh915\matHELICS\helics';
HELICS_PATH = '/home/helics-user/Softwares_user/matHELICS/';
addpath(HELICS_PATH)
% Checking if Octave or Matlab
isOctave = exist('OCTAVE_VERSION', 'builtin') ~= 0;
if isOctave
% Using custom Import as the import function is not yet implemented in Octave
addpath(fullfile(HELICS_PATH, '+helics'))
else
import helics.*
end

import helics.*;
%% Configuration
deltat = 0.01; %Base time interval (seconds)
sim_stop_time = 20;

% HELICS options
helics_core_type = 'zmq';
helics_core_type = 'zmq';
fedinitstring = '--federates=1'; % required with current C interface when using separate processes for each federate

%% Provide summary information
Expand All @@ -39,16 +49,16 @@
helics.helicsFederateInfoSetCoreInitString(fedinfo, fedinitstring);


%% Set the message interval (timedelta) for federate.
%% Set the message interval (timedelta) for federate.
% Note:
% HELICS minimum message time interval is 1 ns and by default
% it uses a time delta of 1 second. What is provided to the
% setTimedelta routine is a multiplier for the default timedelta
% setTimedelta routine is a multiplier for the default timedelta
% (default unit = seconds).

% Set one message interval
helicsFederateInfoSetTimeProperty(fedinfo,helics_property_time_delta,deltat);
helicsFederateInfoSetIntegerProperty(fedinfo,helics_property_int_log_level,helics_log_level_warning);
helicsFederateInfoSetTimeProperty(fedinfo, HelicsProperties.HELICS_PROPERTY_TIME_DELTA, deltat);
helicsFederateInfoSetIntegerProperty(fedinfo, HelicsProperties.HELICS_PROPERTY_INT_LOG_LEVEL, HelicsLogLevels.HELICS_LOG_LEVEL_WARNING);



Expand Down
Loading

0 comments on commit 0cf3ec2

Please sign in to comment.