Logo: Leibniz Universität Hannover

Matlab

Beschreibung

Matlab ist ein programmierbar interaktives Programmsystem zum numerischen und symbolischen Rechnen mit umfangreiche Visualisierungsmöglichkeiten.  Es ist auch möglich C/C++ - und Fortran-Routinen einzubinden.

Verfügbar auf:

  • RRZN-Clustersystem

Ansprechpartner

  • Dr. Paul Cochrane
  • Dr Andreas Gerdes

Benutzung auf dem RRZN-Clustersystem

Um dieses Paket auf dem RRZN-Clustersystem zu benutzen, muss man das Modul laden.  Dies macht man so: 

module load matlab

Falls Sie die Fehlermeldung "module: command not found" bekommen, müssen Sie dieses Kommando eingeben (im normalen Fall ist das "module" Kommando bereits vorhanden): 

source /usr/share/Modules/init/`basename $SHELL`

Dokumentation und Beispiele

Serielles Matlab-Programm

Folgend ist ein Batchskript um Matlab-Programm (hello.m) auf einem Prozessor laufen zu lassen.  Wichtig in diesem Beispiel ist, dass da man nur einen Prozess angefordert hat (#PBS -l nodes=1:ppn=1) muss die -singleCompThread Option zu Matlab eingeben werden.

#!/bin/bash -login
#PBS -N seriellMatlab
#PBS -M ich@meine.email.adresse
#PBS -j oe
#PBS -l nodes=1:ppn=1
#PBS -l walltime=00:10:00
#PBS -l mem=3600mb
#PBS -q all


# initialise the modules environment
source $MODULESHOME/init/bash


# load the relevant modules
module load matlab

 

# change to work dir:
cd $PBS_O_WORKDIR

# log file name

LOGFILE=$(echo $PBS_JOBID | cut -d"." -f1).log
 

# the program to run
matlab -nodesktop -singleCompThread < hello.m > $LOGFILE 2>&1

Paralleles Matlab-Programm

Um Matlab im parallelen Modus zu benutzen muss man aufpassen, dass die angefordeten Anzahl an Threads (parallele Prozesse) auch an Matlab übergeben wird.  Dies ist besonders wichtig auf einem System wie das RRZN-Clustersystem wo man Rechenknoten mit anderen Nutzern teilt.  Um die Anzahl an Threads übergeben zu können, benutzt man im Batchskript die Zeile

export NUM_THREADS=$(wc -l $PBS_NODEFILE | cut -d" " -f1)

Diese Zeile stelle eine Umgebungsvariable mit dem Namen "NUM_THREADS" ein.  Diesen Wert liest man (von Matlab aus) mit dem folgenden Matlab-Code:

num_threads = str2num(getenv('NUM_THREADS'));

Danach erstellt man die benötigten Anzahl an Threads innerhalb Matlab mit dem Kommando:

matlabpool open num_threads

Am Ende des Matlab-Skriptes muss man folgendes schreiben:

matlabpool close

Hier ist ein Beispiel in dem ein Matlab-Programm vier (4) CPU-Kerne benutzt.  Hier werden vier Threads (auch: parallele Prozesse) gestartet.  Zuerst das Batchskript:
 

#!/bin/bash -login
#PBS -N parallelMatlab
#PBS -M ich@meine.email.adresse
#PBS -m ae
#PBS -j oe
#PBS -l nodes=1:ppn=4
#PBS -l walltime=00:10:00
#PBS -l mem=3600mb
#PBS -q all

# show which computer the job ran on
echo "Job ran on:" $(hostname)

# initialise the modules environment
source $MODULESHOME/init/bash

# load the relevant modules
module load matlab

# change to work dir:
cd $PBS_O_WORKDIR

# work out the number of threads
export NUM_THREADS=$(wc -l $PBS_NODEFILE | cut -d" " -f1)

# log file name
LOGFILE=$(echo $PBS_JOBID | cut -d"." -f1).log

# the program to run
matlab -nodesktop < lin_solve.m > $LOGFILE 2>&1

 Und dann das Matlab-Programm (auch Matlab-Skript benannt) namens "lin_solve.m":

% program: lin_solve.m
clear

%%%% the following three lines should be copied to the beginning
%%%% of your matlab program
% use the number of threads we requested in batch script
num_threads = str2num(getenv('NUM_THREADS'));
matlabpool open num_threads

%%%% now run our actual matlab program %%%%
% set up the matrix to solve
n = 7000;
A = rand(n);
y = rand(n,1);

% solve the matrix
x = A\y;
fprintf('Done!\n')

% close the matlabpool
matlabpool close

 

MATLAB Compiler

Die Anzahl der Rechner, auf denen MATLAB verwendet werden kann, ist auf dem Clustersystem aus Lizenzgründen begrenzt. Diese Restriktion kann man umgehen, indem man das MATLAB-Skript mit dem MATLAB Compiler übersetzt. Danach kann man das Programm ohne Lizenzeinschränkungen auf dem Clustersystem laufen lassen. Man muss auch nicht mehr die matlab-Eigenschaft in der nodes-ppn-Zeile mit angeben.

Hier beschreiben wir die Schritte, die nötig sind, um ein MATLAB-Skript in eine "ausführbare" Datei umzuwandeln (genaugenommen wird der Code auch weiterhin zur Laufzeit interpretiert und zwar vom MATLAB Compiler Runtime, MCR).  Als Beispiel wird das folgende Skript benutzt:

function lin_solve(n)
  fprintf('=============== START =================\n')
  if nargin ~= 1
    n = 10000;
    fprintf('Using default matrix size: n = %d\n', n)
  else
  n = str2num(n); % argument is a string; convert to num
  fprintf('Using the matrix size: n = %d\n', n)
  end
  tic
  % set up the matrix to solve
  A = rand(n);
  y = rand(n,1);
  % solve the matrix
  x = A\y;
  toc
  fprintf('=============== END =================\n')
exit;

Dieses Skript löst ein einfaches lineares Gleichungssystem und hat eine variable Matrixgröße, die man als Eingabewert übergibt.  Dieser Eingabewert verleiht dem Programm Flexibilität, so dass man nicht für jede Matrixgröße neu übersetzen muss.

Man lädt zuerst MATLAB auf einem der Login-Knoten des Clustersystems innerhalb einer grafischen Login-Session:

$ module load matlab

Wir testen jetzt das Programm ganz kurz, um zu sehen, was wir am Ende aus dem erstellten Binary-Programm erwarten, und um sicherzustellen, dass alles funktioniert.  Man ruft Matlab mit der '-r' Option und dem Namen der Funktion auf (das m-Script muss im selben Verzeichnis liegen).  Erstmal ohne zusätzlichen Argument:

$ matlab -nodesktop -nosplash -r "lin_solve"
=============== START =================
Using default matrix size: n = 10000
Elapsed time is 16.330347 seconds.
===============  END =================
$

und einmal mit einem Eingabewert '10':

$ matlab -nodesktop -nosplash -r "lin_solve('10')"
=============== START =================
Using default matrix size: n = 10
Elapsed time is 0.040559 seconds.
===============  END =================
$

Um dieses Skript in ein ohne MATLAB-Lizenz lauffähiges Programm zu verwandeln, muss man nun Matlab im grafischen Modus starten:

$ matlab

Man startet das Deployment Tool mit dem "Start"-Knopf unten links im Matlab Fenster:

Es erscheint ein Fenster, in dem man entweder ein neues Projekt erstellen oder ein bestehendes Projekt bearbeiten kann.  In diesem Beispiel bennenen wir das Projekt lin_solve.prj.  Das Projekt darf nicht im selben Order erstellt werden, in dem das Matlab-Skript bzw. -Programm liegt.  Wenn man das mißachtet, wird eine Java-Fehlermeldung erscheinen, die nur sagt "Unknown error".  Hier erstellen wir das Projekt als "Standalone Application" (was das Programm am Ende sein soll) im HOME-Verzeichnis des Nutzers.

Ein zusätzliches Panel erscheint innerhalb des gesamten Matlab-Fensters für die weitere Bearbeitung der Anwendung.  Hier fügt man die Programmskripte und zusätzliche Funktionen dem Projekt hinzu, die als Teil des fertigen Programmes benötigt sind.

Wir klicken jetzt auf "Add Main File" damit wir das Hauptskript zum Projekt hinzufügen können.  Es wird jetzt durch die Verzeichnisse gestöbert um das entsprechende Skript zu finden.  Man wählt das Skript aus (in diesem Falle lin_solve.m wie unten dargestellt) und klickt anschließend auf "Open".

Die m-Datei wurde jetzt zum Projekt hinzugefügt und wir sehen sie jetzt im "Standalone Application"-Panel.  Falls nötig, kann man jetzt weitere Matlab-Funktionen zum Projekt hinzufügen damit das fertige Programm funktioniert wie gewünscht. 

Wenn man zum "Package"-Tab wechselt, sieht man, was bereits dem Projekt hinzugefügt wurde.  Es gibt eine readme.txt-Datei und ein Shell-Skript, was benutzt wird, um das endgültige Programm laufen zu lassen.  Man sieht hier auch die Möglichkeit das MCR (Matlab Common Runtime) dem Projekt hinzuzufügen.  Dies ist aber nur nötig wenn man das Programm auf einem kompletten anderen Rechner (wo kein Matlab installiert ist) laufen lassen möchte.  Da wir das Programm auf dem Clustersystem laufen lassen wollen und das MCR überall auf dem Clustersystem zur Verfügung steht, brauchen wir dies nicht hinzuzufügen.

Durch ein Bug in der Linux-Version von Matlab ist es nötig, alle verfügbare Lizenzen abzuwählen.  Die benötigten Lizenzen werden beim Bau des Programmes trotzdem korrekt bezogen und benutzt, um das endgültige Binary zu erstellen.  Wenn nicht alle Toolboxen abgewählt sind, bekommt man eine Fehlermeldung, dass die Identification Toolbox nicht zur Verfügung stehe, daher ist dieser Schritt notwendig für die korrekte Erstellung des Standalone-Programms.  Man klickt innerhalb des Matlab-Fensters auf das kleine Zahnradsymbol (oben rechts) und wählt die "Settings" Option aus.

Ein Fenster erscheint mit den Projekteinstellungen:

Man klickt nun auf "Clear All" und letzendlich auf "Close".

Jetzt kann man das Programm bauen.  Innerhalb des "Standalone Application" Fensters klickt man auf das "Build"-Symbol (drittes Symbol von rechts, oben rechts im Fenster).

Und das Projekt wird gebaut.  Am Ende sollte ein ähnliches Fenster wie unten erscheinen.

Jetzt kann das fertig gestellte Programm ausgeführt werden.  Man wechselt in das Verzeichnis wo das Projekt am Anfang angelegt wurde (in diesem Falle das HOME-Verzeichnis des Nutzers).

$ cd $HOME

Hier befindet sich sowohl eine Datei namens lin_solve.prj als auch ein Verzeichnis namens lin_solve.  Man wechselt in das distrib/ Unterverzeichnis des lin_solve Ordners und ruft ls (Verzeichnisauflistung) auf um die Dateien im Verzeichnis zu sehen.

$ cd lin_solve/distrib
$ ls
lin_solve  readme.txt  run_lin_solve.sh

Es gibt eine ausführbare Datei namens lin_solve, ein Skript namens run_lin_solve.sh (damit man lin_solve laufen lassen kann) und eine readme.txt Datei mit Informationen, wie man das Programm aufruft.

Die readme.txt verrät, dass man run_lin_solve.sh aufruft mit dem Pfad zum Hauptverzeichnis der zentral installierten Matlab-Version, die benutzt wurde, um das Projekt zu bauen (hier Matlab 2012a), bzw. (auf Rechner ohne installiertes MATLAB) zum Pfad, wo das MCR liegt, in unserem Fall also so:

./run_lin_solve.sh /sw/aws/numerics/matlab/MATLAB_R2012a <optional_argument>

Wenn man das Programm ohne optionales Argument laufen lässt, bekommt man ungefähr diese Ausgabe:

$ ./run_lin_solve.sh /sw/aws/numerics/matlab/MATLAB_R2012a

------------------------------------------
Setting up environment variables
---
LD_LIBRARY_PATH is .:/sw/aws/numerics/matlab/MATLAB_R2012a/runtime/glnxa64:/sw/aws/numerics/matlab/MATLAB_R2012a/bin/glnxa64:/sw/aws/numerics/matlab/MATLAB_R2012a/sys/os/glnxa64:/sw/aws/numerics/matlab/MATLAB_R2012a/sys/java/jre/glnxa64/jre/lib/amd64/native_threads:/sw/aws/numerics/matlab/MATLAB_R2012a/sys/java/jre/glnxa64/jre/lib/amd64/server:/sw/aws/numerics/matlab/MATLAB_R2012a/sys/java/jre/glnxa64/jre/lib/amd64/client:/sw/aws/numerics/matlab/MATLAB_R2012a/sys/java/jre/glnxa64/jre/lib/amd64
=============== START =================
Using default matrix size: n = 10000
Elapsed time is 11.889702 seconds.
===============  END  =================

Und wenn man ein Argument (z.B. den Wert '10') übergibt, bekommt man folgende Ausgabe:

$ ./run_lin_solve.sh /sw/aws/numerics/matlab/MATLAB_R2012a 10

------------------------------------------
Setting up environment variables
---
LD_LIBRARY_PATH is .:/sw/aws/numerics/matlab/MATLAB_R2012a/runtime/glnxa64:/sw/aws/numerics/matlab/MATLAB_R2012a/bin/glnxa64:/sw/aws/numerics/matlab/MATLAB_R2012a/sys/os/glnxa64:/sw/aws/numerics/matlab/MATLAB_R2012a/sys/java/jre/glnxa64/jre/lib/amd64/native_threads:/sw/aws/numerics/matlab/MATLAB_R2012a/sys/java/jre/glnxa64/jre/lib/amd64/server:/sw/aws/numerics/matlab/MATLAB_R2012a/sys/java/jre/glnxa64/jre/lib/amd64/client:/sw/aws/numerics/matlab/MATLAB_R2012a/sys/java/jre/glnxa64/jre/lib/amd64
=============== START =================
Using the matrix size: n = 100
Elapsed time is 0.757293 seconds.
===============  END  =================

Der Vergleich mit oben zeigt, dass das Programm funktioniert!

Jetzt erstellen wir ein Batchskript, mit dem man das Programm benutzen kann:


#!/bin/bash -login
#PBS -N lin_solve
#PBS -M ich@meine.mail.adresse.de
#PBS -m ae
#PBS -j oe
#PBS -l nodes=1:ppn=1
#PBS -l walltime=00:10:00
#PBS -l mem=10gb

# show which computer the job ran on
echo "Job ran on:" $(hostname)

# change to work dir:
cd $PBS_O_WORKDIR

# log file name
LOGFILE=$(echo $PBS_JOBID | cut -d"." -f1).log

# Set up MCR cache directory locally so that program starts faster
export MCR_CACHE_ROOT=/tmp/mcr_cache_$PBS_JOBID
mkdir -p $MCR_CACHE_ROOT

# the program to run, without arguments
$HOME/lin_solve/src/run_lin_solve.sh /sw/aws/numerics/matlab/MATLAB_R2012a &> $LOGFILE

# ... and with arguments
$HOME/lin_solve/src/run_lin_solve.sh /sw/aws/numerics/matlab/MATLAB_R2012a 10 &> $LOGFILE



#Remove temporary MCR cache directory
/bin/rm -rf $MCR_CACHE_ROOT

Man kann jetzt dieses Batchskript als lin_solve.qsub speichern und mit

$ qsub lin_solve.qsub

in die Queue abstellen.  Das war's!

Textausgabe vom Matlab-Skript

Es gibt zwei Methoden um Textausgabe von einem Matlab-Skript zu erzeugen und zu bekommen.  Entweder speichert man die Ausgabe von Matlab in einem Logfile direkt im Batchskript, oder man schickt eine Mail direkt an sich vom Matlab-Skript aus.  Hier werden beide Möglichkeiten beschrieben.

Ausgabe vom Matlab als Logfile

In den Beispiel-Batchskripten oben wurde den direkten Weg Ausgabe von Matlab zu bekommen dokumentiert.  Dies ist auch der empfohlene Weg solche Information zu bekommen.  Wie in den Beispielen oben ist es hilfreich, aber nicht unbedingt nötig, einen Logdateinamen automatisch von der Job-ID zu erzeugen.  Dieser Automatismus hilft um zu vermeiden, dass die Logdateien von vorherigen oder gleichzeitiglaufenden Batchjobs nicht überschrieben werden.

Man erzeugt im Batchskript eine Umgebungsvariable von der einzigartigen Job-ID:

LOGFILE=$(echo $PBS_JOBID | cut -d"." -f1).log

Dann, nach dem Aufruf zu Matlab, leitet man beide die Standard- und Fehlerausgaben von der Konsole in die Logdatei weiter:

matlab -nodesktop < matlab_script.m > $LOGFILE 2>&1

Während der Job läuft, kann man die Ausgabe überpüfen in dem man die Logdatei in einem Editor oder mittels des "more" Kommandos darstellt.

Ausgabe als Mail von Matlab

Man kann sich eine Mail mit beliebigem Text zuschicken lassen und sich somit über den Stand der aktuellen Rechnung informieren lassen. Das funktioniert im Matlab-Skript folgendermaßen:


 setpref('Internet','SMTP_Server','smtpserver.rrzn.uni-hannover.de');
 setpref('Internet','E_mail','absender@email.adresse');
 message = 'irgend-ein-String';
 sendmail('ich@meine.email.adresse','Meine Info',message);


"Meine Info" ist dabei der Betreff der Nachricht und "ich@meine.email.adresse" der Empfänger.

Vielen Dank an Herrn Lutz vom Institut für Baumechanik und Numerische Mechanik für diese Dokumentation.

Speicherung Datenmengen über 2GB

Beim Verwenden des Matlab Kommandos 'save()' zum Abspeichern der Werte von Variablen wird normalerweise ein Format verwendet, das nur Variablen mit der Größe bis zu 2GB verarbeiten kann. Wenn man versucht größere Dateien zu speichern, bekommt man eine Fehlermeldung ähnlich wie folgende:

Warning: Variable 'xxxxxx' cannot be saved to a MAT-file whose version is
older than 7.3. To save this variable, use the -v7.3 switch. Skipping...

Um größere Datenmengen zu erlauben, und den obengenannten Fehler zu beheben, muss vom per default eingestellten Dateiformat v7 auf das neuere v7.3 umgestellt werden. Dies erreicht man entweder durch den Schalter '-v7.3' in jedem 'save()' des Quelltextes, oder durch das generelle Unstellen des Dateiformates auf die neue Version über File > Preferences > General > MAT-Files.

Leibniz Universität IT Services - URL: www.rrzn.uni-hannover.de/matlab.html
 
Dr Paul Cochrane, Letzte Änderung: 05.11.2012
Copyright Gottfried Wilhelm Leibniz Universität Hannover