#!/bin/sh
######################################
##### Model Transformation Tools #####
######################################
# Bourne shell script: mtt_header
# Headings for functions
# Copyright (C) 2000 by Peter J. Gawthrop
###############################################################
## Version control history
###############################################################
## $Id$
## $Log$
## Revision 1.50 2002/05/15 14:22:25 geraint
## Code for Simulink S-function target written direct to sfun.cc instead of
## calling .mexglx files. This eliminates the sfun dependency on Octave
## ColumnVectors. sys_sfun.cc should build directly on a MS Windows machine
## (can't test this yet).
##
## added sfun.zip target to create source code to export.
##
## Revision 1.49 2002/05/11 01:14:17 geraint
## Fix for [ 553218 ] simpar.oct and simpar.m different.
## Translation added between ColumnVector in base .cc and Octave_map in .oct.
##
## Revision 1.48 2002/05/08 14:51:03 geraint
## Moved matlab/octave data type conversion functions to a separate file.
##
## Revision 1.47 2002/05/07 23:50:34 geraint
## Preliminary support for Matlab dynamically linked shared objects:
## invoke with: mtt -cc sys rep mexglx
## ode2odes support is not yet included.
##
## Revision 1.46 2002/05/07 13:48:43 geraint
## Improved clarity of code generated for -cc and -oct (except ode2odes).
## Octave DEFUN_DLDs now call (rather than replace) their .cc equivalents.
##
## Revision 1.45 2002/05/02 09:30:22 gawthrop
## _ssim.m now returns t as 4th arg
##
## Revision 1.44 2002/05/01 17:30:56 geraint
## Improved pre-processor directives to better accommodate future alternatives (matlab)
## if necessary.
##
## Revision 1.43 2002/04/30 23:27:00 geraint
## Replaced octave_map with columnvector in simpar.cc. Not quite as descriptive but
## standardises the interfaces somewhat and reduces the dependency on liboctinterp
## (and thus libreadline, libkpathsea, libncurses, etc).
##
## Revision 1.42 2002/04/28 18:41:27 geraint
## Fixed [ 549658 ] awk should be gawk.
## Replaced calls to awk with call to gawk.
##
## Revision 1.41 2002/04/23 17:46:05 gawthrop
## _sim.m now returns time as third argument
##
## Revision 1.40 2002/04/17 16:23:59 geraint
## Partial fix for [ 545113 ] zeros missing in c++.
## Fixes -oct by removing duplicate initialisation (-c is still outstanding).
##
## Revision 1.39 2002/04/15 10:54:31 geraint
## Statically declare outputs and initialise to zero.
## This is necessary to prevent spurious values from being output when no assignments are made (i.e. when "y(i) := 0 for all u" (Reduce:see NERO)).
##
## Revision 1.38 2001/07/23 23:43:15 gawthrop
## header only version does not need to compute sizes from _def.r
##
## Revision 1.37 2001/07/13 04:54:04 geraint
## Branch merge: numerical-algebraic-solution back to main.
##
## Revision 1.36 2001/07/12 04:00:51 gawthrop
## Now zeros y correctly - ie Ny NOT Nx elements
##
## Revision 1.35 2001/06/13 10:39:51 gawthrop
## Zeros output matices in csex and cseo just in case some elements are
## actually zero and not set in code. Works for m and oct.
##
## Revision 1.34 2001/05/26 18:36:43 gawthrop
## Further modifications. Now works on rcPPP
## -- next jobs:
## add identification to ppp_nlin_sim
## create real-time ppp_nlin_run
##
## Revision 1.33 2001/05/26 15:46:38 gawthrop
## Updated to account for new nonlinear ppp
##
## Revision 1.32 2001/05/24 07:42:12 gawthrop
## Included and updated the missing tf_r2m
##
## Revision 1.31.2.2 2001/07/02 00:34:56 geraint
## gcc-3.0 compatibility.
##
## Revision 1.31.2.1 2001/05/04 04:07:24 geraint
## Numerical solution of algebraic equations.
## sys_ae.cc written for unsolved inputs.
## Solution of equations using hybrd from MINPACK (as used by Octave fsolve).
##
## Revision 1.31 2001/04/03 14:49:42 gawthrop
## Revised to incorporate new ssim (sensitivity simulation)
## representation (m only just now).
##
## Revision 1.30 2001/03/30 15:13:58 gawthrop
## Rationalised simulation modes to each return mtt_data
##
## Revision 1.29 2001/03/27 13:10:23 geraint
## Improved determination of Octave version.
##
## Revision 1.28 2001/02/17 03:48:17 geraint
## Use assignment LHS to gather tmp variable names.
## Prevents collection of long expressions, eg: tmp34*(tmp75
##
## Revision 1.27 2001/02/14 06:06:34 geraint
## Removed octave_value_list wrappers from standalone.exe - speed improvements
##
## Revision 1.26 2001/02/05 08:50:58 geraint
## Octave 2.1.x compatability.
##
## Revision 1.28 2001/01/17 21:16:15 geraint
## uncomment parameter assignments in .m reps
##
## Revision 1.27 2001/01/14 23:51:26 geraint
## declare parameters as variables instead of constants
##
## Revision 1.26 2001/01/07 21:22:47 geraint
## Compatibility with Octave 2.1.x
## vector_value ---> column_vector_value
##
## Revision 1.25 2000/12/05 12:05:26 peterg
## Changed to () form
##
## Revision 1.24 2000/12/05 10:04:52 peterg
## Fixed dummy variable bug
##
## Revision 1.23 2000/12/05 09:47:50 peterg
## Include crs as c files
##
## Revision 1.22 2000/12/04 12:19:12 peterg
## Changed $() to `` and $() to expr for sh compatibility -- geraint
##
## Revision 1.21 2000/12/04 08:52:40 peterg
## Zapped () in functions for sh compatibility
##
## Revision 1.20 2000/12/04 08:19:27 peterg
## Added switch declarations - in logic.cc
##
## Revision 1.19 2000/12/03 16:11:43 peterg
## Corrected bug in logic declatations
##
## Revision 1.18 2000/12/03 16:06:22 peterg
## Fixed bug in generating dummies
## Added logic declarations
##
## Revision 1.17 2000/12/01 20:55:01 peterg
## Added Geraint's fix for zeroing matrices
##
## Revision 1.16 2000/12/01 17:56:30 peterg
## Removed spurious echo '## Set matrices to zero' - thanks Geraint
##
## Revision 1.15 2000/11/29 21:06:16 peterg
## Removed Npar creation - not needed??
##
## Revision 1.14 2000/11/27 11:51:43 peterg
## Added zero matrices in matlab code
##
## Revision 1.13 2000/11/09 17:19:52 peterg
## Geraint's pow() mods
##
## Revision 1.12 2000/11/09 16:09:46 peterg
## Declare dummy variables (mtt_s1 etc)
##
## Revision 1.11 2000/11/09 15:29:35 peterg
## lower-case declarations
##
## Revision 1.10 2000/11/07 17:20:51 peterg
## useful-functions.hh now included locally
##
## Revision 1.9 2000/11/07 16:56:24 peterg
## Version from Geraint
##
## Revision 1.2 2000/11/03 00:55:42 geraint
## typo: missed out 'd' in mttedx
## todo: need to accommodate mttsimpar
##
## Revision 1.1 2000/11/02 04:28:39 geraint
## Initial revision
##
## Revision 1.8 2000/10/17 16:35:03 peterg
## No parameter,state or input conversion in txt files
##
## Revision 1.7 2000/10/17 09:53:20 peterg
## Fixed logic rep
##
## Revision 1.6 2000/10/17 08:37:23 peterg
## Included logic rep
##
## Revision 1.5 2000/10/14 09:12:14 peterg
## No dies arguments and output itself
##
## Revision 1.4 2000/10/14 06:49:31 peterg
## Make parameter listing representation dependent
##
## Revision 1.3 2000/10/11 08:59:15 peterg
## Added csex rep
##
## Revision 1.2 2000/10/11 08:01:42 peterg
## Added noglobal fudge
##
## Revision 1.1 2000/10/10 21:02:27 peterg
## Initial revision
##
###############################################################
# Arguments
system=$1
rep=$2
language=$3
fun_name=${1}_${2}
other=$4 # Anything else eg stdin
insertor=\<\< # help emacs sh-mode out with C++ lines
if [ -z "$system" ]; then
echo 'Usage: mtt_header sys rep lang [stdin]'
exit
fi
# get octave version
octave_development=`octave --version | gawk '{print $4}' | gawk -F\. '{print $2}'`
case `$MATRIX --version | gawk -F\. '{print $2}'` in
0) # stable
vector_value=vector_value
;;
1) # development
vector_value=column_vector_value
;;
*)
vector_value=column_vector_value
;;
esac
# Representation-specific stuff
eqnargs='mttx,mttu,mttt,mttpar'
inputeqnargs='mttx,mtty,mttt,mttpar'
case $rep in
ae)
states=yes;
inputs=yes;
parameters=yes;
output=mttyz;
args=$eqnargs;
;;
cse)
states=yes;
inputs=yes;
parameters=yes;
output='mttdx,mtte'
args=$eqnargs
;;
csex)
states=yes;
inputs=yes;
parameters=yes;
output=mttedx
args=$eqnargs
zeromatrices='edx';
;;
cseo)
states=yes;
inputs=yes;
parameters=yes;
output=mtty
args=$eqnargs
zeromatrices='y';
;;
dm)
states=no;
inputs=no;
parameters=yes;
output='mtta,mttb,mttc,mttd,mtte'
args=mttpar
zeromatrices='a b c d e';
;;
input)
inputs=no;
output=mttu
args=$inputeqnargs
if [ "$other" = "stdin" ]; then
states=no;
parameters=no;
declareinputs=no;
else
states=yes;
parameters=yes;
declareinputs=yes
declarestates=yes
fi
;;
logic)
states=no;
inputs=no;
parameters=yes;
output=mttopen
args=$eqnargs
declareinputs=yes
declarestates=yes
declareswitches=yes
;;
numpar)
states=no;
inputs=no;
parameters=no;
output='mttpar'
;;
ode)
states=yes;
inputs=yes;
parameters=yes;
output='mttdx'
args=$eqnargs
;;
odeo)
states=yes;
inputs=yes;
parameters=yes;
output='mtty'
args=$eqnargs
;;
ode2odes)
states=no;
inputs=no;
parameters=no;
output='mtt_data'
args='x0,par,simpar'
;;
simpar)
states=no;
inputs=no;
parameters=no;
output='mttsimpar'
oct_rep_include="#include <mtt_simpar.hh>"
oct_return_type="mtt_simpar"
;;
sm)
states=no;
inputs=no;
parameters=yes;
output='mtta,mttb,mttc,mttd'
args=mttpar;
zeromatrices='a b c d';
;;
smxa)
states=no;
inputs=no;
parameters=yes;
output='mtta'
args=$eqnargs
;;
smxax)
states=no;
inputs=no;
parameters=yes;
output='mttax'
args=$eqnargs
;;
state)
states=no;
inputs=no;
parameters=yes;
output=mttx
args=mttpar
declarestates=yes
;;
sim)
states=no;
inputs=no;
parameters=no;
output='y,x,t'
args='x0,par,simpar,u'
;;
ssim)
states=no;
inputs=no;
parameters=no;
output='y,y_par,x,t'
args='x0,par,simpar,u,index'
;;
tf)
states=no;
inputs=no;
parameters=yes;
output='mttnum,mttden'
args=mttpar;
;;
type)
states=no;
inputs=no;
parameters=no;
header_only=yes;
;;
*)
echo Representation $rep not supported - sorry; exit 1
esac
## Sort out parentheses
if [ -n "$args" ]; then
Args='('$args')'
fi
if [ -n "$output" ]; then
Output="[$output] = "
fi
# Lanuage specific stuff
case $language in
m)
Lc='##';
Rc='';
Lb='(';
Rb=')';
function="function"
declaration="$Output$1_$rep$Args;"
if [ "$other" != "stdin" ]; then
noglobals=true; # Fudge to make mtt_m2p work
fi
start='## BEGIN Code'
finish='## END Code'
var_declaration=
declarestates=no
declareinputs=no
declareswitches=no
;;
sh)
modeline='## -*-shell-script-*- Put Emacs into shell-script-mode ##';
Lc='##';
Rc='';
Lb='(';
Rb=')';
function=""
declaration=""
start=''
parameters=no
states=no
inputs=no
declarestates=no
declareinputs=no
declareswitches=no
;;
txt)
modeline='## -*-octave-*- Put Emacs into octave-mode ##';
Lc='##';
Rc='';
Lb='(';
Rb=')';
function=""
declaration=""
start=''
parameters=no
states=no
inputs=no
declarestates=no
declareinputs=no
declareswitches=no
;;
oct)
modeline="// -*-c++-*- Put Emacs into c++-mode";
Lc='//';
Lb='(';
Rb=')';
oct_header=yes;
constant_declaration="const double "
var_declaration="double "
minusone="-1"
map="_map"
declaredummies=yes
;;
c)
modeline="/* -*-c-*- Put Emacs into c-mode */";
Lc='/*'
Rc='*/'
Lb='['
Rb=']'
constant_declaration="const double "
var_declaration="double "
minusone="-1"
;;
*)
echo Language $language not supported - sorry; exit 1
esac
if [ "$rep" = "simpar" ]; then
output=${output}${map} # Output is simpar_map in this case
fi
get_sizes()
{
Nx=`mtt_getsize $system x` # States
Nxx=`mtt_getsize $system xx` # States x States
Nu=`mtt_getsize $system u` # Inputs
Ny=`mtt_getsize $system y` # Outputs
Nyz=`mtt_getsize $system yz` # Zero outputs
##Npar=`wc -l $system\_sympar.txt | gawk '{print $1}'`
}
zero_matrices()
{
## Set matrices to zero
echo
## echo '## Set matrices to zero'
for name in $zeromatrices; do
case $name in
a)
N=$Nx; M=$Nx
;;
b)
N=$Nx; M=$Nu
;;
c)
N=$Ny; M=$Nx
;;
d)
N=$Ny; M=$Nu
;;
e)
N=$Nx; M=$Nx
;;
edx)
N=$Nx; M=1
;;
y)
N=$Ny; M=1
;;
*)
esac
if [ "${language}" = "oct" ]; then
if [ "$M" = "1" ]; then
echo " mtt$name = zeros($N);"
else
echo " mtt$name = zeros($N,$M);"
fi
else
echo " mtt$name = zeros($N,$M);"
fi
done
}
declare_dummies()
{
# Get the dummies
dummies="mtt_tmp"
rm -f mtt_dummies
for dummy in $dummies; do
grep "${dummy}[0-9]*[ \t\n]*=" < ${fun_name}.m |\
gawk '{
if (match($1,dummy)==1)
print $1
}' dummy=$dummy >> mtt_dummies
done
dummy_list=`sort -u mtt_dummies`
# Comments
cat <<EOF
$Lc Declarations of dummies $Rc
EOF
for dummy in $dummy_list; do
echo ' ' $var_declaration $dummy';'
done
} # declare_dummies
declare_switches ()
{
cat <<EOF
$Lc Declarations of switches $Rc
EOF
strip_comments <${system}_switch.txt |\
gawk '{printf(" double %s_logic = 0;\n", tolower($1))}'
} # declare_switches
declare_vars()
{
# Grab the names
names=`gawk '{if ($1==var_type) print tolower($4)}' var_type=$1 ${system}_struc.txt`
# Comments
cat <<EOF
$Lc Declarations for $1 names $Rc
EOF
# Declarations
for name in $names; do
echo ' '$var_declaration $name';'
done
}
array2constant()
{
# Parameters
if [ "$parameters" = "yes" ]; then
cat <<EOF
$Lc Parameters $Rc
EOF
sympar2par_txt2m ${system} "" "$var_declaration" "$minusone" "$Lb" "$Rb"
fi
# States
if [ "$states" = "yes" ]; then
cat <<EOF
$Lc States $Rc
EOF
N=`n2m 1 $Nx`
for i in $N; do
echo $constant_declaration 'mttx'$i' = mttx'$Lb$i$minusone$Rb ';'
done
fi
if [ "$declarestates" = "yes" ]; then
declare_vars state
fi
# Inputs
if [ "$inputs" = "yes" ]; then
cat <<EOF
$Lc Inputs $Rc
EOF
N=`n2m 1 $Nu`
for i in $N; do
echo $constant_declaration 'mttu'$i' = mttu'$Lb$i$minusone$Rb';'
done
cat <<EOF
$Lc Unknown Inputs $Rc
EOF
Ni=`n2m 1 $Nyz`
for i in $Ni; do
echo $constant_declaration 'mttui'$i' = mttu'$Lb$Nu+$i$minusone$Rb';'
done
fi
if [ "$declareinputs" = "yes" ]; then
declare_vars input
fi
if [ "$declaredummies" = "yes" ]; then
declare_dummies
fi
if [ "$declareswitches" = "yes" ]; then
declare_switches
fi
zero_matrices;
}
# Argument specific stuff
get_arg_specific_stuff ()
{
arg_name=${1:-""}
case ${arg_name} in
mtta | mtte)
arg_type="Matrix"
arg_init="(MTTNX,MTTNX,0.0)"
;;
mttb)
arg_type="Matrix"
arg_init="(MTTNX,MTTNU,0.0)"
;;
mttc)
arg_type="Matrix"
arg_init="(MTTNY,MTTNX,0.0)"
;;
mttd)
arg_type="Matrix"
arg_init="(MTTNY,MTTNU,0.0)"
;;
mttax | mttdx | mttedx | mttx | mttopen)
arg_type="ColumnVector"
arg_init="(MTTNX,0.0)"
;;
mttpar)
arg_type="ColumnVector"
arg_init="(MTTNPAR,0.0)"
;;
mttsimpar_map)
arg_type="ColumnVector"
arg_init="(8,0.0)";
;;
mttu)
arg_type="ColumnVector"
arg_init="(MTTNU,0.0)"
;;
mttyz)
arg_type="ColumnVector"
arg_init="(MTTNYZ,0.0)"
;;
mtty)
arg_type="ColumnVector"
arg_init="(MTTNY,0.0)"
;;
mttt)
arg_type="const double"
arg_init=""
;;
nil)
arg_type="void *"
arg_init="(0x0)"
;;
*)
echo "Argument ${arg} not supported - sorry"; exit 1
esac
}
get_field ()
{ # parse comma separated string
s=${1:-""} # comma separated string
i=${2:-0} # field number in string
if [ 0 -eq ${i} ]; then # return number of fields
echo ${s} |\
gawk -F\, '{ print NF }'
else # return ith field
echo ${s} |\
gawk -F\, -v i=${i} '{ print $i }'
fi
}
get_extra_fields ()
{ # return list of words in s2 and not in s1
s1=${1:-""} # comma separated list
s2=${2:-""} # comma separated list
c1=`get_field ${s1} 0` # count words in s1
c2=`get_field ${s2} 0` # count words in s2
ans=""
i2=0 # s2 word index
while [ ${i2} -lt ${c2} ]; do
flag=0 # appearance of word in s1 and s2?
i2=`expr ${i2} + 1`
w2=`get_field ${s2} ${i2}` # i2 th word in s2
i1=0 # s1 word index
while [ ${i1} -lt ${c1} ]; do
i1=`expr ${i1} + 1`
w1=`get_field ${s1} ${i1}` # i1 th word in s1
if [ ${w2} = ${w1} ]; then
flag=1 # w2 occurs in s1
fi
done
if [ ${flag} -eq 0 ]; then # w2 is not in s1?
if [ -z ${ans:-""} ]; then # string is empty?
ans=${w2} # assign w2
else
ans=${ans},${w2} # append w2
fi
fi
done
echo ${ans}
}
write_cc_header ()
{
get_arg_specific_stuff ${output}
cat <<EOF
#include <octave/oct.h>
#include "useful-functions.hh"
#include "${system}_cr.h"
#include "${system}_def.h"
#include "${system}_sympar.h"
// Code generation directives
#define STANDALONE 0
#define OCTAVEDLD 1
#define MATLABMEX 2
#ifndef CODEGENTARGET
#define CODEGENTARGET STANDALONE
#endif // CODEGENTARGET
${arg_type} ${system}_${rep} (
EOF
if [ -z ${args:-""} ]; then
printf "\tvoid"
else
c=`get_field ${args:-""} 0`
i=0
while [ ${i} -lt ${c} ]; do
i=`expr ${i} + 1`
if [ ${i} -lt ${c} ]; then
comma=","
else
comma=""
fi
w=`get_field ${args} ${i}`
get_arg_specific_stuff ${w}
printf "\t${arg_type}\t&${w}${comma}\n"
done
fi
get_arg_specific_stuff ${output}
cat <<EOF
)
{
static ${arg_type} ${output} ${arg_init};
EOF
}
write_cc_footer ()
{
cat <<EOF
// BEGIN Code
// END Code
return ${output};
}
EOF
}
map_oct_inputs ()
{
s=${1:-""} # comma separated input list
if [ -z ${s:-""} ];then return; fi
c=`get_field ${s} 0` # count of inputs
i=0
printf " if (${c} != args.length ()) usage (\"${fun_name} expected ${c} argument(s): ${s}\");\n\n"
while [ ${i} -lt ${c} ]; do
j=${i}
i=`expr ${i} + 1`
w=`get_field ${s} ${i}` # argument name
get_arg_specific_stuff ${w}
case ${arg_type} in
"const double")
printf " ${arg_type}\t${w}\t= args(${j}).double_value ();\n"
;;
ColumnVector | Matrix | *)
printf " ${arg_type}\t${w}\t= args(${j}).%s ();\n" ${vector_value}
;;
esac
done
}
map_mex_cc_inputs ()
{
s=${1:-""} # comma separated input list
if [ -z ${s:-""} ];then return; fi
c=`get_field ${s} 0` # count of inputs
i=0
cat <<EOF
if (${c} != nrhs)
{
std::cerr $insertor "${fun_name} expected " $insertor ${c} $insertor " argument(s): ${s}" $insertor std::endl;
return;
}
EOF
while [ ${i} -lt ${c} ]; do
j=${i}
i=`expr ${i} + 1`
w=`get_field ${s} ${i}` # argument name
get_arg_specific_stuff ${w}
case ${arg_type} in
"const double")
printf " ${arg_type}\t${w}\t= mtt_double (prhs [${j}]);\n"
;;
ColumnVector | Matrix | *)
printf " ${arg_type}\t${w}\t= mtt_${arg_type} (prhs [${j}]);\n"
;;
esac
done
}
write_oct()
{
func=${1:-"<insert function name>"}
args=${2:-""}
cat <<EOF
#if (CODEGENTARGET == OCTAVEDLD)
$oct_rep_include
DEFUN_DLD (${system}_${rep}, args, ,
"Usage: [$output] = ${system}_${rep}($args)\nOctave ${rep} representation of system ${system}\nGenerated by MTT on `date`")
{
static octave_value_list retval;
EOF
map_oct_inputs ${args}
cat <<EOF
retval (0) = octave_value ($oct_return_type (${func} (${args})));
return retval;
}
#endif // (CODEGENTARGET == OCTAVEDLD)
EOF
}
write_mex_cc ()
{
func=${1:-"<insert function name>"}
args=${2:-""}
cat <<EOF
#if (CODEGENTARGET == MATLABMEX)
#include <mtt_matlab_octave.hh>
extern "C"
{
void mexFunction (int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
EOF
map_mex_cc_inputs ${args}
cat <<EOF
plhs[0] = mtt_mxArray (${func} (${args}));
}
}
#endif
EOF
}
# Header information
cat<<EOF
$modeline
$function $declaration
$Lc $declaration
$Lc System $system, representation $rep, language $language; $Rc
$Lc File $1_$rep.$language; $Rc
$Lc Generated by MTT on `date`; $Rc
EOF
if [ -n "${header_only}" ]; then
exit
else
get_sizes;
fi
if [ ${language} = "oct" ];then
# standalone
write_cc_header
array2constant
write_cc_footer
# oct and mex code
write_oct ${system}_${rep} ${args}
write_mex_cc ${system}_${rep} ${args}
elif [ $language = "c" ]; then
array2constant
cat <<EOF
/* BEGIN Code */
/* END Code */
EOF
else
if [ -n "$noglobals" ]; then
cat<<EOF
## Horrible fudge to make mtt_m2p work
global ...
mtt_no_globals ;
EOF
fi
## Arrays
array2constant
# Mark start of code
echo
echo $start
fi