Browse Source

Initial commit of "Rocket Workbench".

Taken from sources in CVS at:
    https://sourceforge.net/projects/rocketworkbench/

Sources extracted in two steps:
1. Pull entire project tree into a subdir "rwb" via "rsync":
    rsync -a a.cvs.sourceforge.net::cvsroot/rocketworkbench/ rwb/.
2. Export sources:
    export CVSROOT=$(pwd)/rwb
    SUBDIRS="analyser cpropep cpropep-web CVSROOT data libcompat libcpropep libnum libsimulation libthermo prop rocketworkbench rockflight"
    mkdir rwbx; cd rwbx
    cvs export -D now ${SUBDIRS}

After this (and some backups for safety), the directory content was
added to a Git repo:
    git init .
    git add *
master
R. J. Dev. Kwan 4 years ago
commit
eb05416991
411 changed files with 362300 additions and 0 deletions
  1. +13
    -0
      CVSROOT/checkoutlist
  2. +15
    -0
      CVSROOT/commitinfo
  3. +11
    -0
      CVSROOT/config
  4. +23
    -0
      CVSROOT/cvswrappers
  5. +21
    -0
      CVSROOT/editinfo
  6. +26
    -0
      CVSROOT/loginfo
  7. +26
    -0
      CVSROOT/modules
  8. +12
    -0
      CVSROOT/notify
  9. +13
    -0
      CVSROOT/rcsinfo
  10. +20
    -0
      CVSROOT/taginfo
  11. +21
    -0
      CVSROOT/verifymsg
  12. +35
    -0
      analyser/src/Makefile
  13. +365
    -0
      analyser/src/analyser.c
  14. +51
    -0
      analyser/src/analyser.h
  15. +4
    -0
      analyser/src/essai.txt
  16. +14
    -0
      analyser/src/test.conf
  17. +114
    -0
      analyser/src/test2.txt
  18. +11
    -0
      cpropep-web/Makefile
  19. +40
    -0
      cpropep-web/src/Makefile
  20. +351
    -0
      cpropep-web/src/cgitest.c
  21. +17
    -0
      cpropep/Makefile
  22. +135
    -0
      cpropep/doc/thermo.html
  23. +31
    -0
      cpropep/src/Makefile
  24. +36
    -0
      cpropep/src/Makefile.win
  25. +31
    -0
      cpropep/src/README.txt
  26. +764
    -0
      cpropep/src/cpropep.c
  27. +2
    -0
      cpropep/src/cpropep.conf
  28. +102
    -0
      cpropep/src/input.pro
  29. +1098
    -0
      data/propellant.dat
  30. +24
    -0
      data/references.txt
  31. +14517
    -0
      data/thermo.dat
  32. +37
    -0
      libcompat/Makefile
  33. +50
    -0
      libcompat/Makefile.win
  34. +68
    -0
      libcompat/include/compat.h
  35. +10
    -0
      libcompat/include/getopt.h
  36. +46
    -0
      libcompat/src/compat.c
  37. +83
    -0
      libcompat/src/getopt.c
  38. +11
    -0
      libcpropep/Makefile
  39. +50
    -0
      libcpropep/Makefile.win
  40. +11
    -0
      libcpropep/include/const.h
  41. +60
    -0
      libcpropep/include/conversion.h
  42. +8
    -0
      libcpropep/include/derivative.h
  43. +156
    -0
      libcpropep/include/equilibrium.h
  44. +18
    -0
      libcpropep/include/performance.h
  45. +69
    -0
      libcpropep/include/print.h
  46. +22
    -0
      libcpropep/include/return.h
  47. +161
    -0
      libcpropep/include/type.h
  48. +32
    -0
      libcpropep/src/Makefile
  49. +241
    -0
      libcpropep/src/derivative.c
  50. +1258
    -0
      libcpropep/src/equilibrium.c
  51. +562
    -0
      libcpropep/src/performance.c
  52. +427
    -0
      libcpropep/src/print.c
  53. +13
    -0
      libnum/Makefile
  54. +43
    -0
      libnum/Makefile.win
  55. +149
    -0
      libnum/include/num.h
  56. +38
    -0
      libnum/src/Makefile
  57. +32
    -0
      libnum/src/general.c
  58. +172
    -0
      libnum/src/lu.c
  59. +31
    -0
      libnum/src/newton.c
  60. +54
    -0
      libnum/src/print.c
  61. +31
    -0
      libnum/src/ptfix.c
  62. +107
    -0
      libnum/src/rk4.c
  63. +179
    -0
      libnum/src/rkf.c
  64. +33
    -0
      libnum/src/sec.c
  65. +49
    -0
      libnum/src/simpson.c
  66. +108
    -0
      libnum/src/spline.c
  67. +86
    -0
      libnum/src/sysnewton.c
  68. +344
    -0
      libnum/src/test.c
  69. +16
    -0
      libnum/src/trapeze.c
  70. +43
    -0
      libsimulation/Makefile
  71. +2
    -0
      libsimulation/TODO
  72. +51
    -0
      libsimulation/c++rocket.h
  73. +193
    -0
      libsimulation/lsode.cc
  74. +93
    -0
      libsimulation/lsode.h
  75. +234
    -0
      libsimulation/modeles.cc
  76. +146
    -0
      libsimulation/motor.l
  77. +118
    -0
      libsimulation/rk4.cc
  78. +65
    -0
      libsimulation/rk4.h
  79. +314
    -0
      libsimulation/rocket.cc
  80. +174
    -0
      libsimulation/rocket.h
  81. +51
    -0
      libsimulation/simulation.cc
  82. +74
    -0
      libsimulation/simulation.h
  83. +348
    -0
      libsimulation/simulator/.ccmalloc
  84. +35
    -0
      libsimulation/simulator/Makefile
  85. +78
    -0
      libsimulation/simulator/c++rocket.cc
  86. +11
    -0
      libthermo/Makefile
  87. +50
    -0
      libthermo/Makefile.win
  88. +56
    -0
      libthermo/include/load.h
  89. +218
    -0
      libthermo/include/thermo.h
  90. +31
    -0
      libthermo/src/Makefile
  91. +520
    -0
      libthermo/src/load.c
  92. +563
    -0
      libthermo/src/thermo.c
  93. +9
    -0
      prop/Makefile
  94. +38
    -0
      prop/Makefile.win
  95. +36
    -0
      prop/src/Makefile
  96. +334
    -0
      prop/src/plot.c
  97. +611
    -0
      prop/src/prop.c
  98. +47
    -0
      rocketworkbench/BUILD
  99. +14
    -0
      rocketworkbench/Documentation/analyser/examples/H.conf
  100. +114
    -0
      rocketworkbench/Documentation/analyser/examples/H.dat

+ 13
- 0
CVSROOT/checkoutlist View File

@ -0,0 +1,13 @@
# The "checkoutlist" file is used to support additional version controlled
# administrative files in $CVSROOT/CVSROOT, such as template files.
#
# The first entry on a line is a filename which will be checked out from
# the corresponding RCS file in the $CVSROOT/CVSROOT directory.
# The remainder of the line is an error message to use if the file cannot
# be checked out.
#
# File format:
#
# [<whitespace>]<filename><whitespace><error message><end-of-line>
#
# comment lines begin with '#'

+ 15
- 0
CVSROOT/commitinfo View File

@ -0,0 +1,15 @@
# The "commitinfo" file is used to control pre-commit checks.
# The filter on the right is invoked with the repository and a list
# of files to check. A non-zero exit of the filter program will
# cause the commit to be aborted.
#
# The first entry on a line is a regular expression which is tested
# against the directory that the change is being committed to, relative
# to the $CVSROOT. For the first match that is found, then the remainder
# of the line is the name of the filter to run.
#
# If the repository name does not match any of the regular expressions in this
# file, the "DEFAULT" line is used, if it is specified.
#
# If the name "ALL" appears as a regular expression it is always used
# in addition to the first matching regex or "DEFAULT".

+ 11
- 0
CVSROOT/config View File

@ -0,0 +1,11 @@
# Set this to "no" if pserver shouldn't check system users/passwords
#SystemAuth=no
# Set `PreservePermissions' to `yes' to save file status information
# in the repository.
#PreservePermissions=no
# Set `TopLevelAdmin' to `yes' to create a CVS directory at the top
# level of the new working directory when using the `cvs checkout'
# command.
#TopLevelAdmin=no

+ 23
- 0
CVSROOT/cvswrappers View File

@ -0,0 +1,23 @@
# This file affects handling of files based on their names.
#
# The -t/-f options allow one to treat directories of files
# as a single file, or to transform a file in other ways on
# its way in and out of CVS.
#
# The -m option specifies whether CVS attempts to merge files.
#
# The -k option specifies keyword expansion (e.g. -kb for binary).
#
# Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers)
#
# wildcard [option value][option value]...
#
# where option is one of
# -f from cvs filter value: path to filter
# -t to cvs filter value: path to filter
# -m update methodology value: MERGE or COPY
# -k expansion mode value: b, o, kkv, &c
#
# and value is a single-quote delimited value.
# For example:
#*.gif -k 'b'

+ 21
- 0
CVSROOT/editinfo View File

@ -0,0 +1,21 @@
# The "editinfo" file is used to allow verification of logging
# information. It works best when a template (as specified in the
# rcsinfo file) is provided for the logging procedure. Given a
# template with locations for, a bug-id number, a list of people who
# reviewed the code before it can be checked in, and an external
# process to catalog the differences that were code reviewed, the
# following test can be applied to the code:
#
# Making sure that the entered bug-id number is correct.
# Validating that the code that was reviewed is indeed the code being
# checked in (using the bug-id number or a seperate review
# number to identify this particular code set.).
#
# If any of the above test failed, then the commit would be aborted.
#
# Actions such as mailing a copy of the report to each reviewer are
# better handled by an entry in the loginfo file.
#
# One thing that should be noted is the the ALL keyword is not
# supported. There can be only one entry that matches a given
# repository.

+ 26
- 0
CVSROOT/loginfo View File

@ -0,0 +1,26 @@
# The "loginfo" file controls where "cvs commit" log information
# is sent. The first entry on a line is a regular expression which must match
# the directory that the change is being made to, relative to the
# $CVSROOT. If a match is found, then the remainder of the line is a filter
# program that should expect log information on its standard input.
#
# If the repository name does not match any of the regular expressions in this
# file, the "DEFAULT" line is used, if it is specified.
#
# If the name ALL appears as a regular expression it is always used
# in addition to the first matching regex or DEFAULT.
#
# You may specify a format string as part of the
# filter. The string is composed of a `%' followed
# by a single format character, or followed by a set of format
# characters surrounded by `{' and `}' as separators. The format
# characters are:
#
# s = file name
# V = old version number (pre-checkin)
# v = new version number (post-checkin)
#
# For example:
#DEFAULT (echo ""; id; echo %s; date; cat) >> $CVSROOT/CVSROOT/commitlog
# or
#DEFAULT (echo ""; id; echo %{sVv}; date; cat) >> $CVSROOT/CVSROOT/commitlog

+ 26
- 0
CVSROOT/modules View File

@ -0,0 +1,26 @@
# Three different line formats are valid:
# key -a aliases...
# key [options] directory
# key [options] directory files...
#
# Where "options" are composed of:
# -i prog Run "prog" on "cvs commit" from top-level of module.
# -o prog Run "prog" on "cvs checkout" of module.
# -e prog Run "prog" on "cvs export" of module.
# -t prog Run "prog" on "cvs rtag" of module.
# -u prog Run "prog" on "cvs update" of module.
# -d dir Place module in directory "dir" instead of module name.
# -l Top-level directory only -- do not recurse.
#
# NOTE: If you change any of the "Run" options above, you'll have to
# release and re-checkout any working directories of these modules.
#
# And "directory" is a path to a directory relative to $CVSROOT.
#
# The "-a" option specifies an alias. An alias is interpreted as if
# everything on the right of the "-a" had been typed on the command line.
#
# You can encode a module within a module by using the special '&'
# character to interpose another module into the current module. This
# can be useful for creating a module that consists of many directories
# spread out over the entire source repository.

+ 12
- 0
CVSROOT/notify View File

@ -0,0 +1,12 @@
# The "notify" file controls where notifications from watches set by
# "cvs watch add" or "cvs edit" are sent. The first entry on a line is
# a regular expression which is tested against the directory that the
# change is being made to, relative to the $CVSROOT. If it matches,
# then the remainder of the line is a filter program that should contain
# one occurrence of %s for the user to notify, and information on its
# standard input.
#
# "ALL" or "DEFAULT" can be used in place of the regular expression.
#
# For example:
#ALL mail %s -s "CVS notification"

+ 13
- 0
CVSROOT/rcsinfo View File

@ -0,0 +1,13 @@
# The "rcsinfo" file is used to control templates with which the editor
# is invoked on commit and import.
#
# The first entry on a line is a regular expression which is tested
# against the directory that the change is being made to, relative to the
# $CVSROOT. For the first match that is found, then the remainder of the
# line is the name of the file that contains the template.
#
# If the repository name does not match any of the regular expressions in this
# file, the "DEFAULT" line is used, if it is specified.
#
# If the name "ALL" appears as a regular expression it is always used
# in addition to the first matching regex or "DEFAULT".

+ 20
- 0
CVSROOT/taginfo View File

@ -0,0 +1,20 @@
# The "taginfo" file is used to control pre-tag checks.
# The filter on the right is invoked with the following arguments:
#
# $1 -- tagname
# $2 -- operation "add" for tag, "mov" for tag -F, and "del" for tag -d
# $3 -- repository
# $4-> file revision [file revision ...]
#
# A non-zero exit of the filter program will cause the tag to be aborted.
#
# The first entry on a line is a regular expression which is tested
# against the directory that the change is being committed to, relative
# to the $CVSROOT. For the first match that is found, then the remainder
# of the line is the name of the filter to run.
#
# If the repository name does not match any of the regular expressions in this
# file, the "DEFAULT" line is used, if it is specified.
#
# If the name "ALL" appears as a regular expression it is always used
# in addition to the first matching regex or "DEFAULT".

+ 21
- 0
CVSROOT/verifymsg View File

@ -0,0 +1,21 @@
# The "verifymsg" file is used to allow verification of logging
# information. It works best when a template (as specified in the
# rcsinfo file) is provided for the logging procedure. Given a
# template with locations for, a bug-id number, a list of people who
# reviewed the code before it can be checked in, and an external
# process to catalog the differences that were code reviewed, the
# following test can be applied to the code:
#
# Making sure that the entered bug-id number is correct.
# Validating that the code that was reviewed is indeed the code being
# checked in (using the bug-id number or a seperate review
# number to identify this particular code set.).
#
# If any of the above test failed, then the commit would be aborted.
#
# Actions such as mailing a copy of the report to each reviewer are
# better handled by an entry in the loginfo file.
#
# One thing that should be noted is the the ALL keyword is not
# supported. There can be only one entry that matches a given
# repository.

+ 35
- 0
analyser/src/Makefile View File

@ -0,0 +1,35 @@
CC = gcc
COPT = -g -Wall -O3 #-pg
LIB = -lnum -lm -lgpcp -lconvert
ROOT = ../..
LIBDIR = -L$(ROOT)/libnum/lib \
-L$(ROOT)/gpcp/src/ \
-L$(ROOT)/libconvert/lib/
INCDIR = -I$(ROOT)/libnum/include/ \
-I$(ROOT)/gpcp/src/ \
-I$(ROOT)/libconvert/include/
DEF = -DGCC
PROG = analyser
OBJS = analyser.o
.SUFFIXES: .c
all: $(PROG)
.c.o:
$(CC) $(DEF) $(INCDIR) $(COPT) -c $*.c -o $*.o
$(PROG): $(OBJS) $(LIBNAME)
$(CC) $(COPT) $(OBJS) $(LIBDIR) $(LIB) -o $@
clean:
rm -f *.o *~
deep-clean: clean
rm -f $(PROG)

+ 365
- 0
analyser/src/analyser.c View File

@ -0,0 +1,365 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <math.h>
/* Numerical method library */
#include "num.h"
/* Config file parser library */
#include "gpcp.h"
/* Conversion library */
#include "convert.h"
#include "analyser.h"
#define MAX_LINE 100
Options analyser_options[] = {
{"datafile", STRING, NULL},
{"format", PARENT, NULL},
{"column", INTEGER, "format"},
{"time", PARENT, "format"},
{"col", INTEGER, "time"},
{"units", STRING, "time"},
{"thrust", PARENT, "format"},
{"col", INTEGER, "thrust"},
{"units", STRING, "thrust"},
{"comments", STRING, "format"},
{"motor", PARENT, NULL},
{"propellant_mass", PARENT, "motor"},
{"val", FLOAT, "propellant_mass"},
{"units", STRING, "propellant_mass"},
{"total_mass", PARENT, "motor"},
{"val", FLOAT, "total_mass"},
{"units", STRING, "total_mass"},
{NULL, 0, NULL}
};
int main(int argc, char *argv[])
{
int n, c;
char *datafile; /* Name of the datafile */
double *data = NULL; /* Array containing the data read in the data file */
format_t format;
motor_t motor;
results_t results;
/* Name of the config file */
char filename[FILENAME_MAX] = "\0";
GPCP_RegisterOptions(analyser_options);
/* Read the command line arguments */
while (1)
{
c = getopt(argc, argv, "f:");
if (c == EOF)
break;
switch (c)
{
case 'f':
strncpy(filename, optarg, FILENAME_MAX);
break;
}
}
if (filename[0] =='\0')
{
printf("A config file must be specified.\n");
return -1;
}
if (parse_config(filename, &datafile, &format, &motor))
return 1;
if (parse_datafile(datafile, &data, &n, &format))
return 1;
analyse_data(data, n, &results, &format, &motor);
print_results(&results);
return 0;
}
void print_results(results_t *res)
{
printf("Results of thrust data analysis.\n");
printf("--------------------------------\n");
printf("Maximum thrust : %.2f N\n", res->max_thrust);
printf("Total impulse : %.2f Ns\n", res->impulse);
printf("Average thrust : %.2f N\n", res->avg_thrust);
printf("Burn time : %.2f s\n", res->burn_time);
printf("Exhaust velocity : %.2f m/s\n", res->vg);
printf("Specific impulse : %.2f s\n", res->isp);
printf("Propellant mass fraction : %.2f \n", res->prop_mass_fraction);
printf("Impulse to weight ratio : %.2f \n", res->impulse_to_weight);
// I will have to invert thrust and impulse in the definition
printf("Motor classification : %c-%d\n",
'A' + (char) (log(res->max_thrust/2.5)/log(2)) + 1,
(int) res->impulse);
}
int analyse_data(double *data, int n, results_t *res, format_t *f, motor_t *m)
{
int i;
double max;
double integral;
/* Calculation based on those data */
//double max_thrust; /* Maximum thrust */
//double avg_thrust; /* Mean thrust */
//double burn_time; /* Burning time */
//double impulse; /* Total impulse */
//double vg; /* Exhaust velocity */
//double isp; /* Specific impulse */
//double prop_mass_fraction; /* Propellant mass fraction */
//double impulse_to_weight; /* Impulse to weight ratio */
memset(res, 0x00, sizeof(results_t));
max = 0;
for (i = 0; i < n; i++)
{
max = ((data[1 + i*f->col] > max) ? data[1 + i*f->col] : max);
}
res->max_thrust = max;
res->burn_time = data[0 + (n - 1)*f->col];
simpson(data, n, 2, 1, &integral);
res->impulse = integral;
res->avg_thrust = res->impulse / res->burn_time;
if (m->isprop)
{
res->vg = res->impulse / m->prop_mass;
res->isp = res->vg / 9.80665;
}
if (m->isprop && m->istot)
{
res->prop_mass_fraction = m->prop_mass / m->total_mass;
res->impulse_to_weight = res->impulse / (m->total_mass * 9.80665);
}
return 0;
}
int parse_datafile(char *datafile, double **data, int *ndata, format_t *f)
{
FILE *inputfile;
int i, n;
char *token;
char line[MAX_LINE];
double *tmp;
if ((inputfile = fopen(datafile, "r")) == NULL)
{
printf("Unable to open datafile.\n");
return -1;
}
tmp = (double *) malloc (sizeof(double) * f->col);
/* Reading file */
n = 0;
while (fgets(line, MAX_LINE, inputfile) != NULL)
{
if (line[0] != f->comments[0]) /* comments */
{
token = strtok(line, " \t");
if (!isdigit(token[0])) /* no number on this line, skip... */
continue;
tmp[0] = atof(token);
for (i = 1; i < f->col; i++)
{
token = strtok(NULL, " \t");
if (!isdigit(token[0])) /* error, there is missing number
on this line */
return -1;
tmp[i] = atof(token);
}
/* reallocating the memory */
*data = (double *) realloc(*data, sizeof(double) * 2 * (n + 1));
(*data)[0 + n*f->col] = tmp[f->time - 1] * f->sctime;
(*data)[1 + n*f->col] = tmp[f->thrust - 1] * f->scthrust;
n++;
}
}
*ndata = n;
fclose(inputfile);
return 0;
}
int parse_config(char *configfile, char **datafile, format_t *f, motor_t *m)
{
char *tmp;
float number;
Data *config;
/* read the file */
if (GPCP_ReadFile(configfile, &config) != 0)
{
printf("Error reading config file.\n");
return 1;
}
/* Use config data (we must provide string length*/
if (GPCP_GetValue ("datafile", datafile) != 0)
{
printf("A 'datafile' must be specified.\n");
return 1;
}
if (GPCP_EnterLevel("format", 0) != 0)
{
printf("The file format must be specified.\n");
return 1;
}
else
{
if (GPCP_GetValue ("column", &f->col) != 0)
{
printf("Unable to get number of column.\n");
return 1;
}
if (GPCP_GetValue ("comments", &f->comments) != 0)
{
printf("No 'comments' sign specified: assuming '#'.\n");
strcpy(f->comments, "#");
}
if (GPCP_EnterLevel("time", 0) == -1)
{
printf("Unable to get time information.\n");
return 1;
}
else
{
if (GPCP_GetValue ("col", &f->time) != 0)
{
printf("Unable to get time column index.\n");
return 1;
}
if (GPCP_GetValue ("units", &tmp) != 0)
{
printf("Unable to get units.\n");
return 1;
}
f->sctime = 1;
free(tmp);
GPCP_ExitLevel();
}
if (GPCP_EnterLevel("thrust", 0) == -1)
{
printf("Unable to get thrust information.\n");
return 1;
}
else
{
if (GPCP_GetValue ("col", &f->thrust) != 0)
{
printf("Unable to get time column index.\n");
return 1;
}
if (GPCP_GetValue ("units", &tmp) != 0)
{
printf("Unable to get units.\n");
return 1;
}
f->scthrust = 1.0;
convert("force", &(f->scthrust), tmp, "N");
free(tmp);
GPCP_ExitLevel();
}
GPCP_ExitLevel();
}
m->isprop = 0;
m->istot = 0;
if (GPCP_EnterLevel("motor", 0) != 0)
{
printf("No motor information specified.\n");
}
else
{
if (GPCP_EnterLevel("propellant_mass", 0) == -1)
{
printf("No propellant mass specified.\n");
}
else
{
if (GPCP_GetValue ("val", &number) != 0)
{
printf("Unable propellant mass.\n");
return 1;
}
if (GPCP_GetValue ("units", &tmp) != 0)
{
printf("Unable to get units.\n");
return 1;
}
m->prop_mass = (double) number;
if (convert("mass", &(m->prop_mass), tmp, "kg"))
{
printf("Incorrect units: %s\n", tmp);
return -1;
}
free(tmp);
m->isprop = 1;
GPCP_ExitLevel();
}
if (GPCP_EnterLevel("total_mass", 0) == -1)
{
printf("No total mass specified.\n");
}
else
{
if (GPCP_GetValue ("val", &number) != 0)
{
printf("Unable total mass.\n");
return 1;
}
if (GPCP_GetValue ("units", &tmp) != 0)
{
printf("Unable to get units.\n");
return 1;
}
m->total_mass = (double) number;
if (convert("mass", &(m->total_mass), tmp, "kg"))
{
printf("Incorrect units: %s\n", tmp);
return -1;
}
free(tmp);
m->istot = 1;
GPCP_ExitLevel();
}
GPCP_ExitLevel();
}
GPCP_FreeData(&config);
return 0;
}

+ 51
- 0
analyser/src/analyser.h View File

@ -0,0 +1,51 @@
#ifndef analyser_h
#define analyser_h
struct flags
{
unsigned char a:1, b:1, c:1, d:1, e:1, f:1, g:1, h:1;
};
typedef unsigned char uchar;
typedef struct _motor
{
uchar isprop; /* prop mass have bben read */
uchar istot; /* total mass have been read */
double prop_mass; /* Propellant mass (kg)*/
double total_mass; /* Total engine mass (kg)*/
} motor_t;
typedef struct _results
{
double max_thrust; /* Maximum thrust */
double avg_thrust; /* Mean thrust */
double burn_time; /* Burning time */
double impulse; /* Total impulse */
double vg; /* Exhaust velocity */
double isp; /* Specific impulse */
double prop_mass_fraction; /* Propellant mass fraction */
double impulse_to_weight; /* Impulse to weight ratio */
} results_t;
typedef struct _format
{
int col; /* Number of columns */
int time; /* Index of time column */
double sctime; /* convesion factor to put time in seconds */
int thrust; /* Index of thrust column */
double scthrust; /* Conversion factor to put thrust in N */
char *comments; /* Character beginning commented lines */
} format_t;
void print_results(results_t *res);
int analyse_data(double *data, int n, results_t *res, format_t *f, motor_t *m);
int parse_config(char *configfile, char **datafile, format_t *f, motor_t *m);
int parse_datafile(char *datafile, double **data, int *ndata, format_t *f);
#endif /* analyser_h */

+ 4
- 0
analyser/src/essai.txt View File

@ -0,0 +1,4 @@
0 0
1 0.25
2 1
3 2.25

+ 14
- 0
analyser/src/test.conf View File

@ -0,0 +1,14 @@
datafile = "test2.txt"
format = (
column = 2,
time = (col = 1, units = "s"),
thrust = (col = 2, units = "lbf"),
comments = "#"
)
motor = (propellant_mass = (val = 117.,
units = "g"),
total_mass = (val = 200.,
units = "g")
)

+ 114
- 0
analyser/src/test2.txt View File

@ -0,0 +1,114 @@
# Test du moteur H...
# time (s) thrust (lbf)
0 4
0.01 9.6
0.02 14
0.03 18.3
0.04 21.9
0.05 24.9
0.06 27.4
0.07 29.5
0.08 31.3
0.09 35
0.1 39
0.11 43.8
0.12 48.6
0.13 51
0.14 54.7
0.15 57.5
0.16 59.5
0.17 62.5
0.18 63.2
0.19 65
0.2 65.9
0.21 66.8
0.22 66.8
0.23 67.5
0.24 67.4
0.25 67.8
0.26 67.7
0.27 68.2
0.28 68.6
0.29 68.4
0.3 68.3
0.31 68.5
0.32 67.9
0.33 65.4
0.34 64
0.35 62.1
0.36 61.2
0.37 59.7
0.38 58.9
0.39 57.4
0.4 56.8
0.41 55.7
0.42 54.9
0.43 54.5
0.44 52.9
0.45 51.4
0.46 50.2
0.47 48.3
0.48 46.9
0.49 45.8
0.5 44.8
0.51 44.1
0.52 43.3
0.53 42.3
0.54 41.8
0.55 41.2
0.56 39.8
0.57 39.6
0.58 37.9
0.59 37.5
0.6 36.6
0.61 36
0.62 35.3
0.63 34.9
0.64 34.3
0.65 34
0.66 33.1
0.67 32.5
0.68 30.8
0.69 29.8
0.7 28.7
0.71 27.1
0.72 26.1
0.73 25.2
0.74 24.2
0.75 23.6
0.76 23.4
0.77 22.6
0.78 21.9
0.79 20.3
0.8 19
0.81 17.8
0.82 16.6
0.83 14.8
0.84 14
0.85 12.5
0.86 12.2
0.87 11.2
0.88 11
0.89 9.8
0.9 9
0.91 8.3
0.92 7.2
0.93 6.3
0.94 5.7
0.95 4.6
0.96 4.2
0.97 3.6
0.98 2.9
0.99 2.7
1 2.3
1.01 2.1
1.02 1.9
1.03 1.3
1.04 1.3
1.05 1.2
1.06 0.8
1.07 0.6
1.08 0.5
1.09 0.5
1.1 0.5

+ 11
- 0
cpropep-web/Makefile View File

@ -0,0 +1,11 @@
all:
make -C src all
clean:
make -C src clean
deep-clean: clean
make -C src deep-clean
upload:
make -C src upload

+ 40
- 0
cpropep-web/src/Makefile View File

@ -0,0 +1,40 @@
CC = gcc
COPT = -g -Wall
LIB = -lcpropep -lthermo -lm -lnum -lcgi
ROOT = ../..
LIBDIR = -L$(ROOT)/libnum/lib/ \
-L$(ROOT)/libcpropep/lib/ \
-L$(ROOT)/libthermo/lib/
INCDIR = -I$(ROOT)/libnum/include/ \
-I$(ROOT)/libcpropep/include/ \
-I$(ROOT)/libthermo/include/ \
-I$(ROOT)/libcompat/include/
DEF = -DGCC -DSOURCEFORGE
PROG = cgitest
OBJS = cgitest.o
.SUFFIXES: .c
all: $(PROG)
.c.o:
$(CC) $(DEF) $(INCDIR) $(COPT) -c $*.c -o $*.o
$(PROG): $(OBJS)
$(CC) $(COPT) $(OBJS) $(LIBDIR) $(LIB) -o $@
clean:
rm -f *.o *~
deep-clean: clean
rm -f cgitest
upload:
scp $(PROG) antoine@rocketworkbench.sourceforge.net:/home/groups/rocketworkbench/cgi-bin/

+ 351
- 0
cpropep-web/src/cgitest.c View File

@ -0,0 +1,351 @@
/*
cgitest.c - Testprogram for cgi.o
Copyright (c) 1998,9 by Martin Schulze <joey@infodrom.north.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*/
/*
* Compile with: cc -o cgitest cgitest.c -lcgi
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <cgi.h>
#include "equilibrium.h"
#include "performance.h"
#include "thermo.h"
#include "load.h"
#include "print.h"
s_cgi *cgi;
#ifdef SOURCEFORGE
#define THERMO_PATH "thermo.dat"
#define PROPELLANT_PATH "propellant.dat"
#else
#define THERMO_PATH "/home/antoine/projets/rocket/rocketworkbench/cpropep/thermo.dat"
#define PROPELLANT_PATH "/home/antoine/projets/rocket/rocketworkbench/cpropep/propellant.dat"
#endif
void init_equil(void)
{
load_thermo (THERMO_PATH);
load_propellant (PROPELLANT_PATH);
}
void destroy(void)
{
free (propellant_list);
free (thermo_list);
}
int eval_cgi(equilibrium_t *e, double *exit_condition,
exit_condition_t *exit_type)
{
int mol = 0;
char buffer[64];
double tmp;
double tmp1;
printf ("<h1>Results</h1>\n\n");
strncpy(buffer, cgiGetValue(cgi, "temp"), 64);
if ( ((tmp = atof(buffer)) != 0) && tmp > 298.15 && tmp < 6000 )
e->properties.T = tmp;
else
return -1;
strncpy(buffer, cgiGetValue(cgi, "pressure"), 64);
if ((tmp = atof(buffer)) != 0)
e->properties.P = tmp;
else
return -1;
strncpy(buffer, cgiGetValue(cgi, "exit_cond_type"), 64);
if (!(strcmp(buffer, "Pressure")))
*exit_type = PRESSURE;
else if (!(strcmp(buffer, "Supersonic aera ratio")))
*exit_type = SUPERSONIC_AREA_RATIO;
else if (!(strcmp(buffer, "Subsonic aera ratio")))
*exit_type = SUBSONIC_AREA_RATIO;
else
return -1;
strncpy(buffer, cgiGetValue(cgi, "exit_cond"), 64);
if ((tmp = atof(buffer)) != 0)
*exit_condition = tmp;
else
return -1;
if (strncmp("mol", cgiGetValue(cgi, "select"), 3) == 0)
mol = 1;
strncpy(buffer, cgiGetValue(cgi, "qt1"), 32);
tmp = atof(buffer);
strncpy(buffer, cgiGetValue(cgi, "ml1"), 32);
tmp1 = atof(buffer);
if ((tmp != 0) && (tmp1 != 0))
{
if (mol)
add_in_propellant(e, tmp1, tmp);
else
add_in_propellant(e, tmp1, GRAM_TO_MOL(tmp, tmp1));
}
strncpy(buffer, cgiGetValue(cgi, "qt2"), 32);
tmp = atof(buffer);
strncpy(buffer, cgiGetValue(cgi, "ml2"), 32);
tmp1 = atof(buffer);
if ((tmp != 0) && (tmp1 != 0))
{
if (mol)
add_in_propellant(e, tmp1, tmp);
else
add_in_propellant(e, tmp1, GRAM_TO_MOL(tmp, tmp1));
}
strncpy(buffer, cgiGetValue(cgi, "qt3"), 32);
tmp = atof(buffer);
strncpy(buffer, cgiGetValue(cgi, "ml3"), 32);
tmp1 = atof(buffer);
if ((tmp != 0) && (tmp1 != 0))
{
if (mol)
add_in_propellant(e, tmp1, tmp);
else
add_in_propellant(e, tmp1, GRAM_TO_MOL(tmp, tmp1));
}
compute_density(&(e->propellant));
return 0;
}
int main (int argc, char **argv, char **env)
{
short i;
char *path_info = NULL;
equilibrium_t *equil, *frozen, *shifting;
char buffer[32];
double value;
double exit_cond;
exit_condition_t exit_cond_type;
int val;
problem_t P = TP;
errorfile = stderr;
outputfile = stdout;
cgiDebug(0, 0);
cgi = cgiInit();
init_equil();
global_verbose = 0;
path_info = getenv("PATH_INFO");
if (path_info)
{
if (!strcmp(path_info, "/list"))
{
cgiHeader();
printf("<pre>");
print_propellant_list();
printf("</pre>");
}
else if (!strcmp(path_info, "/list_thermo"))
{
cgiHeader();
printf("<pre>");
print_thermo_list();
printf("</pre>");
}
else if (!strcmp(path_info, "/search_thermo"))
{
cgiHeader();
printf("<pre>");
thermo_search( cgiGetValue(cgi, "formula"));
printf("</pre>");
}
else if (!strcmp(path_info, "/search_prop"))
{
cgiHeader();
printf("<pre>");
propellant_search( cgiGetValue(cgi, "name"));
//thermo_search( cgiGetValue(cgi, "formula"));
printf("</pre>");
}
else if (!strcmp(path_info, "/equil"))
{
cgiHeader();
equil = (equilibrium_t *) malloc (sizeof (equilibrium_t));
initialize_equilibrium(equil);
frozen = (equilibrium_t *) malloc (sizeof(equilibrium_t)*3);
shifting = (equilibrium_t *) malloc (sizeof(equilibrium_t)*3);
for (i = 0; i < 3; i++)
{
initialize_equilibrium(frozen + i);
initialize_equilibrium(shifting + i);
}
if (eval_cgi(equil, &exit_cond, &exit_cond_type))
printf("<b>Error</b>");
else
{
list_element(equil);
list_product(equil);
printf("<pre>");
if (strncmp("Find", cgiGetValue(cgi, "type"), 4) == 0)
{
print_propellant_composition(equil);
P = HP;
equilibrium(equil, P);
print_product_properties(equil, 1);
print_product_composition(equil, 1);
}
else if (strncmp("Froz", cgiGetValue(cgi, "type"), 4) == 0)
{
copy_equilibrium(frozen, equil);
print_propellant_composition(frozen);
equilibrium(frozen, HP);
frozen_performance(frozen, exit_cond_type, exit_cond);
print_product_properties(frozen, 3);
print_performance_information(frozen, 3);
print_product_composition(frozen, 3);
}
else if (strncmp("Shifting", cgiGetValue(cgi, "type"), 8) == 0)
{
copy_equilibrium(shifting, equil);
print_propellant_composition(shifting);
equilibrium(shifting, HP);
shifting_performance(shifting, exit_cond_type, exit_cond);
print_product_properties(shifting, 3);
print_performance_information(shifting, 3);
print_product_composition(shifting, 3);
}
else
{
print_propellant_composition(equil);
equilibrium(equil, P);
print_product_properties(equil, 1);
print_product_composition(equil, 1);
}
printf("</pre>");
}
free (equil);
free (frozen);
free (shifting);
}
else if (!strcmp(path_info, "/prop"))
{
cgiHeader();
printf("<pre>");
strncpy(buffer, cgiGetValue(cgi, "propellant"), 32);
if ( print_propellant_info (atoi (buffer)))
printf("Request out of range\n");
printf("</pre>");
}
else if (!strcmp(path_info, "/prod"))
{
cgiHeader();
printf("<pre>");
strncpy(buffer, cgiGetValue(cgi, "product"), 32);
val = atoi (buffer);
if ( print_thermo_info (val))
printf("Request out of range\n");
else
{
strncpy(buffer, cgiGetValue(cgi, "temp"), 32);
value = atof(buffer);
printf("Thermodynamics properties at temperature %.2f K\n", value);
printf("Enthalpy: % f J/mol\n", enthalpy_0(val, value)*R*value);
printf("Entropy: % f J/(mol K)\n", entropy_0(val, value)*R);
printf("Specific heat: % f J/(mol K)\n",
specific_heat_0(val, value)*R);
}
printf("</pre>");
}
else
{
cgiHeader();
printf("<br>Bad queries<br>");
}
}
else
{
cgiHeader();
printf("<br>Bad PATH_INFO<br>");
}
printf ("\n<hr>\n</body>\n</html>\n");
destroy();
return 0;
}

+ 17
- 0
cpropep/Makefile View File

@ -0,0 +1,17 @@
CC = gcc
COPT = -g -Wall -O3 #-pg -O6\
# -mpentium -ffast-math -funroll-loops -fnonnull-objects\
# -fno-exceptions -fforce-mem -fforce-addr -fcse-follow-jumps\
# -fexpensive-optimizations -march=pentium -fno-rtti #-fomit-frame-pointer
DEF = -DGCC #-DTRUE_ARRAY
all:
make -C src all
clean:
make -C src clean
deep-clean: clean
make -C src deep-clean

+ 135
- 0
cpropep/doc/thermo.html View File

@ -0,0 +1,135 @@
<plaintext>
The NASA thermo data file format was documented in:
Sanford Gordon and Bonnie J. McBride, "Computer Program for Calculation of
Complex Chemical Equilibrium Compositions and Applications: I. Analysis",
NASA Reference Publication 1311, October 1994.
Bonnie J. McBride and Sanford Gordon, "Computer Program for Calculation of
Complex Chemical Equilibrium Compositions and Applications: II. Users Manual
and Program Description", NASA Reference Publication 1311, June 1996.
The equations below for nondimensional specific heat, enthalpy, and
entropy, are given in Sanford and Bonnie (1994). Eqs. 4.6-4.8 are the
"old" NASA format, and Eqs. 4.9-4.11 are the "new" NASA format as discussed
in this file.
Eq. 4.6: Cp0/R = a1 + a2*T + a3*T^2 + a4*T^3 + a5*T^4
Eq. 4.7: H0/RT = a1 + a2/2*T + a3/3*T^2 + a4/4*T^3 + a5/5*T^4 + a6/T
Eq. 4.8: S0/R = a1*ln(T) + a2*T + a3/2*T^2 + a4/3*T^3 + a5/4*T^4 + a7
Eq. 4.9: Cp0/R = a1*T^-2 + a2*T^-1 + a3 + a4*T + a5*T^2 + a6*T^3 + a7*T^4
Eq. 4.10: H0/RT = -a1*T^-2 + a2*T^-1*ln(T) + a3 + a4*T/2 + a5*T^2/3 +
a6*T^3/4 + a7*T^4/5 + b1/T
Eq. 4.11: S0/R = -a1*T^-2/2 - a2*T^-1 + a3*ln(T) + a4*T + a5*T^2/2 +
a6*T^3/6 + a7*T^4/4 + b2
The following information is quoted directly from McBride and Gordon (1996):
"Appendix A: Format for Thermodynamic Data
The library of thermodynamic data contains data for both reaction products
and reactants. All reaction products and some reactants are in the
nine-constant functional form discussed in section 4.2 of Gordon and
McBride (1994). The format for these data is given here. Thermodynamic
data are provided with the program on a separate file, thermo.inp.
Sections 2.8 and 5.24 discuss the processing of the thermo.inp data and
the storing of the processed data in thermo.lib for subsequent use in the
CEA program. Names of species contained in thermo.inp are listed in
Appendix B.
The general format is given in table A1. This format is applicable for
all gaseous species and for those condensed species whose data extend over
a temperature range. For those condensed species with data given at only
one temperature, the format is somewhat different. On record 2, instead
of the last number being a heat of formation, it is an assigned enthalpy.
(Note that if the temperature is 298.15 K, the heat of formation and the
assigned enthalpy are equivalent.) The first number in record 2 (number
of temperature intervals) is always zero. On record 3, only one number is
given, the temperature of the assigned enthalpy on record 2. Two examples are
given. Example A1, for chlorine gas, illustrates the general format.
Example A2, for liquid acetylene, illustrates the format for a condensed
species with data given at only one temperature. The general equations
for dimensionless heat capacity, enthalpy, and entropy (eqs. (4.6) to (4.8)
<sic> from Gordon and McBride, 1994) are repeated for convenience.
Record Constants Format Column
1 Species name or formula A24 1 to 24
Comments (data source) A56 25-80
2 Number of T intervals I2 2
Optional identification code A6 4-9
Chemical formulas, symbols, and numbers 5(A2,F6.2) 11-50
Zero for gas and nonzero for condensed phases I1 52
Molecular weight F13.5 53-65
Heat of formation at 298.15 K, J/mol F13.5 66-80
3 Temperature range 2F10.3 2-21
Number of coefficients for Cp0/R I1 23
T exponents in empirical equation for Cp0/R 8F5.1 24-63
{H0(298.15)-H0(0)}, J/mol F15.3 66-80
4 First five coefficients for Cp0/R 5D16.8 1-80
5 Last three coefficients for Cp0/R 3D16.8 1-48
Integration constants b1 and b2 2D16.8 49-80
... Repeat 3, 4, and 5 for each interval
Example A.1:
CL2 Chlorine gas. TPIS 1989, v1, pt2, p88.
2 tpis89 CL 2.00 0.00 0.00 0.00 0.00 0 70.90540 0.000
200.000 1000.000 7 -2.0 -1.0 0.0 1.0 2.0 3.0 4.0 0.0 9181.110
3.46281724D+04 -5.54712949D+02 6.20759103D+00 -2.98963673D-03 3.17303416D-06
-1.79363467D-09 4.26005863D-13 0.00000000D+00 1.53407075D+03 -9.43835303D+00
1000.000 6000.000 7 -2.0 -1.0 0.0 1.0 2.0 3.0 4.0 0.0 9181.110
6.09256675D+06 -1.94962688D+04 2.85453491D+01 -1.44996828D-02 4.46388943D-06
-6.35852403D-10 3.32735931D-14 0.00000000D+00 1.21211722D+05 -1.69077832D+02
Empirical equations for example A.1:
Heat capacity: Cp0/R = a1*T^-2 + a2*T^-1 + a3 + a4*T + a5*T^2 + a6*T^3 + a7*T^4
Enthalpy: H0(T)/(RT) = -a1*T^-2 + a2*T^-1*ln(T) + a3 + a4*T/2 + a5*T^2/3 +
a6*T^3/4 + a7*T^4/5 + b1/T
Entropy: S0(T)/R = -a1*T^-2/2 - a2*T^-1 + a3*ln(T) + a4*T + a5*T^2/2 +
at*T^3/3 + a7*T^4/4 + b2
Example A.2:
C2H2(L),acetyle Acetylene. JANAF Prop.Ser.E,1/67. TRC a-3000,10/86.
0 1 3/95 C 2.00H 2.00 0.00 0.00 0.00 1 26.03788 207599.000
192.35"
Notes:
1. Besides a very different file layout, the most significant change between
the older (1971) NASA thermo data and the 1996 data is the generalization
to any number of temperature intervals.
2. The preceding discussion only mentions the format of individual species
data blocks. In addition, the thermo input file included with the NASA
CEA program contains:
a. Comments at the top of the file marked by exclamation (!) points in the
first column
b. Two lines at the beginning of the species data:
i. One line containing only "thermo"
ii. One line with 4 temperatures and a date
c. A line containing only "END PRODUCTS" separating product species from
reactants, and a line at the end of the file containing only
"END REACTANTS".
3. There are some differences between the format actually used by CEA and
the format described in McBride and Gordon (1996), and some undocumented
features:
a. In the CEA code, the actual read and format statements differ from the
documentation by:
i. The species name on the first line of a block is 15 characters long,
not 24. The rest of the line is comments.
ii. The heat of formation at the end of line 2 is read with f15.3, not f13.5
iii. The temperature range at the beginning of line 3 is read as 2F11.3,
not 2F10.3.
iv. Line 5 is formatted as 2D16.8,16x,2D16.8 rather than
3D16.8,2D16.8. The 16x acknowledges that the third field is
not actually used. The first two fields are the 6th and 7th
polynomial coefficients, and the last two fields are the 8th and
9th (integration constants).
b. Although the number of polynomial coefficients is included in the data,
this number is almost always 7 (plus 2 integration constants). In the
current NASA database, there are only 3 species that use less than
7 coefficients (P4O10(cr), P4O10(cr), and P4O10(L)). Apparently if
less than 7 are used, they are the lowest numbered (a1, a2, a3, ...).
4. In the preceding excerpt from McBride and Gordon (1996), reference is
made to eqs. (4.6) to (4.8). These should be eqs. (4.9) to (4.11).

+ 31
- 0
cpropep/src/Makefile View File

@ -0,0 +1,31 @@
CC = gcc
COPT = -g -Wall -O3 #-pg
LIB = -lcpropep -lthermo -lnum -lm
ROOT = ../..
LIBDIR = -L$(ROOT)/libnum/lib \
-L$(ROOT)/libthermo/lib \
-L$(ROOT)/libcpropep/lib
INCDIR = -I$(ROOT)/libnum/include/ \
-I$(ROOT)/libthermo/include/ \
-I$(ROOT)/libcpropep/include/ \
-I$(ROOT)/libcompat/include/
DEF = -DGCC -DCONF_FILE=\"/etc/rocketworkbench/cpropep.conf\"
PROG = cpropep
OBJS = cpropep.o
all: $(PROG)
.c.o:
$(CC) $(DEF) $(INCDIR) $(COPT) -c $*.c -o $*.o
$(PROG): $(OBJS)
$(CC) $(COPT) $(OBJS) $(LIBDIR) $(LIB) -o $@
clean:
rm -f *.o *~
deep-clean: clean
rm -f $(PROG)

+ 36
- 0
cpropep/src/Makefile.win View File

@ -0,0 +1,36 @@
CC = bcc32
CPP32 = cpp32
LIBRARIAN = tlib
LINKER = ilink32
RC = brc32
COPT = -3 -O2 -w-8012 -w-8004 -w-8057 -IC:\borland\bcc55\include
LDOPT = -LC:\borland\bcc55\lib
IDIR = -I..\..\libnum\ -I..\lib\ -I.
LIB = compat.lib libnum.lib thermo.lib cpropep.lib
LIBDIR = -L..\..\libnum\ -L..\lib\
DEF = -DBORLAND
PROG = cpropep.exe
OBJS = cpropep.obj getopt.obj
.SUFFIXES: .c
all: $(PROG)
.c.obj:
$(CC) $(COPT) $(IDIR) $(DEF) -c $*.c -o $*.obj
$(PROG): $(OBJS)
$(CC) $(LDOPT) $(LIBDIR) $(LIB) $(OBJS)
clean:
del *.obj
del *.bak
del *.tds
deep-clean: clean
del $(PROG)

+ 31
- 0
cpropep/src/README.txt View File

@ -0,0 +1,31 @@
This is cpropep version 1.0, a program for determining the
theoretical performance of rocket propellant compositions.
Cpropep is released under the GPL and is written in ANSI C.
It has compiled successfully under the following platforms:
. i686 Windows 98 (4.10.1998) running Microsoft Visual
C++ 6.0 Standard Edition with Microsoft Visual Studio
Service Pack 2
. i686 Red Hat Linux 6.2 (Kernel 2.2.14-12) with gcc
. i586 Debian GNU/Linux 2.2 (Kernel 2.2.16) with gcc
To compile under linux, type make in the top-level directory.
Under MSVC++, create a new Win32 console project file, add
all source and header files to the project, set the header
file directory to ..\lib\ (or copy all files from \lib to
\cpropep or change the #include statements in cpropep.c) and
build.
Run using
cpropep -h
for command-line help and usage.
Cpropep is Copyright (C) 2000 Antoine Lefebvre
<antoinelefebvre@softhome.net>

+ 764
- 0
cpropep/src/cpropep.c View File

@ -0,0 +1,764 @@
/* cpropep.c - Calculation of Complex Chemical Equilibrium */
/* $Id: cpropep.c,v 1.3 2001/07/09 13:51:39 antoine Exp $ */
/* Copyright (C) 2000 */
/* Antoine Lefebvre <antoine.lefebvre@polymtl.ca> */
/* Mark Pinese <pinese@cyberwizards.com.au> */
/* */
/* Licensed under the GPLv2 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <malloc.h>
//#include <time.h>
#ifdef GCC
#include <unistd.h>
#else
#include "getopt.h"
#endif
#include "load.h"
#include "equilibrium.h"
#include "performance.h"
#include "derivative.h"
#include "thermo.h"
#include "print.h"
#include "conversion.h"
#include "compat.h"
#include "return.h"
#define version "1.0"
#define date "10/07/2000"
//#define CHAMBER_MSG "Time spent for computing chamber equilibrium"
//#define FROZEN_MSG "Time spent for computing frozen performance"
//#define EQUILIBRIUM_MSG "Time spent for computing equilibrium performance"
#ifndef CONF_FILE
#define CONF_FILE "cpropep.conf"
#endif
//#undef TIME
//#define TIME(function, msg) function;
#define MAX_CASE 10
typedef enum _p
{
SIMPLE_EQUILIBRIUM,
FIND_FLAME_TEMPERATURE,
FROZEN_PERFORMANCE,
EQUILIBRIUM_PERFORMANCE
} p_type;
char case_name[][80] = {
"Fixed pressure-temperature equilibrium",
"Fixed enthalpy-pressure equilibrium - adiabatic flame temperature",
"Frozen equilibrium performance evaluation",
"Shifting equilibrium performance evaluation"
};
char thermo_file[FILENAME_MAX] = "thermo.dat";
char propellant_file[FILENAME_MAX] = "propellant.dat";
typedef struct _case_t
{
p_type p;
bool temperature_set;
bool pressure_set;
bool exit_condition_set;
double temperature;
double pressure;
exit_condition_t exit_cond_type;
double exit_condition;
} case_t;
void welcome_message(void)
{
printf("----------------------------------------------------------\n");
printf("Cpropep is an implementation in standard C of the chemical\n");
printf("equilibrium algorythm presented by GORDON and McBRIDE in the\n");
printf("NASA report RP-1311.\n");
printf("This is the version %s %s\n", version, date);
printf("This software is release under the GPL and is free of charge\n");
printf("Copyright (C) 2000 Antoine Lefebvre <antoine.lefebvre@polymtl.ca>\n");
printf("----------------------------------------------------------\n");
}
void info(char **argv)
{
printf("Try `%s -h' for more information\n", argv[0]);
}
void usage(void)
{
/*
Usage:
cpropep -f infile [-voe]
cpropep -pqtuh
Arguments:
*/
printf("Usage:");
printf("\n\tcpropep -f infile [-voe]");
printf("\n\tcpropep -pqtuh");
printf("\n\nArguments:\n");
printf("-f file \t Perform an analysis of the propellant data in file\n");
printf("-v num \t Verbosity setting, 0 - 10\n");
printf("-o file \t Results file, stdout if omitted\n");
printf("-e file \t Error file, stdout if omitted\n");
printf("-p \t Print the propellant list\n");
printf("-q num \t Print information about propellant component number num\n");
printf("-t \t Print the combustion product list\n");
printf("-u num \t Print information about product number num\n");
printf("-h \t Print help\n");
printf("-i \t Print program information\n");
}
int load_input(FILE *fd, equilibrium_t *e, case_t *t, double *pe)
{
double m;
int sp;
int section = 0;
int n_case = 0;
char buffer[128], num[10], qt[10], unit[10];
char variable[64];
char *bufptr;
while ( fgets(buffer, 128, fd) != NULL )
{
switch (section)
{
case 0:
if (n_case >= MAX_CASE)
{
fprintf(outputfile, "Warning: Too many different case, "
"maximum is %d: deleting case.\n", MAX_CASE+1);
section = 100;
break;
}
if (buffer[0] == ' ' || buffer[0] == '\n' || buffer[0] == '\0' ||
buffer[0] == '#')
{
section = 0;
break;
}
else if (strncmp(buffer, "Propellant", 10) == 0)
{
section = 1;
}
else
{
if (strncmp(buffer, "TP", 2) == 0)
t[n_case].p = SIMPLE_EQUILIBRIUM;
else if (strncmp(buffer, "HP", 2) == 0)
t[n_case].p = FIND_FLAME_TEMPERATURE;
else if (strncmp(buffer, "FR", 2) == 0)
t[n_case].p = FROZEN_PERFORMANCE;
else if (strncmp(buffer, "EQ", 2) == 0)
t[n_case].p = EQUILIBRIUM_PERFORMANCE;
else
{
printf ("Unknown option.\n");
break;
}
section = 2;
}
break;
case 1: /* propellant section */
if (buffer[0] == '+')
{
sscanf(buffer, "%s %s %s", num, qt, unit);
bufptr = num + 1;
sp = atoi(bufptr);
m = atof(qt);
if (strcmp(unit, "g") == 0)
{
add_in_propellant(e, sp, GRAM_TO_MOL(m, sp) );
}
else if (strcmp(unit, "m") == 0)
{
add_in_propellant(e, sp, m);
}
else
{
printf("Unit must be g (gram) or m (mol)\n");
break;
}
break;
}
else if (buffer[0] == '#')
{
break;
}
else if (buffer[0] == ' ' || buffer[0] == '\n' || buffer[0] == '\0')
{
section = 0;
}
break;
case 2:
if (buffer[0] == '+')
{
sscanf(buffer, "%s %s %s", variable, qt, unit);
bufptr = variable + 1;
if (strcmp(bufptr, "chamber_temperature") == 0)
{
m = atof(qt);
if (strcmp(unit, "k") == 0)
{
t[n_case].temperature = m;
}
else if (strcmp(unit, "c") == 0)
{
t[n_case].temperature = m + 273.15;
}
else if (strcmp(unit, "f") == 0)
{
t[n_case].temperature = (5.0/9.0) * (m - 32.0) + 273.15;
}
else
{
printf("Unit must be k (kelvin) or c (celcius)\n");
break;
}
t[n_case].temperature_set = true;
}
else if (strcmp(bufptr, "chamber_pressure") == 0)
{
m = atof(qt);
if (strcmp(unit, "atm") == 0)
{
t[n_case].pressure = m;
}
else if (strcmp(unit, "kPa") == 0)
{
t[n_case].pressure = KPA_TO_ATM * m;
}
else if (strcmp(unit, "psi") == 0)
{
t[n_case].pressure = PSI_TO_ATM * m;
}
else if (strcmp(unit, "bar") == 0)
{
t[n_case].pressure = BAR_TO_ATM * m;
}
else
{
fprintf(errorfile, "Units must be psi, kPa, atm or bar.\n");
break;
}
t[n_case].pressure_set = true;
}
else if (strcmp(bufptr, "exit_pressure") == 0)
{
m = atof(qt);
if (strcmp(unit, "atm") == 0)
{
t[n_case].exit_condition = m;
}
else if (strcmp(unit, "kPa") == 0)
{
t[n_case].exit_condition = KPA_TO_ATM * m;
}
else if (strcmp(unit, "psi") == 0)
{
t[n_case].exit_condition = PSI_TO_ATM * m;
}
else if (strcmp(unit, "bar") == 0)
{
t[n_case].exit_condition = BAR_TO_ATM * m;
}
else
{
fprintf(errorfile, "Units must be psi, kPa, atm or bar.\n");
break;
}
t[n_case].exit_cond_type = PRESSURE;
t[n_case].exit_condition_set = true;
}
else if (strcmp(bufptr, "supersonic_area_ratio") == 0)
{
t[n_case].exit_cond_type = SUPERSONIC_AREA_RATIO;
t[n_case].exit_condition = atof(qt);
t[n_case].exit_condition_set = true;
}
else if (strcmp(bufptr, "subsonic_area_ratio") == 0)
{
t[n_case].exit_cond_type = SUBSONIC_AREA_RATIO;
t[n_case].exit_condition = atof(qt);
t[n_case].exit_condition_set = true;
}
else
{
printf("Unknown keyword.\n");
break;
}
break;
}
else if (buffer[0] == '#')
{
break;
}
else if (buffer[0] == ' ' || buffer[0] == '\n' || buffer[0] == '\0')
{
section = 0;
n_case++;
}
break;
default:
section = 0;
break;
}
}
return 0;
}
int main(int argc, char *argv[])
{
int i, c, v = 0;
int err_code;
char filename[FILENAME_MAX];
FILE *fd = NULL;
FILE *conf = NULL;
equilibrium_t *equil, *frozen, *shifting;
int thermo_loaded = 0;
int propellant_loaded = 0;
double exit_pressure;
// clock_t timer;
char variable[64];
char path[FILENAME_MAX];
char buffer[512];
case_t case_list[MAX_CASE];
for (i = 0; i < MAX_CASE; i++)
{
case_list[i].p = -1;
case_list[i].temperature_set = false;
case_list[i].pressure_set = false;
case_list[i].exit_condition_set = false;
}
errorfile = stderr;
outputfile = stdout;
/* global_verbose = 1; */
if (argc == 1)
{
usage ();
exit (ERROR);
}
/* read the configuration file if there is one*/
if ((conf = fopen(CONF_FILE, "r")) != NULL)
{
while (fgets(buffer, 512, conf))
{
sscanf(buffer, "%s %s", variable, path);
if (strcmp(variable, "thermo") == 0)
{
strncpy(thermo_file, path, FILENAME_MAX);
}
else if (strcmp(variable, "propellant") == 0)
{
strncpy(propellant_file, path, FILENAME_MAX);
}
}
}
while (1)
{
c = getopt(argc, argv, "ipht?f:v:o:e:q:u:");
if (c == EOF)
break;
switch (c)
{
/* the output file */
case 'o':
if (strlen(optarg) > FILENAME_MAX)
{
printf("Filename too long!\n");
break;
}
strncpy (filename, optarg, FILENAME_MAX);
if ( (outputfile = fopen (filename, "w")) == NULL )
return 1;
break;
/* the output error file */
case 'e':
if (strlen(optarg) > FILENAME_MAX)
{
printf("Filename too long!\n");
break;
}
strncpy (filename, optarg, FILENAME_MAX);
if ( (errorfile = fopen (filename, "w")) == NULL )
return (ERROR);
break;
/* print the propellant list */
case 'p':
if (!propellant_loaded)
{
if (load_propellant (propellant_file) < 0)
{
printf("Error loading propellant file: %s\n", propellant_file);
return -1;
}
propellant_loaded = 1;
}
print_propellant_list();
free(propellant_list);
return (SUCCESS);
/* print propellant info */
case 'q':
if (!propellant_loaded)
{
if (load_propellant (propellant_file) < 0)
{
printf("Error loading propellant file: %s\n", propellant_file);
return -1;
}
propellant_loaded = 1;
}
print_propellant_info( atoi(optarg) );
free(propellant_list);
return (SUCCESS);
/* print the usage */
case 'h':
usage();
return (SUCCESS);
/* the input file */
case 'f':
if (strlen(optarg) > FILENAME_MAX)
{
printf("Filename too long!\n");
break;
}
strncpy (filename, optarg, FILENAME_MAX);
if ( (fd = fopen (filename, "r")) == NULL )
return (ERROR);
break;
/* print the thermo list */
case 't':
if (!thermo_loaded)
{
if (load_thermo (thermo_file) < 0)
{
printf("Error loading thermo data file: %s\n", thermo_file);
return -1;
}
thermo_loaded = 1;
}
print_thermo_list();
free(thermo_list);
return (SUCCESS);
case 'u':
if (!thermo_loaded)
{
if (load_thermo (thermo_file) < 0)
{
printf("Error loading thermo data file: %s\n", thermo_file);
return -1;
}
thermo_loaded = 1;
}
print_thermo_info( atoi(optarg) );
free(thermo_list);
return (SUCCESS);
/* set the verbosity level */
case 'v':
v = atoi(optarg);
if (v < 0 || v > 10)
{
printf("Verbose is an integer betwenn 0 and 10.\n");
v = 0;
}
break;
/* print information */
case 'i':
welcome_message();
return (SUCCESS);
case '?':
info(argv);
return (SUCCESS);
}
}
if (!thermo_loaded)
{
if (load_thermo (thermo_file) < 0)
{
printf("Error loading thermo data file: %s\n", thermo_file);
return -1;
}
thermo_loaded = 1;
}
if (!propellant_loaded)
{
if (load_propellant (propellant_file) < 0)
{
printf("Error loading propellant file: %s\n", propellant_file);
return -1;
}
propellant_loaded = 1;
}
if (fd != NULL)
{
equil = (equilibrium_t *) malloc (sizeof (equilibrium_t));
initialize_equilibrium(equil);
frozen = (equilibrium_t *) malloc (sizeof(equilibrium_t)*3);
shifting = (equilibrium_t *) malloc (sizeof(equilibrium_t)*3);
for (i = 0; i < 3; i++)
{
initialize_equilibrium(frozen + i);
initialize_equilibrium(shifting + i);
}
load_input(fd, equil, case_list, &exit_pressure);
compute_density(&(equil->propellant));
fclose(fd);
global_verbose = v;
list_element(equil);
if ((err_code = list_product(equil)) < 0)
{
print_error_message(err_code);
return err_code;
}
i = 0;
while ((case_list[i].p != -1) && (i <= MAX_CASE))
{
fprintf(outputfile, "Computing case %d\n%s\n\n", i+1,
case_name[case_list[i].p]);
/* be sure to begin iteration without considering
condensed species. Once n_condensed have been set */
equil->product.n[CONDENSED] = 0;
switch (case_list[i].p)
{
case SIMPLE_EQUILIBRIUM:
if (!(case_list[i].temperature_set))
{
printf("Chamber temperature not set. Aborted.\n");
break;
}
else if (!(case_list[i].pressure_set))
{
printf("Chamber pressure not set. Aborted.\n");
break;
}
equil->properties.T = case_list[i].temperature;
equil->properties.P = case_list[i].pressure;
print_propellant_composition(equil);
if ((err_code = equilibrium(equil, TP)) < 0)
{
print_error_message(err_code);
return err_code;
}
print_product_properties(equil, 1);
print_product_composition(equil, 1);
break;
case FIND_FLAME_TEMPERATURE:
if (!(case_list[i].pressure_set))
{
printf("Chamber pressure not set. Aborted.\n");
break;
}
equil->properties.P = case_list[i].pressure;
print_propellant_composition(equil);
if ((err_code = equilibrium(equil, HP)) < 0)
{
print_error_message(err_code);
return err_code;
}
print_product_properties(equil, 1);
print_product_composition(equil, 1);
break;
case FROZEN_PERFORMANCE:
if (!(case_list[i].pressure_set))
{
printf("Chamber pressure not set. Aborted.\n");
break;
}
else if (!(case_list[i].exit_condition_set))
{
printf("Exit condition not set. Aborted.\n");
break;
}
equil->properties.T = case_list[i].temperature;
equil->properties.P = case_list[i].pressure;
copy_equilibrium(frozen, equil);
print_propellant_composition(frozen);
if ((err_code = equilibrium(equil, HP)) < 0)
{
print_error_message(err_code);
return err_code;
}
if ((err_code =
frozen_performance(frozen, case_list[i].exit_cond_type,
case_list[i].exit_condition)) < 0)
{
print_error_message(err_code);
return err_code;
}
print_product_properties(frozen, 3);
print_performance_information(frozen, 3);
print_product_composition(frozen, 3);
break;
case EQUILIBRIUM_PERFORMANCE:
if (!(case_list[i].pressure_set))
{
printf("Chamber pressure not set. Aborted.\n");
break;
}
else if (!(case_list[i].exit_condition_set))
{
printf("Exit condition not set. Aborted.\n");
break;
}
equil->properties.T = case_list[i].temperature;
equil->properties.P = case_list[i].pressure;
copy_equilibrium(shifting, equil);
print_propellant_composition(shifting);
if ((err_code = equilibrium(shifting, HP)) < 0)
{
print_error_message(err_code);
return err_code;
}
if ((err_code = shifting_performance(shifting,
case_list[i].exit_cond_type,
case_list[i].exit_condition))
< 0)
{
print_error_message(err_code);
return err_code;
}
print_product_properties(shifting, 3);
print_performance_information(shifting, 3);
print_product_composition(shifting, 3);
break;
}
i++;
}
free (equil);
free (frozen);
free (shifting);
}
free (propellant_list);
free (thermo_list);
if (errorfile != stderr)
fclose (errorfile);
if (outputfile != stdout)
fclose (outputfile);
return 0;
}

+ 2
- 0
cpropep/src/cpropep.conf View File

@ -0,0 +1,2 @@
thermo /usr/share/rocketworkbench/cpropep/thermo.dat
propellant /usr/share/rocketworkbench/cpropep/propellant.dat

+ 102
- 0
cpropep/src/input.pro View File

@ -0,0 +1,102 @@
# Cpropep is based on the theory presented by Gordon and McBride
# in the NASA report RP-1311. You can download a pdf version of
# this document at http://www.arocket.net/library/
# The thermodynamics data file thermo.dat coma also from McBride
# at the NASA Gleen Research center.
# Here is an example of an input file to be use by cpropep.
# Any line beginning by a '#' a space or a new_line is considered
# as a comment.
# This file should first contain a section named 'Propellant' which
# contain a list of all substance contain in the propellant. The
# number refer to an element in the data file containing propellant
# information. In order to have a list of the substance, you could
# invoque the program like that: 'cpropep -p'
# There is two units that are support for ingredient quantity g (gram) or m (mole)
#Propellant HTPB/KClO4/Al
#+108 78 g
#+788 11 g
#+34 7 g
#+788 8.4 g
#+108 62 g
#+493 18 g
#Propellant DEXTROSE/KNO3
#+1024 35 g
#+765 65 g
#Propellant DEXTROSE/KNO3/AL
#+1024 10 g
#+765 37 g
#+34 20 g
#Propellant PVC/AIR
#+1030 60 g
#+15 300 g
#Propellant H2O2/OCTANE
#+673 12 g
#+469 80 g
#Propellant O2/OCTANE
#+686 51 g
#+673 20 g
Propellant O2/PROPANE
+686 51 g
+771 20 g
#Propellant O2/NH3
#+686 28 g
#+54 20 g
#Propellant NITRIC ACID/OCTANE
#+630 80 g
#+673 19 g
# You could then specify a list of problem to be solve. There is 4
# possible cases:
# TP for temperature-pressure fixed problem
# You have to specify the temperature and the pressure (of course)
# There is 4 pressure units (psi, kPa, atm and bar) and 3 temperature units (k, c and f)
#TP
#+chamber_pressure 500 psi
#+chamber_temperature 673 k
# HP for enthalpy-pressure fixed problem. It use the enthalpy of
# the propellant describe at the beginning.
# Only the chamber pressure shoud be specified. The temperature of
# the product will be the adiabatic flame temperature.
#HP
#+chamber_pressure 20.4 atm # 136 atm
# FR is used to compute frozen performance.
# You have to specify the chamber pressure and an exit condition.
# This condition could be one of the following three:
# exit_pressure: pressure at the exit.
# supersonic_area_ratio: exit to throat area for an area after the nozzle
# subsonic_area_ratio: exit to throat area for an area before any nozzle
FR
+chamber_pressure 40 atm
+exit_pressure 1 atm
#+supersonic_area_ratio 8.566
#+subsonic_area_ratio 5
# EQ is used to compute shifting equilibrium performance.
# The options are the same as for frozen.
EQ
+chamber_pressure 40 atm
+exit_pressure 1 atm
#+supersonic_area_ratio 10
#+subsonic_area_ratio 5

+ 1098
- 0
data/propellant.dat
File diff suppressed because it is too large
View File


+ 24
- 0
data/references.txt View File

@ -0,0 +1,24 @@
The data contain in thermo.dat come from the NASA Gleen research center
and was provide by Bonnie McBride.
The file propellant.dat come from the package of propep.
The following entrie have been add to propellant.dat by R.Nakka.
--------------------------------------------------------
PEPCODED.DAF file revision 1.0 by R.Nakka 7 Nov. 1999
The following entries have been added to the pepcoded.daf file:
1093 DEXTROSE (GLUCOSE) 6C 12H 6O 0 0 0 -1689 .0567]
1094 SORBITOL 6C 14H 6O 0 0 0 -1776 .0531]
1095 BITUMEN (ASPHALT) 84C 11H 3O 1N 1S 0 -351 .0400]
1096 CHARCOAL (OAK) 71C 3H 13O 1N 0 0 -396 .0206]
1097 CHARCOAL (MAPLE) 79C 3H 14O 0 0 0 -222 .0206]
1098 EICOSANE (PARAFFIN) 20C 42H 0 0 0 0 -469 .0000]
References:
1093,1094,1098: NIST WebBook http://webbook.nist.gov/chemistry
1095-1097: Journal of Pyrotechnics, Issue No.9 (1999)

+ 14517
- 0
data/thermo.dat
File diff suppressed because it is too large
View File


+ 37
- 0
libcompat/Makefile View File

@ -0,0 +1,37 @@
CC = gcc
COPT = -g -Wall -O3 -pg #-O6\
# -mpentium -ffast-math -funroll-loops -fnonnull-objects\
# -fno-exceptions -fforce-mem -fforce-addr -fcse-follow-jumps\
# -fexpensive-optimizations -march=pentium -fno-rtti #-fomit-frame-pointer
INCLUDEDIR = -I../../libnum/ -I.
DEF = -DGCC #-DTRUE_ARRAY
CPROPEP_LIBNAME = libcpropep.a
THERMO_LIBNAME = libthermo.a
THERMO_LIBOBJS = load.o thermo.o
CPROPEP_LIBOBJS = equilibrium.o print.o performance.o derivative.o
.SUFFIXES: .c
all: $(CPROPEP_LIBNAME) $(THERMO_LIBNAME)
.c.o:
$(CC) $(DEF) $(INCLUDEDIR) $(COPT) -c $*.c -o $*.o
$(CPROPEP_LIBNAME): $(CPROPEP_LIBOBJS)
ar -r $@ $(CPROPEP_LIBOBJS)
ranlib $@
$(THERMO_LIBNAME): $(THERMO_LIBOBJS)
ar -r $@ $(THERMO_LIBOBJS)
ranlib $@
clean:
rm -f *.o *~
deep-clean: clean
rm -f $(CPROPEP_LIBNAME) $(THERMO_LIBNAME)

+ 50
- 0
libcompat/Makefile.win View File

@ -0,0 +1,50 @@
CC = bcc32
CPP32 = cpp32
LIBRARIAN = tlib
LINKER = ilink32
RC = brc32
COPT = -3 -O2 -w-8004 -w-8012 -w-8057 -IC:\borland\bcc55\include
LDOPT = -LC:\borland\bcc55\lib
INCLUDEDIR = -I..\..\libnum\ -I.
DEF = -DBORLAND
COMPAT_LIBNAME = compat.lib
CPROPEP_LIBNAME = cpropep.lib
THERMO_LIBNAME = thermo.lib
COMPAT_LIBOBJS = compat.obj getopt.obj
THERMO_LIBOBJS = load.obj thermo.obj
CPROPEP_LIBOBJS = equilibrium.obj print.obj performance.obj derivative.obj
TLIBCOMPAT = +compat.obj +getopt.obj
TLIBTHERMO = +load.obj +thermo.obj
TLIBCPROPEP = +equilibrium.obj +print.obj +performance.obj +derivative.obj
.SUFFIXES: .c
all: $(CPROPEP_LIBNAME) $(THERMO_LIBNAME) $(COMPAT_LIBNAME)
.c.obj:
$(CC) $(DEF) $(INCLUDEDIR) $(COPT) -c $*.c -o $*.obj
$(COMPAT_LIBNAME): $(COMPAT_LIBOBJS)
tlib $@ $(TLIBCOMPAT)
$(CPROPEP_LIBNAME): $(CPROPEP_LIBOBJS)
tlib $@ $(TLIBCPROPEP)
$(THERMO_LIBNAME): $(THERMO_LIBOBJS)
tlib $@ $(TLIBTHERMO)
clean:
del *.obj
del *.bak
del *.tds
deep-clean: clean
del $(COMPAT_LIBNAME)
del $(CPROPEP_LIBNAME)
del $(THERMO_LIBNAME)

+ 68
- 0
libcompat/include/compat.h View File

@ -0,0 +1,68 @@
#ifndef COMPAT_H
#define COMPAT_H
/*
Checking for _MSC_VER will detect whether MSVC++ is being used.
I don't know of the other compiler flags, so others will want to
add to this for their own compilers.
Mark Pinese 24/4/2000
*/
#ifdef _MSC_VER
/* MSVC++ 6.0 Std */
#define STRNCASECMP _strnicmp
/* add for MSVC++ 5.0 */
#define STRCASECMP _stricmp
#ifdef _DEBUG
#include <crtdbg.h>
#endif /* defined (_DEBUG) */
#ifndef __cplusplus
typedef enum
{
false = 0,
true = 1
} bool;
#endif /* !defined (__cplusplus) */
#endif /* define _MSC_VER */
#ifdef GCC
#define STRCASECMP strcasecmp
#define STRNCASECMP strncasecmp
#define __min(a, b) ( (a) <= (b) ? (a) : (b))
#define __max(a, b) ( (a) >= (b) ? (a) : (b))
typedef enum
{
false = 0,
true = 1
} bool;
#endif /* define GCC */
#ifdef BORLAND
int StrNCaseCmp(const char *s1, const char *s2, size_t sz);
#define STRNCASECMP StrNCaseCmp
#define __min(a, b) ( (a) <= (b) ? (a) : (b))
#define __max(a, b) ( (a) >= (b) ? (a) : (b))
typedef enum
{
false = 0,
true = 1
} bool;
#endif /* define BORLAND */
#endif /* !defined(COMPAT_H) */

+ 10
- 0
libcompat/include/getopt.h View File

@ -0,0 +1,10 @@
/* getopt.h from Don Libes "Obfuscated C" (extended by PRW) */
#ifndef GETOPT_H
#define GETOPT_H
extern int getopt(int argc, char **argv, char *opts);
extern char *optarg; /* current argv string */
extern int optind; /* current argv index */
extern int optopt; /* option character */
extern int opterr; /* getopt prints errors if 1 */
#endif /* GETOPT_H */

+ 46
- 0
libcompat/src/compat.c View File

@ -0,0 +1,46 @@
#ifdef BORLAND
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
/* Compare two strings, ignoring case */
static int strcasecmp(const char *s1, const char *s2)
{
unsigned int i, len = strlen(s1)+1;
char c1, c2;
for (i = 0; i < len; ++i)
{
c1 = tolower(s1[i]);
c2 = tolower(s2[i]);
if (c1 != c2)
{
return ((c1 > c2) ? (1) : (-1));
}
}
return 0;
}
/* Compare two strings up to n characters, ignoring case */
static int strncasecmp(const char *s1, const char *s2, size_t sz)
{
unsigned int i, len = strlen(s1)+1;
char c1, c2;
if (sz < len) len = sz;
for (i = 0; i < len; ++i)
{
c1 = tolower(s1[i]);
c2 = tolower(s2[i]);
if (c1 != c2)
{
return ((c1 > c2) ? (1) : (-1));
}
}
return 0;
}
#endif

+ 83
- 0
libcompat/src/getopt.c View File

@ -0,0 +1,83 @@
/* file getopt.c */
/* Author: Peter Wilson */
/* Catholic University and NIST */
/* pwilson@cme.nist.gov */
/* */
/* getopt() from Don Libes "Obfuscated C" */
#include <stdio.h>
#include <string.h>
/* getopt() -- parse command line arguments */
/* Original Author: AT&T */
/* This version from Don Libes "Obfuscated C and Other Mysteries" */
/* John Wiley & Sons, 1993. Chapter 6 */
#define ERR(s, c) if (opterr) {\
char errbuf[3];\
errbuf[0] = c; errbuf[1] = '\n'; errbuf[2] = '\0'; \
fprintf(stderr, "%s", argv[0]);\
fprintf(stderr, "%s", s);\
fprintf(stderr, "%s", errbuf); }
int opterr = 1; /* getopt prints errors if this is one */
int optind = 1; /* token pointer */
int optopt; /* option character passed back to user */
char *optarg; /* flag argument (or value) */
/* return option option character, EOF if no more or ? if problem */
int getopt(int argc, char **argv, char *opts) /* opts: option string */
{
static int sp = 1; /* character index in current token */
register char *cp; /* pointer into current token */
if (sp == 1) {
/* check for more flag-like tokens */
if(optind >= argc ||
argv[optind][0] != '-' || argv[optind][1] == '\0')
return(EOF);
else if(strcmp(argv[optind], "--") == 0) {
optind++;
return(EOF);
}
}
optopt = argv[optind][sp];
if(optopt == ':' || ( cp = strchr(opts, optopt)) == 0) {
ERR(": illegal option -- ", optopt);
/* if no chars left in this token, move to next token */
if(argv[optind][++sp] == '\0') {
optind++;
sp = 1;
}
return('?');
}
if(*++cp == ':') {/* if a value is expected, get it */
if(argv[optind][sp+1] != '\0')
/* flag value is rest of current token */
optarg = &argv[optind++][sp+1];
else if (++optind >= argc) {
ERR(": option requires an argument -- ", optopt);
sp = 1;
return('?');
} else
/* flag value is next token */
optarg = argv[optind++];
sp = 1;
} else {
/* set up to look at next char in token, next time */
if(argv[optind][++sp] == '\0') {
/* no m ore in current token, set up next token */
sp = 1;
optind++;
}
optarg = 0;
}
return(optopt); /* return current flag character found */
}

+ 11
- 0
libcpropep/Makefile View File

@ -0,0 +1,11 @@
all:
@mkdir -p lib
make -C src all
clean:
@rm -rf lib
make -C src clean
deep-clean: clean
make -C src deep-clean

+ 50
- 0
libcpropep/Makefile.win View File

@ -0,0 +1,50 @@
CC = bcc32
CPP32 = cpp32
LIBRARIAN = tlib
LINKER = ilink32
RC = brc32
COPT = -3 -O2 -w-8004 -w-8012 -w-8057 -IC:\borland\bcc55\include
LDOPT = -LC:\borland\bcc55\lib
INCLUDEDIR = -I..\..\libnum\ -I.
DEF = -DBORLAND
COMPAT_LIBNAME = compat.lib
CPROPEP_LIBNAME = cpropep.lib
THERMO_LIBNAME = thermo.lib
COMPAT_LIBOBJS = compat.obj getopt.obj
THERMO_LIBOBJS = load.obj thermo.obj
CPROPEP_LIBOBJS = equilibrium.obj print.obj performance.obj derivative.obj
TLIBCOMPAT = +compat.obj +getopt.obj
TLIBTHERMO = +load.obj +thermo.obj
TLIBCPROPEP = +equilibrium.obj +print.obj +performance.obj +derivative.obj
.SUFFIXES: .c
all: $(CPROPEP_LIBNAME) $(THERMO_LIBNAME) $(COMPAT_LIBNAME)
.c.obj:
$(CC) $(DEF) $(INCLUDEDIR) $(COPT) -c $*.c -o $*.obj
$(COMPAT_LIBNAME): $(COMPAT_LIBOBJS)
tlib $@ $(TLIBCOMPAT)
$(CPROPEP_LIBNAME): $(CPROPEP_LIBOBJS)
tlib $@ $(TLIBCPROPEP)
$(THERMO_LIBNAME): $(THERMO_LIBOBJS)
tlib $@ $(TLIBTHERMO)
clean:
del *.obj
del *.bak
del *.tds
deep-clean: clean
del $(COMPAT_LIBNAME)
del $(CPROPEP_LIBNAME)
del $(THERMO_LIBNAME)

+ 11
- 0
libcpropep/include/const.h View File

@ -0,0 +1,11 @@
#ifndef const_h
#define const_h
/* molar gaz constant in J/(mol K)*/
#define R 8.31451
/* earth gravitational acceleration */
#define Ge 9.80665
#endif

+ 60
- 0
libcpropep/include/conversion.h View File

@ -0,0 +1,60 @@
#ifndef conversion_h
#define conversion_h
/* pressure units */
enum
{
ATM,
PSI,
BAR,
KPA
};
/* Transform calories to joules */
#define CAL_TO_JOULE 4.1868
/* Transform pound/(cubic inch) to gram/(cubic centimeter) */
#define LBS_IN3_TO_G_CM3 27.679905
/* Transform different pressure units */
#define ATM_TO_PA 101325.0
#define ATM_TO_PSI 14.695949
#define ATM_TO_BAR 1.01325
#define BAR_TO_PSI 14.503774
#define BAR_TO_ATM 0.98692327
#define PSI_TO_ATM 0.068045964
#define KPA_TO_ATM 0.0098692327
/* Length */
#define M_TO_CM 100.0
#define M_TO_IN 39.370079
#define IN_TO_M 0.0254
/* Surface */
#define M2_TO_CM2 10000.0
#define M2_TO_IN2 1550.0031
/* Volume */
#define M3_TO_CM3 1000000.0
#define M3_TO_IN3 61023.744
/* Mass flow */
#define KG_S_TO_LB_S 2.2046226
/* force */
/* newton to pound-force */
#define N_TO_LBF 0.22480894
#define LBF_TO_N 4.4482216
#endif

+ 8
- 0
libcpropep/include/derivative.h View File

@ -0,0 +1,8 @@
#ifndef derivative_h
#define derivative_h
#include "equilibrium.h"
int derivative(equilibrium_t *e);
#endif

+ 156
- 0
libcpropep/include/equilibrium.h View File

@ -0,0 +1,156 @@
#ifndef equilibrium_h
#define equilibrium_h
/* equilibrium.h - Calculation of Complex Chemical Equilibrium */
/* $Id: equilibrium.h,v 1.1 2000/10/13 19:24:31 antoine Exp $ */
/* Copyright (C) 2000 */
/* Antoine Lefebvre <antoine.lefebvre@polymtl.ca> */
/* Mark Pinese <pinese@cyberwizards.com.au> */
/* */
/* Licensed under the GPLv2 */
#include "compat.h"
#include "type.h"
#define GRAM_TO_MOL(g, sp) g/propellant_molar_mass(sp)
#define _min(a, b, c) __min( __min(a, b), c)
#define _max(a, b, c) __max( __max(a, b), c)
extern int global_verbose;
/***************************************************************
FUNCTION PROTOTYPE SECTION
****************************************************************/
int set_verbose(equilibrium_t *e, int v);
/************************************************************
FUNCTION: This function search for all elements present in
the composition and fill the list with the
corresponding number.
PARAMETER: e is of type equilibrium_t and hold the information
about the propellant composition.
COMMENTS: It fill the member element in equilibrium_t
DATE: February 6, 2000
AUTHOR: Antoine Lefebvre
**************************************************************/
int list_element(equilibrium_t *e);
int reset_element_list(equilibrium_t *e);
int list_product(equilibrium_t *e);
/***************************************************************
FUNCTION: This function initialize the equilibrium structure.
The function allocate memory for all the structure
it need. It is important to call dealloc_equilibrium
after.
AUTHOR: Antoine Lefebvre
DATE: February 27, 2000
****************************************************************/
int initialize_equilibrium(equilibrium_t *e);
/***************************************************************
FUNCTION: Dealloc what have been allocated by
initialize_equilibrium
***************************************************************/
int dealloc_equilibrium(equilibrium_t *e);
int reset_equilibrium(equilibrium_t *e);
int copy_equilibrium(equilibrium_t *dest, equilibrium_t *src);
int compute_thermo_properties(equilibrium_t *e);
/***************************************************************
FUNCTION: Set the state at which we want to compute the
equilibrium.
PARAMETER: e is a pointer to an equilibrium_t structure
T is the temperature in deg K
P is the pressure in atm
AUTHOR: Antoine Lefebvre
****************************************************************/
int set_state(equilibrium_t *e, double T, double P);
/***************************************************************
FUNCTION: Add a new molecule in the propellant
PARAMETER: e is a pointer to the equilibrium_t structure
sp is the number of the molecule in the list
mol is the quantity in mol
AUTHOR: Antoine Lefebvre
****************************************************************/
int add_in_propellant(equilibrium_t *e, int sp, double mol);
/***************************************************************
FUNCTION: Return the stochiometric coefficient of an element
in a molecule. If the element isn't present, it return 0.
COMMENTS: There is a different function for the product and for the
propellant.
AUTHOR: Antoine Lefebvre
****************************************************************/
int product_element_coef(int element, int molecule);
//int propellant_element_coef(int element, int molecule);
/***************************************************************
FUNCTION: This function fill the matrix in function of the data
store in the structure equilibrium_t. The solution
of this matrix give corresction to initial estimate.
COMMENTS: It use the theory explain in
"Computer Program for Calculation of Complex Chemical
Equilibrium Compositions, Rocket Performance, Incident
and Reflected Shocks, and Chapman-Jouguet Detonations"
by Gordon and McBride
AUTHOR: Antoine Lefebvre
****************************************************************/
//#ifdef TRUE_ARRAY
//int fill_equilibrium_matrix(double *matrix, equilibrium_t *e, problem_t P);
int fill_matrix(double *matrix, equilibrium_t *e, problem_t P);
//#else
//int fill_equilibrium_matrix(double **matrix, equilibrium_t *e, problem_t P);
//int fill_matrix(double **matrix, equilibrium_t *e, problem_t P);
//#endif
/****************************************************************
FUNCTION: This function compute the equilibrium composition at
at specific pressure/temperature point. It use fill_matrix
to obtain correction to initial estimate. It correct the
value until equilibrium is obtain.
AUTHOR: Antoine Lefebvre
******************************************************************/
int equilibrium(equilibrium_t *equil, problem_t P);
double product_molar_mass(equilibrium_t *e);
#endif

+ 18
- 0
libcpropep/include/performance.h View File

@ -0,0 +1,18 @@
#ifndef performance_h
#define performance_h
#include "compat.h"
#include "return.h"
#include "equilibrium.h"
#include "derivative.h"
int frozen_performance(equilibrium_t *e, exit_condition_t exit_type,
double value);
int shifting_performance(equilibrium_t *e, exit_condition_t exit_type,
double value);
#endif

+ 69
- 0
libcpropep/include/print.h View File

@ -0,0 +1,69 @@
#ifndef print_h
#define print_h
#include "type.h"
#include "equilibrium.h"
#include "derivative.h"
#include "performance.h"
#define PROPELLANT_NAME(sp) (propellant_list + sp)->name
extern FILE * errorfile;
extern FILE * outputfile;
int print_error_message(int error_code);
/***************************************************************
FUNCTION: Print the information of a specie in the thermo_list
PARAMETER: an integer corresponding to the molecule
AUTHOR: Antoine Lefebvre
***************************************************************/
int print_propellant_info(int sp);
int print_thermo_info(int sp);
/*************************************************************
FUNCTION: Print the content of the respective list with the
number which refer to the molecule
AUTHOR: Antoine Lefebvre
modification by Mark Pinese
**************************************************************/
int print_thermo_list(void);
int print_propellant_list(void);
/*************************************************************
FUNCTION: Print the list of condensed species in the product
PARAMETER: a structure of tupe product_t
AUTHOR: Antoine Lefebvre
**************************************************************/
int print_condensed(product_t p);
/*************************************************************
FUNCTION: Print the list of gazeous species in the product
PARAMETER: a structure of tupe product_t
AUTHOR: Antoine Lefebvre
**************************************************************/
int print_gazeous(product_t p);
int print_product_composition(equilibrium_t *e, short npt);
int print_product_properties(equilibrium_t *e, short npt);
int print_propellant_composition(equilibrium_t *e);
//int print_derivative_results(deriv_t *d);
//int print_performance_information(performance_t *p);
int print_performance_information(equilibrium_t *e, short npt);
#endif

+ 22
- 0
libcpropep/include/return.h View File

@ -0,0 +1,22 @@
#ifndef RETURN_H
#define RETURN_H
/* Codes used in some functions by Antoine Lefebvre */
#define SUCCESS 0
#define ERROR -1
/*
Return codes
Mark Pinese 24/4/2000
*/
#define ERR_MALLOC -1
#define ERR_FOPEN -2
#define ERR_EOF -3
#define ERR_NOT_ALLOC -4
#define ERR_TOO_MUCH_PRODUCT -5
#define ERR_EQUILIBRIUM -6
#define ERR_AERA_RATIO -7
#define ERR_RATIO_TYPE -8
#endif /* !defined(RETURN_H) */

+ 161
- 0
libcpropep/include/type.h View File

@ -0,0 +1,161 @@
#ifndef type_h
#define type_h
#define MAX_PRODUCT 400 /* Maximum species in product */
#define MAX_ELEMENT 15 /* Maximum different element */
#define MAX_COMP 20 /* Maximum different ingredient in
composition */
#include "compat.h"
/****************************************************************
TYPE: Enumeration of the possible state of a substance
*****************************************************************/
typedef enum
{
GAS,
CONDENSED,
STATE_LAST
} state_t;
typedef enum
{
TP, /* assign temperature and pressure */
HP, /* assign enthalpy and pressure */
SP /* assign entropy and pressure */
} problem_t;
typedef enum
{
SUBSONIC_AREA_RATIO,
SUPERSONIC_AREA_RATIO,
PRESSURE
} exit_condition_t;
/********************************************
Note: Specific impulse have unit of m/s
Ns/kg = (kg m / s^2) * (s / kg)
= (m / s)
It is habitual to found in literature
specific impulse in units of second.
It is in reality Isp/g where g is
the earth acceleration.
**********************************************/
typedef struct _performance_prop
{
double ae_at; /* Exit aera / Throat aera */
double a_dotm; /* Exit aera / mass flow rate (m/s/atm) */
double cstar; /* Characteristic velocity */
double cf; /* Coefficient of thrust */
double Ivac; /* Specific impulse (vacuum) */
double Isp; /* Specific impulse */
} performance_prop_t;
/***************************************************************
TYPE: Hold the composition of a specific propellant
ncomp is the number of component
molecule[ ] hold the number in propellant_list corresponding
to the molecule
coef[ ] hold the stochiometric coefficient
NOTE: It should be great to allocate the memory of the array in
function of the number of element
DATE: February 6, 2000
****************************************************************/
typedef struct _composition
{
short ncomp; /* Number of different component */
short molecule[MAX_COMP]; /* Molecule code */
double coef[MAX_COMP]; /* Moles of molecule */
double density; /* Density of propellant */
} composition_t;
/*****************************************************************
TYPE: Hold the composition of the combustion product. The molecule
are separate between their different possible state.
NOTE: This structure should be initialize with the function
initialize_product.
DATE: February 13, 2000
******************************************************************/
typedef struct _product
{
bool element_listed; /* true if element have been listed */
bool product_listed; /* true if product have been listed */
bool isequil; /* true if equilibrium is ok */
/* coefficient matrix for the gases */
unsigned short A[MAX_ELEMENT][MAX_PRODUCT];
short n_element; /* n. of different element */
short element[MAX_ELEMENT]; /* element list */
short n[STATE_LAST]; /* n. of species for each state */
short n_condensed; /* n. of total possible condensed */
short species[STATE_LAST][MAX_PRODUCT]; /* possible species in each state */
double coef[STATE_LAST][MAX_PRODUCT]; /* coef. of each molecule */
} product_t;
/* Structure to hold information during the iteration procedure */
typedef struct _iteration_var
{
double n; /* mol/g of the mixture */
double ln_n; /* ln(n) */
double sumn; /* sum of all the nj */
double delta_ln_n; /* delta ln(n) in the iteration process */
double delta_ln_T; /* delta ln(T) in the iteration process */
double delta_ln_nj[MAX_PRODUCT]; /* delta ln(nj) in the iteration process */
double ln_nj[MAX_PRODUCT]; /* ln(nj) nj are the individual mol/g */
} iteration_var_t;
/**********************************************
Hold information on equilibrium properties once
it have been compute
June 14, 2000
***********************************************/
typedef struct _equilib_prop
{
double P; /* Pressure (atm) */
double T; /* Temperature (K) */
double H; /* Enthalpy (kJ/kg) */
double U; /* Internal energy (kJ/kg) */
double G; /* Gibbs free energy (kJ/kg) */
double S; /* Entropy (kJ/(kg)(K)) */
double M; /* Molar mass (g/mol) */
double dV_P; /* (d ln(V) / d ln(P))t */
double dV_T; /* (d ln(V) / d ln(T))p */
double Cp; /* Specific heat (kJ/(kg)(K)) */
double Cv; /* Specific heat (kJ/(kg)(K)) */
double Isex; /* Isentropic exponent (gamma) */
double Vson; /* Sound speed (m/s) */
} equilib_prop_t;
typedef struct _new_equilibrium
{
bool equilibrium_ok; /* true if the equilibrium have been compute */
bool properties_ok; /* true if the properties have been compute */
bool performance_ok; /* true if the performance have been compute */
//temporarily
double entropy;
iteration_var_t itn;
composition_t propellant;
product_t product;
equilib_prop_t properties;
performance_prop_t performance;
} equilibrium_t;
#endif

+ 32
- 0
libcpropep/src/Makefile View File

@ -0,0 +1,32 @@
CC = gcc
COPT = -g -Wall -O3
ROOT = ../..
INCLUDEDIR = -I$(ROOT)/libcompat/include \
-I$(ROOT)/libthermo/include \
-I$(ROOT)/libnum/include \
-I../include/
DEF = -DGCC #-DTRUE_ARRAY
LIBNAME = libcpropep.a
LIBOBJS = equilibrium.o print.o performance.o derivative.o
all: $(LIBNAME)
.c.o:
$(CC) $(DEF) $(INCLUDEDIR) $(COPT) -c $*.c -o $*.o
$(LIBNAME): $(LIBOBJS)
ar -r $@ $(LIBOBJS)
ranlib $@
mv $(LIBNAME) ../lib
clean:
rm -f *.o *~
deep-clean: clean
rm -f ../lib/$(LIBNAME)

+ 241
- 0
libcpropep/src/derivative.c View File

@ -0,0 +1,241 @@
/* derivative.c - Fill the mattrix to compute thermochemical derivative
relative to logarithm of pressure and temperature */
/* $Id: derivative.c,v 1.2 2001/02/22 19:49:28 antoine Exp $ */
/* Copyright (C) 2000 */
/* Antoine Lefebvre <antoine.lefebvre@polymtl.ca> */
/* Mark Pinese <pinese@cyberwizards.com.au> */
/* */
/* Licensed under the GPLv2 */
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "num.h"
#include "derivative.h"
#include "equilibrium.h"
#include "performance.h"
#include "thermo.h"
#include "print.h"
#include "compat.h"
#include "return.h"
int fill_temperature_derivative_matrix(double *matrix, equilibrium_t *e);
int fill_pressure_derivative_matrix(double *matrix, equilibrium_t *e);
/* Compute the specific_heat of the mixture using thermodynamics
derivative with respect to logarithm of temperature */
double mixture_specific_heat(equilibrium_t *e, double *sol)
{
short i, j;
double cp, tmp;
product_t *p = &(e->product);
equilib_prop_t *pr = &(e->properties);
cp = 0.0;
/* Compute Cp/R */
for (i = 0; i < p->n_element; i++)
{
tmp = 0.0;
for (j = 0; j < p->n[GAS]; j++)
tmp += p->A[i][j] * p->coef[GAS][j] *
enthalpy_0(p->species[GAS][j], pr->T);
cp += tmp * sol[i];
}
for (i = 0; i < p->n[CONDENSED]; i++)
{
cp += enthalpy_0(p->species[CONDENSED][i], pr->T)
* sol[i + p->n_element];
}
tmp = 0.0;
for (i = 0; i < p->n[GAS]; i++)
{
tmp += p->coef[GAS][i] * enthalpy_0(p->species[GAS][i], pr->T);
}
cp += tmp * sol[p->n_element + p->n[CONDENSED]];
cp += mixture_specific_heat_0(e, pr->T);
for (i = 0; i < p->n[GAS]; i++)
{
cp += p->coef[GAS][i] * pow(enthalpy_0(p->species[GAS][i], pr->T), 2);
}
return cp;
}
int derivative(equilibrium_t *e)
{
short size;
double *matrix;
double *sol;
product_t *p = &(e->product);
equilib_prop_t *prop = &(e->properties);
/* the size of the coefficient matrix */
size = p->n_element + p->n[CONDENSED] + 1;
matrix = (double *) malloc (size * (size + 1) * sizeof(double));
/* allocate the memory for the solution vector */
sol = (double *) calloc (size, sizeof(double));
fill_temperature_derivative_matrix(matrix, e);
if (NUM_lu(matrix, sol, size) == -1)
{
fprintf(outputfile, "The matrix is singular.\n");
}
else
{
if (global_verbose > 2)
{
fprintf(outputfile, "Temperature derivative results.\n");
NUM_print_vec(sol, size);
}
prop->Cp = mixture_specific_heat(e, sol)*R;
prop->dV_T = 1 + sol[e->product.n_element + e->product.n[CONDENSED]];
}
fill_pressure_derivative_matrix(matrix, e);
if (NUM_lu(matrix, sol, size) == -1)
{
fprintf(outputfile, "The matrix is singular.\n");
}
else
{
if (global_verbose > 2)
{
fprintf(outputfile, "Pressure derivative results.\n");
NUM_print_vec(sol, size);
}
prop->dV_P = sol[e->product.n_element + e->product.n[CONDENSED]] - 1;
}
prop->Cv = prop->Cp + e->itn.n * R * pow(prop->dV_T, 2)/prop->dV_P;
prop->Isex = -(prop->Cp / prop->Cv) / prop->dV_P;
prop->Vson = sqrt(1000 * e->itn.n * R * e->properties.T * prop->Isex);
free(matrix);
free(sol);
return 0;
}
/* Fill the matrix with the coefficient for evaluating derivatives with
respect to logarithm of temperature at constant pressure */
int fill_temperature_derivative_matrix(double *matrix, equilibrium_t *e)
{
short j, k, size;
double tmp;
short idx_cond, idx_n, idx_T;
product_t *p = &(e->product);
equilib_prop_t *pr = &(e->properties);
idx_cond = p->n_element;
idx_n = p->n_element + p->n[CONDENSED];
idx_T = p->n_element + p->n[CONDENSED] + 1;
/* the size of the coefficient matrix */
size = p->n_element + p->n[CONDENSED] + 1;
/* fill the common part */
fill_matrix(matrix, e, TP);
/* del ln(n)/ del ln(T) */
matrix[idx_n + size * idx_n] = 0.0;
/* right side */
for (j = 0; j < p->n_element; j++)
{
tmp = 0.0;
for (k = 0; k < p->n[GAS]; k++)
tmp -= p->A[j][k] * p->coef[GAS][k] * enthalpy_0(p->species[GAS][k],
pr->T);
matrix[j + size * idx_T] = tmp;
}
for (j = 0; j < p->n[CONDENSED]; j++) /* row */
matrix[j + idx_cond + size * idx_T] =
-enthalpy_0( p->species[CONDENSED][j], pr->T);
tmp = 0.0;
for (k = 0; k < p->n[GAS]; k++)
tmp -= p->coef[GAS][k]*enthalpy_0(p->species[GAS][k], pr->T);
matrix[idx_n + size * idx_T] = tmp;
return 0;
}
/* Fill the matrix with the coefficient for evaluating derivatives with
respect to logarithm of pressure at constant temperature */
int fill_pressure_derivative_matrix(double *matrix, equilibrium_t *e)
{
short j, k, size;
double tmp;
short idx_cond, idx_n, idx_T;
product_t *p = &(e->product);
idx_cond = p->n_element;
idx_n = p->n_element + p->n[CONDENSED];
idx_T = p->n_element + p->n[CONDENSED] + 1;
/* the size of the coefficient matrix */
size = p->n_element + p->n[CONDENSED] + 1;
/* fill the common part */
fill_matrix(matrix, e, TP);
/* del ln(n)/ del ln(T) */
matrix[idx_n + size * idx_n] = 0.0;
/* right side */
for (j = 0; j < p->n_element; j++)
{
tmp = 0.0;
for (k = 0; k < p->n[GAS]; k++)
tmp += p->A[j][k] * p->coef[GAS][k];
matrix[j + size * idx_T] = tmp;
}
for (j = 0; j < p->n[CONDENSED]; j++) /* row */
matrix[j + idx_cond + size * idx_T] = 0.0;
tmp = 0.0;
for (k = 0; k < p->n[GAS]; k++)
tmp += p->coef[GAS][k];
matrix[idx_n + size * idx_T] = tmp;
return 0;
}

+ 1258
- 0
libcpropep/src/equilibrium.c
File diff suppressed because it is too large
View File


+ 562
- 0
libcpropep/src/performance.c View File

@ -0,0 +1,562 @@
/* performance.c - Compute performance caracteristic of a motor
considering equilibrium */
/* $Id: performance.c,v 1.2 2001/02/22 19:49:28 antoine Exp $ */
/* Copyright (C) 2000 */
/* Antoine Lefebvre <antoine.lefebvre@polymtl.ca> */
/* Mark Pinese <pinese@cyberwizards.com.au> */
/* */
/* Licensed under the GPLv2 */
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "performance.h"
#include "derivative.h"
#include "print.h"
#include "equilibrium.h"
#include "const.h"
#include "compat.h"
#include "return.h"
#include "thermo.h"
#define TEMP_ITERATION_MAX 8
#define PC_PT_ITERATION_MAX 5
#define PC_PE_ITERATION_MAX 6
double compute_temperature(equilibrium_t *e, double pressure,
double p_entropy);
/* Entropy of the product at the exit pressure and temperature */
double product_entropy_exit(equilibrium_t *e, double pressure, double temp)
{
double ent;
double t = e->properties.T;
double p = e->properties.P;
e->properties.T = temp;
e->properties.P = pressure;
ent = product_entropy(e); /* entropy at the new pressure */
e->properties.T = t;
e->properties.P = p;
return ent;
}
/* Enthalpy of the product at the exit temperature */
double product_enthalpy_exit(equilibrium_t *e, double temp)
{
double enth;
double t = e->properties.T;
e->properties.T = temp;
enth = product_enthalpy(e);
e->properties.T = t;
return enth;
}
/* The temperature could be found by entropy conservation with a
specified pressure */
double compute_temperature(equilibrium_t *e, double pressure, double p_entropy)
{
int i = 0;
double delta_lnt;
double temperature;
/* The first approximation is the chamber temperature */
temperature = e->properties.T;
do
{
delta_lnt = (p_entropy - product_entropy_exit(e, pressure, temperature))
/ mixture_specific_heat_0(e, temperature);
temperature = exp (log(temperature) + delta_lnt);
i++;
} while (fabs(delta_lnt) >= 0.5e-4 && i < TEMP_ITERATION_MAX);
if (i == TEMP_ITERATION_MAX)
{
fprintf(errorfile,
"Temperature do not converge in %d iterations. Don't thrust results.\n",
TEMP_ITERATION_MAX);
}
return temperature;
}
int frozen_performance(equilibrium_t *e, exit_condition_t exit_type,
double value)
{
int err_code;
short i;
double sound_velocity;
double flow_velocity;
double pc_pt; /* Chamber pressure / Throat pressure */
double pc_pe; /* Chamber pressure / Exit pressure */
double log_pc_pe; /* log(pc_pe) */
double ae_at; /* Exit aera / Throat aera */
double cp_cv;
double chamber_entropy;
double exit_pressure = 0;
equilibrium_t *t = e + 1; /* throat equilibrium */
equilibrium_t *ex = e + 2; /* exit equilibrium */
/* find the equilibrium composition in the chamber */
if (!(e->product.isequil))
{
if ((err_code = equilibrium(e, HP)) != SUCCESS)
{
fprintf(outputfile,
"No equilibrium, performance evaluation aborted.\n");
return err_code;
}
}
/* Simplification due to frozen equilibrium */
e->properties.dV_T = 1.0;
e->properties.dV_P = -1.0;
e->properties.Cp = mixture_specific_heat_0(e, e->properties.T) * R;
e->properties.Cv = e->properties.Cp - e->itn.n * R;
e->properties.Isex = e->properties.Cp/e->properties.Cv;
compute_thermo_properties(e);
chamber_entropy = product_entropy(e);
/* begin computation of throat caracteristic */
copy_equilibrium(t, e);
cp_cv = e->properties.Cp/e->properties.Cv;
/* first estimate of Pc/Pt */
pc_pt = pow (cp_cv/2 + 0.5, cp_cv/(cp_cv - 1));
i = 0;
do
{
t->properties.T = compute_temperature(t, e->properties.P/pc_pt,
chamber_entropy);
/* Cp of the combustion point assuming frozen */
t->properties.Cp = mixture_specific_heat_0(e, t->properties.T) * R;
/* Cv = Cp - nR (for frozen) */
t->properties.Cv = t->properties.Cp - t->itn.n * R;
t->properties.Isex = t->properties.Cp/t->properties.Cv;
compute_thermo_properties(t);
sound_velocity = sqrt(1000 * e->itn.n * R * t->properties.T *
t->properties.Isex);
flow_velocity = sqrt(2000*(product_enthalpy(e)*R*e->properties.T -
product_enthalpy_exit(e, t->properties.T)*
R*t->properties.T));
pc_pt = pc_pt / ( 1 + ((pow(flow_velocity, 2) - pow(sound_velocity, 2))
/(1000*(t->properties.Isex + 1)*
t->itn.n * R *t->properties.T)));
i++;
} while ((fabs((pow(flow_velocity, 2) - pow(sound_velocity, 2))
/pow(flow_velocity, 2)) > 0.4e-4) &&
(i < PC_PT_ITERATION_MAX));
if (i == PC_PT_ITERATION_MAX)
{
fprintf(errorfile,
"Throat pressure do not converge in %d iterations. Don't thrust results\n",
PC_PT_ITERATION_MAX);
}
//printf("%d iterations to evaluate throat pressure.\n", i);
t->properties.P = e->properties.P/pc_pt;
t->performance.Isp = t->properties.Vson = sound_velocity;
/* Now compute exit properties */
copy_equilibrium(ex, e);
if (exit_type == PRESSURE)
{
exit_pressure = value;
}
else
{
ae_at = value;
/* Initial estimate of pressure ratio */
if (exit_type == SUPERSONIC_AREA_RATIO)
{
if ((ae_at > 1.0) && (ae_at < 2.0))
{
log_pc_pe = log(pc_pt) + sqrt (3.294*pow(ae_at,2) + 1.535*log(ae_at));
}
else if (ae_at >= 2.0)
{
log_pc_pe = t->properties.Isex + 1.4 * log(ae_at);
}
else
{
printf("Aera ratio out of range ( < 1.0 )\n");
return ERR_AERA_RATIO;
}
}
else if (exit_type == SUBSONIC_AREA_RATIO)
{
if ((ae_at > 1.0) && (ae_at < 1.09))
{
log_pc_pe = 0.9 * log(pc_pt) /
(ae_at + 10.587 * pow(log(ae_at), 3) + 9.454 * log(ae_at));
}
else if (ae_at >= 1.09)
{
log_pc_pe = log(pc_pt) /
(ae_at + 10.587 * pow(log(ae_at), 3) + 9.454 * log(ae_at));
}
else
{
printf("Aera ratio out of range ( < 1.0 )\n");
return ERR_AERA_RATIO;
}
}
else
{
return ERR_RATIO_TYPE;
}
/* Improved the estimate */
i = 0;
do
{
pc_pe = exp(log_pc_pe);
ex->properties.P = exit_pressure = e->properties.P/pc_pe;
ex->properties.T = compute_temperature(e, exit_pressure,
chamber_entropy);
/* Cp of the combustion point assuming frozen */
ex->properties.Cp = mixture_specific_heat_0(e, ex->properties.T) * R;
/* Cv = Cp - nR (for frozen) */
ex->properties.Cv = ex->properties.Cp - ex->itn.n * R;
ex->properties.Isex = ex->properties.Cp/ex->properties.Cv;
compute_thermo_properties(ex);
sound_velocity = sqrt(1000 * ex->itn.n * R * ex->properties.T *
ex->properties.Isex);
ex->performance.Isp =
flow_velocity = sqrt(2000*(product_enthalpy(e)*R*e->properties.T -
product_enthalpy_exit(e, ex->properties.T)*
R*ex->properties.T));
ex->performance.ae_at =
(ex->properties.T * t->properties.P * t->performance.Isp) /
(t->properties.T * ex->properties.P * ex->performance.Isp);
log_pc_pe = log_pc_pe +
(ex->properties.Isex*pow(flow_velocity, 2)/
(pow(flow_velocity, 2) - pow(sound_velocity,2))) *
(log(ae_at) - log(ex->performance.ae_at));
i++;
} while ( (fabs((log_pc_pe - log(pc_pe))) > 0.00004) &&
(i < PC_PE_ITERATION_MAX) );
if (i == PC_PE_ITERATION_MAX)
{
fprintf(errorfile,
"Exit pressure do not converge in %d iterations. Don't thrust results\n",
PC_PE_ITERATION_MAX);
}
//printf("%d iterations to evaluate exit pressure.\n", i);
pc_pe = exp(log_pc_pe);
exit_pressure = e->properties.P/pc_pe;
}
ex->properties.T = compute_temperature(e, exit_pressure,
chamber_entropy);
/* We must check if the exit temperature is more than 50 K lower
than any transition temperature of condensed species.
In this case the results are not good and must be reject. */
ex->properties.P = exit_pressure;
ex->performance.Isp = sqrt(2000*(product_enthalpy(e)*R*e->properties.T -
product_enthalpy_exit(e, ex->properties.T)*
R*ex->properties.T));
/* units are (m/s/atm) */
ex->performance.a_dotm = 1000 * R * ex->properties.T * ex->itn.n /
(ex->properties.P * ex->performance.Isp);
/* Cp of the combustion point assuming frozen */
ex->properties.Cp = mixture_specific_heat_0(e, ex->properties.T) * R;
/* Cv = Cp - nR (for frozen) */
ex->properties.Cv = ex->properties.Cp - ex->itn.n * R;
ex->properties.Isex = ex->properties.Cp/ex->properties.Cv;
compute_thermo_properties(ex);
ex->properties.Vson = sqrt(1000 * e->itn.n * R * ex->properties.T *
e->properties.Isex);
t->performance.a_dotm = 1000 * R * t->properties.T
* t->itn.n / (t->properties.P * t->performance.Isp);
t->performance.ae_at = 1.0;
t->performance.cstar = e->properties.P * t->performance.a_dotm;
t->performance.cf = t->performance.Isp /
(e->properties.P * t->performance.a_dotm);
t->performance.Ivac = t->performance.Isp + t->properties.P
* t->performance.a_dotm;
ex->performance.ae_at =
(ex->properties.T * t->properties.P * t->performance.Isp) /
(t->properties.T * ex->properties.P * ex->performance.Isp);
ex->performance.cstar = e->properties.P * t->performance.a_dotm;
ex->performance.cf = ex->performance.Isp /
(e->properties.P * t->performance.a_dotm);
ex->performance.Ivac = ex->performance.Isp + ex->properties.P
* ex->performance.a_dotm;
return SUCCESS;
}
int shifting_performance(equilibrium_t *e, exit_condition_t exit_type,
double value)
{
int err_code;
short i;
double sound_velocity = 0.0;
double flow_velocity;
double pc_pt;
double pc_pe;
double log_pc_pe;
double ae_at;
double chamber_entropy;
double exit_pressure = 0;
equilibrium_t *t = e + 1; /* throat equilibrium */
equilibrium_t *ex = e + 2; /* throat equilibrium */
/* find the equilibrium composition in the chamber */
if (!(e->product.isequil))
/* if the equilibrium have not already been compute */
{
if ((err_code = equilibrium(e, HP)) < 0)
{
fprintf(outputfile, "No equilibrium, performance evaluation aborted.\n");
return err_code;
}
}
/* Begin by first aproximate the new equilibrium to be
the same as the chamber equilibrium */
copy_equilibrium(t, e);
chamber_entropy = product_entropy(e);
/* Computing throat condition */
/* Approximation of the throat pressure */
pc_pt = pow(t->properties.Isex/2 + 0.5,
t->properties.Isex/(t->properties.Isex - 1) );
t->entropy = chamber_entropy;
i = 0;
do
{
t->properties.P = e->properties.P/pc_pt;
/* We must compute the new equilibrium each time */
if ((err_code = equilibrium(t, SP)) < 0)
{
fprintf(outputfile, "No equilibrium, performance evaluation aborted.\n");
return err_code;
}
sound_velocity = sqrt (1000*t->itn.n*R*t->properties.T*
t->properties.Isex);
flow_velocity = sqrt (2000*(product_enthalpy(e)*R*e->properties.T -
product_enthalpy(t)*R*t->properties.T));
pc_pt = pc_pt / ( 1 + ((pow(flow_velocity, 2) - pow(sound_velocity, 2))
/(1000*(t->properties.Isex + 1)*t->itn.n*R*
t->properties.T)));
i++;
} while ((fabs((pow(flow_velocity, 2) - pow(sound_velocity, 2))
/pow(flow_velocity, 2)) > 0.4e-4) &&
(i < PC_PT_ITERATION_MAX));
if (i == PC_PT_ITERATION_MAX)
{
fprintf(errorfile, "Throat pressure do not converge in %d iterations."
" Don't thrust results.\n", PC_PT_ITERATION_MAX);
}
//printf("%d iterations to evaluate throat pressure.\n", i);
t->properties.P = e->properties.P/pc_pt;
t->properties.Vson = sound_velocity;
t->performance.Isp = sound_velocity;
t->performance.a_dotm = 1000 * R *
t->properties.T * t->itn.n /
(t->properties.P * t->performance.Isp);
copy_equilibrium(ex, e);
if (exit_type == PRESSURE)
{
exit_pressure = value;
}
else
{
ae_at = value;
/* Initial estimate of pressure ratio */
if (exit_type == SUPERSONIC_AREA_RATIO)
{
if ((ae_at > 1.0) && (ae_at < 2.0))
{
log_pc_pe = log(pc_pt) + sqrt (3.294*pow(ae_at,2) + 1.535*log(ae_at));
}
else if (ae_at >= 2.0)
{
log_pc_pe = t->properties.Isex + 1.4 * log(ae_at);
}
else
{
printf("Aera ratio out of range ( < 1.0 )\n");
return ERR_AERA_RATIO;
}
}
else if (exit_type == SUBSONIC_AREA_RATIO)
{
if ((ae_at > 1.0) && (ae_at < 1.09))
{
log_pc_pe = 0.9 * log(pc_pt) /
(ae_at + 10.587 * pow(log(ae_at), 3) + 9.454 * log(ae_at));
}
else if (ae_at >= 1.09)
{
log_pc_pe = log(pc_pt) /
(ae_at + 10.587 * pow(log(ae_at), 3) + 9.454 * log(ae_at));
}
else
{
printf("Aera ratio out of range ( < 1.0 )\n");
return ERR_AERA_RATIO;
}
}
else
{
return ERR_RATIO_TYPE;
}
/* Improved the estimate */
ex->entropy = chamber_entropy;
i = 0;
do
{
pc_pe = exp(log_pc_pe);
ex->properties.P = exit_pressure = e->properties.P/pc_pe;
/* Find the exit equilibrium */
if ((err_code = equilibrium(ex, SP)) < 0)
{
fprintf(outputfile,
"No equilibrium, performance evaluation aborted.\n");
return err_code;
}
sound_velocity = ex->properties.Vson;
ex->performance.Isp =
flow_velocity = sqrt(2000*(product_enthalpy(e)*R*e->properties.T -
product_enthalpy(ex)*R*ex->properties.T));
ex->performance.ae_at =
(ex->properties.T * t->properties.P * t->performance.Isp) /
(t->properties.T * ex->properties.P * ex->performance.Isp);
log_pc_pe = log_pc_pe +
(ex->properties.Isex*pow(flow_velocity, 2)/
(pow(flow_velocity, 2) - pow(sound_velocity,2))) *
(log(ae_at) - log(ex->performance.ae_at));
i++;
} while ((fabs((log_pc_pe - log(pc_pe))) > 0.00004) &&
(i < PC_PE_ITERATION_MAX));
if (i == PC_PE_ITERATION_MAX)
{
fprintf(errorfile, "Exit pressure do not converge in %d iteration."
" Don't thrust results.\n", PC_PE_ITERATION_MAX);
}
//printf("%d iterations to evaluate exit pressure.\n", i);
pc_pe = exp(log_pc_pe);
exit_pressure = e->properties.P/pc_pe;
}
ex->entropy = chamber_entropy;
ex->properties.P = exit_pressure;
/* Find the exit equilibrium */
if ((err_code = equilibrium(ex, SP)) < 0)
{
fprintf(outputfile, "No equilibrium, performance evaluation aborted.\n");
return err_code;
}
flow_velocity = sqrt(2000*(product_enthalpy(e)*R*e->properties.T -
product_enthalpy(ex)*R*ex->properties.T));
ex->performance.Isp = flow_velocity;
ex->performance.a_dotm = 1000 * R *
ex->properties.T * ex->itn.n /
(ex->properties.P * ex->performance.Isp);
t->performance.ae_at = 1.0;
t->performance.cstar = e->properties.P * t->performance.a_dotm;
t->performance.cf = t->performance.Isp /
(e->properties.P * t->performance.a_dotm);
t->performance.Ivac = t->performance.Isp + t->properties.P
* t->performance.a_dotm;
ex->performance.ae_at =
(ex->properties.T * t->properties.P * t->performance.Isp) /
(t->properties.T * ex->properties.P * ex->performance.Isp);
ex->performance.cstar = e->properties.P * t->performance.a_dotm;
ex->performance.cf = ex->performance.Isp /
(e->properties.P * t->performance.a_dotm);
ex->performance.Ivac = ex->performance.Isp + ex->properties.P
* ex->performance.a_dotm;
return SUCCESS;
}

+ 427
- 0
libcpropep/src/print.c View File

@ -0,0 +1,427 @@
/* print.c - Output functions */
/* $Id: print.c,v 1.2 2001/02/22 19:49:28 antoine Exp $ */
/* Copyright (C) 2000 */
/* Antoine Lefebvre <antoine.lefebvre@polymtl.ca> */
/* Mark Pinese <pinese@cyberwizards.com.au> */
/* */
/* Licensed under the GPLv2 */
#include <stdio.h>
#include "print.h"
#include "performance.h"
#include "equilibrium.h"
#include "conversion.h"
#include "thermo.h"
#include "const.h"
char header[][32] = {
"CHAMBER",
"THROAT",
"EXIT" };
char err_message[][64] = {
"Error allocating memory",
"Error opening file",
"Error EOF",
"Error memory not allocated",
"Error too much product",
"Error in equilibrium",
"Error bad aera ratio",
"Error bad aera ratio type"};
FILE * errorfile;
FILE * outputfile;
int print_error_message(int error_code)
{
fprintf(errorfile, "%s\n", err_message[-error_code - 1]);
return 0;
}
int print_propellant_info(int sp)
{
int j;
if (sp > num_propellant || sp < 0)
return -1;
fprintf(outputfile, "Code %-35s Enthalpy Density Composition\n", "Name");
fprintf(outputfile, "%d %-35s % .4f % .2f", sp,
(propellant_list + sp)->name,
(propellant_list + sp)->heat,
(propellant_list + sp)->density);
fprintf(outputfile, " ");
/* print the composition */
for (j = 0; j < 6; j++)
{
if (!((propellant_list + sp)->coef[j] == 0))
fprintf(outputfile, "%d%s ", (propellant_list + sp)->coef[j],
symb[ (propellant_list + sp)->elem[j] ]);
}
fprintf(outputfile, "\n");
return 0;
}
int print_thermo_info(int sp)
{
int i, j;
thermo_t *s;
if (sp > num_thermo || sp < 0)
return -1;
s = (thermo_list + sp);
fprintf(outputfile, "---------------------------------------------\n");
fprintf(outputfile, "Name: \t\t\t%s\n", s->name);
fprintf(outputfile, "Comments: \t\t%s\n", s->comments);
fprintf(outputfile, "Id: \t\t\t%s\n", s->id);
fprintf(outputfile, "Chemical formula:\t");
for (i = 0; i < 5; i++)
{
if (!(s->coef[i] == 0))
fprintf(outputfile, "%d%s", s->coef[i], symb[ s->elem[i]]);
}
fprintf(outputfile, "\n");
fprintf(outputfile, "State:\t\t\t");
switch (s->state)
{
case GAS:
fprintf(outputfile, "GAZ\n");
break;
case CONDENSED:
fprintf(outputfile, "CONDENSED\n");
break;
default:
printf("UNRECOGNIZE\n");
}
fprintf(outputfile, "\n");
fprintf(outputfile, "Molecular weight: \t\t% f g/mol\n", s->weight);
fprintf(outputfile, "Heat of formation at 298.15 K : % f J/mol\n", s->heat);
fprintf(outputfile, "Assign enthalpy : % f J/mol\n", s->enth);
fprintf(outputfile, "HO(298.15) - HO(0): \t\t% f J/mol\n", s->dho);
fprintf(outputfile, "Number of temperature range: % d\n\n", s->nint);
for (i = 0; i < s->nint; i++)
{
fprintf(outputfile, "Interval: %f - %f \n", s->range[i][0],
s->range[i][1]);
for (j = 0; j < 9; j++)
fprintf(outputfile, "% .9e ", s->param[i][j]);
fprintf(outputfile, "\n\n");
}
fprintf(outputfile, "---------------------------------------------\n");
return 0;
}
int print_thermo_list(void)
{
int i;
for (i = 0; i < num_thermo; i++)
fprintf(outputfile, "%-4d %-15s % .2f\n", i, (thermo_list + i)->name,
(thermo_list + i)->heat);
return 0;
}
int print_propellant_list(void)
{
int i;
for (i = 0; i < num_propellant; i++)
fprintf(outputfile, "%-4d %-30s %5f\n", i, (propellant_list + i)->name,
(propellant_list +i)->heat);
return 0;
}
int print_condensed(product_t p)
{
int i;
for (i = 0; i < p.n[CONDENSED]; i ++)
fprintf(outputfile, "%s ",
(thermo_list + p.species[CONDENSED][i])->name );
fprintf(outputfile, "\n");
return 0;
}
int print_gazeous(product_t p)
{
int i;
for (i = 0; i < p.n[GAS]; i++)
fprintf(outputfile, "%s ", (thermo_list + p.species[GAS][i])->name);
fprintf(outputfile, "\n");
return 0;
}
int print_product_composition(equilibrium_t *e, short npt)
{
int i, j, k;
double mol_g = e->itn.n;
/* we have to build a list of all condensed species present
in the three equilibrium */
int n = 0;
int condensed_list[MAX_PRODUCT];
/* ok become false if the species already exist in the list */
int ok = 1;
double qt;
for (i = 0; i < e->product.n[CONDENSED]; i++)
mol_g += e->product.coef[CONDENSED][i];
fprintf(outputfile, "\nMolar fractions\n\n");
for (i = 0; i < e->product.n[GAS]; i++)
{
if (e->product.coef[GAS][i]/e->itn.n > 0.0)
{
fprintf(outputfile, "%-20s",
(thermo_list + e->product.species[GAS][i])->name);
for (j = 0; j < npt; j++)
fprintf(outputfile, " %11.4e", (e+j)->product.coef[GAS][i]/mol_g);
fprintf(outputfile,"\n");
}
}
/* build the list of condensed */
for (i = 0; i < npt; i++)
{
for (j = 0; j < (e+i)->product.n[CONDENSED]; j++)
{
for (k = 0; k < n; k++)
{
/* check if the condensed are to be include in the list */
if (condensed_list[k] == (e+i)->product.species[CONDENSED][j])
{
/* we do not have to include the species */
ok = 0;
break;
}
} /* k */
if (ok)
{
condensed_list[n] = (e+i)->product.species[CONDENSED][j];
n++;
}
/* reset the flag */
ok = 1;
} /* j */
} /* i */
if (n > 0)
{
fprintf(outputfile, "Condensed species\n");
for (i = 0; i < n; i++)
{
fprintf(outputfile, "%-20s",
(thermo_list + condensed_list[i])->name);
for (j = 0; j < npt; j++)
{
/* search in the product of each equilibrium if the
condensed is present */
qt = 0.0;
for (k = 0; k < (e+j)->product.n[CONDENSED]; k++)
{
if (condensed_list[i] == (e+j)->product.species[CONDENSED][k])
{
qt = (e+j)->product.coef[CONDENSED][k];
break;
}
}
fprintf(outputfile, " %11.4e", qt/mol_g);
}
fprintf(outputfile,"\n");
}
}
fprintf(outputfile, "\n");
return 0;
}
int print_propellant_composition(equilibrium_t *e)
{
int i, j;
fprintf(outputfile, "Propellant composition\n");
fprintf(outputfile, "Code %-35s mol Mass (g) Composition\n", "Name");
for (i = 0; i < e->propellant.ncomp; i++)
{
fprintf(outputfile, "%-4d %-35s %.4f %.4f ", e->propellant.molecule[i],
PROPELLANT_NAME(e->propellant.molecule[i]), e->propellant.coef[i],
e->propellant.coef[i] *
propellant_molar_mass(e->propellant.molecule[i]));
fprintf(outputfile, " ");
/* print the composition */
for (j = 0; j < 6; j++)
{
if (!((propellant_list + e->propellant.molecule[i])->coef[j] == 0))
fprintf(outputfile, "%d%s ",
(propellant_list + e->propellant.molecule[i])->coef[j],
symb[(propellant_list + e->propellant.molecule[i])->elem[j]]);
}
fprintf(outputfile, "\n");
}
fprintf(outputfile, "Density : % .3f g/cm^3\n", e->propellant.density);
if (e->product.element_listed)
{
fprintf(outputfile, "%d different elements\n", e->product.n_element);
/* Print those elements */
for (i = 0; i < e->product.n_element; i++)
fprintf(outputfile, "%s ", symb[e->product.element[i]] );
fprintf(outputfile, "\n");
}
fprintf(outputfile, "Total mass: % f g\n", propellant_mass(e));
fprintf(outputfile, "Enthalpy : % .2f kJ/kg\n",
propellant_enthalpy(e));
fprintf(outputfile, "\n");
if (e->product.product_listed)
{
fprintf(outputfile, "%d possible gazeous species\n", e->product.n[GAS]);
if (global_verbose > 1)
print_gazeous(e->product);
fprintf(outputfile, "%d possible condensed species\n\n",
e->product.n_condensed);
if (global_verbose > 1)
print_condensed(e->product);
}
return 0;
}
int print_performance_information (equilibrium_t *e, short npt)
{
short i;
fprintf(outputfile, "Ae/At : ");
for (i = 1; i < npt; i++)
fprintf(outputfile, " % 11.5f", (e+i)->performance.ae_at);
fprintf(outputfile, "\n");
fprintf(outputfile, "A/dotm (m/s/atm) : ");
for (i = 1; i < npt; i++)
fprintf(outputfile, " % 11.5f", (e+i)->performance.a_dotm);
fprintf(outputfile, "\n");
fprintf(outputfile, "C* (m/s) : ");
for (i = 1; i < npt; i++)
fprintf(outputfile, " % 11.5f", (e+i)->performance.cstar);
fprintf(outputfile, "\n");
fprintf(outputfile, "Cf : ");
for (i = 1; i < npt; i++)
fprintf(outputfile, " % 11.5f", (e+i)->performance.cf);
fprintf(outputfile, "\n");
fprintf(outputfile, "Ivac (m/s) : ");
for (i = 1; i < npt; i++)
fprintf(outputfile, " % 11.5f", (e+i)->performance.Ivac);
fprintf(outputfile, "\n");
fprintf(outputfile, "Isp (m/s) : ");
for (i = 1; i < npt; i++)
fprintf(outputfile, " % 11.5f", (e+i)->performance.Isp);
fprintf(outputfile, "\n");
fprintf(outputfile, "Isp/g (s) : ");
for (i = 1; i < npt; i++)
fprintf(outputfile, " % 11.5f", (e+i)->performance.Isp/Ge);
fprintf(outputfile, "\n");
return 0;
}
int print_product_properties(equilibrium_t *e, short npt)
{
short i;
fprintf(outputfile, " ");
for (i = 0; i < npt; i++)
fprintf(outputfile, " %11s", header[i]);
fprintf(outputfile, "\n");
fprintf(outputfile, "Pressure (atm) :");
for (i = 0; i < npt; i++)
fprintf(outputfile, " % 11.3f", (e+i)->properties.P);
fprintf(outputfile, "\n");
fprintf(outputfile, "Temperature (K) :");
for (i = 0; i < npt; i++)
fprintf(outputfile, " % 11.3f", (e+i)->properties.T);
fprintf(outputfile, "\n");
fprintf(outputfile, "H (kJ/kg) :");
for (i = 0; i < npt; i++)
fprintf(outputfile, " % 11.3f", (e+i)->properties.H);
fprintf(outputfile, "\n");
fprintf(outputfile, "U (kJ/kg) :");
for (i = 0; i < npt; i++)
fprintf(outputfile, " % 11.3f", (e+i)->properties.U);
fprintf(outputfile, "\n");
fprintf(outputfile, "G (kJ/kg) :");
for (i = 0; i < npt; i++)
fprintf(outputfile, " % 11.3f", (e+i)->properties.G);
fprintf(outputfile, "\n");
fprintf(outputfile, "S (kJ/(kg)(K) :");
for (i = 0; i < npt; i++)
fprintf(outputfile, " % 11.3f", (e+i)->properties.S);
fprintf(outputfile, "\n");
fprintf(outputfile, "M (g/mol) :");
for (i = 0; i < npt; i++)
fprintf(outputfile, " % 11.3f", (e+i)->properties.M);
fprintf(outputfile, "\n");
fprintf(outputfile, "(dLnV/dLnP)t :");
for (i = 0; i < npt; i++)
fprintf(outputfile, " % 11.5f", (e+i)->properties.dV_P);
fprintf(outputfile, "\n");
fprintf(outputfile, "(dLnV/dLnT)p :");
for (i = 0; i < npt; i++)
fprintf(outputfile, " % 11.5f", (e+i)->properties.dV_T);
fprintf(outputfile, "\n");
fprintf(outputfile, "Cp (kJ/(kg)(K)) :");
for (i = 0; i < npt; i++)
fprintf(outputfile, " % 11.5f", (e+i)->properties.Cp);
fprintf(outputfile, "\n");
fprintf(outputfile, "Cv (kJ/(kg)(K)) :");
for (i = 0; i < npt; i++)
fprintf(outputfile, " % 11.5f", (e+i)->properties.Cv);
fprintf(outputfile, "\n");
fprintf(outputfile, "Cp/Cv :");
for (i = 0; i < npt; i++)
fprintf(outputfile, " % 11.5f", (e+i)->properties.Cp/(e+i)->properties.Cv);
fprintf(outputfile, "\n");
fprintf(outputfile, "Gamma :");
for (i = 0; i < npt; i++)
fprintf(outputfile, " % 11.5f", (e+i)->properties.Isex);
fprintf(outputfile, "\n");
fprintf(outputfile, "Vson (m/s) :");
for (i = 0; i < npt; i++)
fprintf(outputfile, " % 11.5f", (e+i)->properties.Vson);
fprintf(outputfile, "\n");
fprintf(outputfile, "\n");
return 0;
}

+ 13
- 0
libnum/Makefile View File

@ -0,0 +1,13 @@
all:
@mkdir -p lib
make -C src all
clean:
@rm -rf lib
make -C src clean
deep-clean: clean
make -C src deep-clean

+ 43
- 0
libnum/Makefile.win View File

@ -0,0 +1,43 @@
CC = bcc32
CPP32 = cpp32
LIBRARIAN = tlib
LINKER = ilink32
RC = brc32
COPT = -3 -O2 -w-8012 -w-8004 -w-8057 -IC:\borland\bcc55\include
OBJS = lu.obj rk4.obj general.obj print.obj sec.obj
TLIBNUM = +lu.obj +rk4.obj +general.obj +print.obj +sec.obj
LDOPT = -LC:\borland\bcc55\lib
PROG = test.exe
PROGOBJS = test.obj
LIBNUM = libnum.lib
.SUFFIXES: .c
all: $(LIBNUM) $(PROG)
.c.obj:
$(CC) $(DEF) $(COPT) -c $*.c -o $*.obj
$(LIBNUM): $(OBJS)
tlib $@ $(TLIBNUM)
$(PROG): $(PROGOBJS)
$(CC) $(LDOPT) $(LIBNUM) $(PROGOBJS)
clean:
del *.obj
del *.bak
del *.tds
deep-clean: clean
del $(LIBNUM)
del $(PROG)

+ 149
- 0
libnum/include/num.h View File

@ -0,0 +1,149 @@
/* num.h - Library of numerical method
* $Id: num.h,v 1.3 2001/02/22 19:47:37 antoine Exp $
* Copyright (C) 2000
* Antoine Lefebvre <antoine.lefebvre@polymtl.ca>
*
* Licensed under the GPL
*/
#ifndef num_h
#define num_h
/* NOTE on matrix representation
* -----------------------------
* All matrix should be allocate the following way
*
* matrix = (double *) malloc (sizeof(double) * line * column)
*
* to access the value at line 2, column 4, you do it like that
*
* matrix[2 + 4*line]
*/
/* This type is used as function pointer for the
* sysnewton algorithm.
*/
typedef double (*func_t)(double *x);
typedef struct status
{
int itn;
} status_t;
#define NO_CONVERGENCE 1
#define NO_SOLUTION 2
/* Find the solution of linear system of equation using the
* LU factorisation method as explain in
* 'Advanced engineering mathematics' bye Erwin Kreyszig.
*
* This algorithm will also do column permutation to find
* the larger pivot.
*
* ARGUMENTS
* ---------
* matrix: the augmented matrix of coefficient in the system
* with right hand side value.
*
* solution: the solution vector
*
* neq: number of equation in the system
*
* Antoine Lefebvre
* february 6, 2000 Initial version
* october 20, 2000 revision of the permutation method
*/
int NUM_lu(double *matrix, double *solution, int neq);
//int old_lu(double *matrix, double *solution, int neq);
/* This function print the coefficient of the matrix to
* the screen.
*
* matrix: should be an augmented matrix
* neq : number of equation
*/
int NUM_print_matrix(double *matrix, int neq);
/* Print the coefficient of the square matrix to the screen
*/
int NUM_print_square_matrix(double *matrix, int neq);
/* This function print the contents of the vector to
* the screen.
*
* vec: vector containing neq element
*/
int NUM_print_vec(double *vec, int neq);
/**************************************************************
FUNCTION: This function solve systems of ODE of the first order
with the Runge-Kutta method of the fourth order.
PARAMETER: The first parameter is a pointer to the function we
we want to solve. This function take five parameter
neq is the number of equations in the system
time is the time at which we want to evaluate
y is an array containing an initial value
dy will store the result of the function
ierr any error field
step is the time variation
duration is the total time of the simulation
ic are the initial conditions
**y is an array containing all the data
void * is nay user data
COMMENTS: **y must be properly allocated, [number of points]X[neq]
It could be interesting to add a tolerance and use
variable step to reach our tolerance instead of using a
fixed step.
AUTHOR: Antoine Lefebvre
DATE: February 11
*****************************************************************/
int NUM_rk4(int (*f)(int neq, double time, double *y, double *dy, void *data),
int neq, double step, double duration, double *ic,
double **y, void *data );
int NUM_rkf(int (*f)(int neq, double time, double *y, double *dy, void *data),
int neq, double step, double duration, double *ic,
double **y, double epsil, void *data);
/* this function return the nearest integer to a */
/* it is a replacement of rint which is not ANSI complient */
int Round(double a);
double epsilon(void);
int NUM_sec(double (*f)(double x), double x0, double x1, int nmax,
double epsilon, double *ans);
int NUM_newton(double (*f)(double x), double (*df)(double x), double x0,
int nmax, double epsilon, double *ans);
int NUM_ptfix(double (*f)(double x), double x0,
double nmax, double epsilon, double *ans);
int NUM_sysnewton(func_t *Jac, func_t *R, double *x, int nvar,
int nmax, double eps);
int trapeze(double *data, int n_point, int col, int off, double *integral);
int simpson(double *data, int n_point, int col, int off, double *integral);
int create_spline(double *data, int n_point, double *spline);
#endif

+ 38
- 0
libnum/src/Makefile View File

@ -0,0 +1,38 @@
CC = gcc
COPT = -g -Wall -O3 #-pg
LIB = -lnum -lm
LIBDIR = -L../lib/
INCDIR = -I../include/
DEF = -DLINUX
PROG = test
OBJS = test.o
LIBOBJS = lu.o rk4.o rkf.o general.o print.o sec.o newton.o ptfix.o\
sysnewton.o trapeze.o simpson.o spline.o
LIBNUM = libnum.a
all: $(LIBNUM) $(PROG)
.c.o:
$(CC) $(DEF) $(INCDIR) $(COPT) -c $*.c -o $*.o
$(LIBNUM): $(LIBOBJS)
ar -r $@ $(LIBOBJS)
ranlib $@
mv $(LIBNUM) ../lib/
$(PROG): $(LIBNUM) $(OBJS)
$(CC) $(COPT) $(OBJS) $(LIBDIR) $(LIB) -o $@
clean:
rm -f $(PROG) *.o *~
deep-clean: clean
rm -f ../lib/$(LIBNUM)

+ 32
- 0
libnum/src/general.c View File

@ -0,0 +1,32 @@
#include "num.h"
int Round(double a)
{
int t = a;
if (a - (double)t < 0.5)
return t;
else if (a - (double)t > 0.5)
return t + 1;
else
return (t + (t % 2));
}
double epsilon(void)
{
double epsilon;
double temp;
epsilon = 1.0;
temp = epsilon + 1.0;
while (temp > 1.0)
{
epsilon = epsilon / 2.0;
temp = epsilon + 1.0;
}
return (epsilon * 2.0);
}

+ 172
- 0
libnum/src/lu.c View File

@ -0,0 +1,172 @@
/* lu.c - PA = LU factorisation with pivoting
* $Id: lu.c,v 1.4 2001/02/22 19:47:37 antoine Exp $
* Copyright (C) 2000
* Antoine Lefebvre <antoine.lefebvre@polymtl.ca>
*
*
* Licensed under the GPLv2
*/
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "num.h"
/*
This algorithm will compute an LU factorisation on the augmented
matrix (A) passed in arguments.
This algorithm assumed the element on the diagonal of the lower
triangular matrix set to 1.
In order to save memory space, every coefficient of both matrix
L and U are written in the original matrix overwriting initial
values of A.
*/
int NUM_lu(double *matrix, double *solution, int neq)
{
int i, j, k;
int idx; /* index of the larger pivot */
double big; /* the larger pivot found */
double tmp = 0.0;
int *P; /* keep memory of permutation (column permutation) */
double *y;
P = (int *) calloc (neq, sizeof(int));
y = (double *) calloc (neq, sizeof(double));
for (i = 0; i < neq; i++)
{
solution[i] = 0; /* reset the solution vector */
P[i] = i; /* initialize permutation vector */
}
/* LU Factorisation */
for (i = 0; i < neq - 1; i++) /* line */
{
for (j = i; j < neq; j++) /* column */
{
tmp = 0.0;
for (k = 0; k < i; k++)
tmp += matrix[i + neq*P[k]] * matrix[k + neq*P[j]];
matrix[i + neq*P[j]] = matrix[i + neq*P[j]] - tmp;
}
/* find the larger pivot and interchange the columns */
big = 0.0;
idx = i;
for (j = i; j < neq; j++)
{
if (big < fabs(matrix[i + neq*P[j]])) /* we found a larger pivot */
{
idx = j;
big = fabs(matrix[i + neq*P[j]]);
}
}
/* check if we have to interchange the lines */
if (idx != i)
{
tmp = P[i];
P[i] = P[idx];
P[idx] = tmp;
}
if (matrix[i + neq*P[i]] == 0.0)
{
printf("LU: matrix is singular, no unique solution.\n");
return NO_SOLUTION;
}
for (j = i+1; j < neq; j++)
{
tmp = 0.0;
for (k = 0; k < i; k++)
tmp += matrix[j + neq*P[k]] * matrix[k + neq*P[i]];
matrix[j + neq*P[i]] = (matrix[j + neq*P[i]] - tmp)/matrix[i + neq*P[i]];
}
}
i = neq - 1;
tmp = 0.0;
for (k = 0; k < neq-1; k++)
tmp += matrix[i + neq*P[k]] * matrix[k + neq*P[i]];
matrix[i + neq*P[i]] = matrix[i + neq*P[i]] - tmp;
/* End LU-Factorisation */
/* substitution for y Ly = b*/
for (i = 0; i < neq; i++)
{
tmp = 0.0;
for (j = 0; j < i; j++)
tmp += matrix[i + neq*P[j]] * y[j];
y[i] = matrix[i + neq*neq] - tmp;
}
/* substitution for x Ux = y*/
for (i = neq - 1; i >=0; i--)
{
if (matrix[i + neq*P[i]] == 0.0)
{
printf("LU: No unique solution exist.\n");
return NO_SOLUTION;
}
tmp = 0.0;
for (j = i; j < neq; j++)
tmp += matrix[i + neq*P[j]] * solution[P[j]];
solution[P[i]] = (y[i] - tmp)/matrix[i + neq*P[i]];
}
free (y);
return 0;
}
/* This function will divide each row of the matrix
* by the highest element of this row.
* This kind of scaling could improve precision while
* solving some difficult matrix.
*/
int NUM_matscale(double *matrix, int neq)
{
int i; /* line */
int j; /* column */
double val;
double tmp;
for (i = 0; i < neq; i++)
{
val = 0;
/* find the highest value */
for (j = 0; j < neq; j++)
{
tmp = abs(matrix[i + neq*j]);
val = (tmp > val) ? tmp : val;
}
/* divide element of the line by this value
* including the right side
* if the max value is defferent than zero
*/
if (val != 0.0)
{
for (j = 0; j < neq+1; j++)
matrix[i + neq*j] = matrix[i + neq*j]/val;
}
}
return 0;
}

+ 31
- 0
libnum/src/newton.c View File

@ -0,0 +1,31 @@
#include <math.h>
#include <stdio.h>
#include "num.h"
int NUM_newton(double (*f)(double x), double (*df)(double x), double x0,
int nmax, double eps, double *ans)
{
int i = 0;
double x1;
double delta;
do
{
if (i >= nmax)
{
return NO_CONVERGENCE;
}
x1 = x0 - f(x0)/df(x0);
delta = fabs(x1 - x0)/fabs(x1);
x0 = x1;
i++;
} while (delta > eps);
*ans = x1;
return 0;
}

+ 54
- 0
libnum/src/print.c View File

@ -0,0 +1,54 @@
/* print.c
* $Id: print.c,v 1.3 2000/10/20 20:17:20 antoine Exp $
* Copyright (C) 2000
* Antoine Lefebvre <antoine.lefebvre@polymtl.ca>
*
* Licensed under the GPL
*/
#include <stdio.h>
#include "num.h"
int NUM_print_square_matrix(double *matrix, int neq)
{
int i = 0;
int j = 0;
for (i = 0; i < neq; i++)
{
for (j = 0; j < neq; j++)
printf("% .5f ", matrix[i + neq*j]);
printf("\n");
}
printf("\n");
return 0;
}
int NUM_print_matrix(double *matrix, int neq)
{
int i = 0;
int j = 0;
for (i = 0; i < neq; i++)
{
for (j = 0; j <= neq; j++)
printf("% .5e ", matrix[i + neq*j]);
printf("\n");
}
printf("\n");
return 0;
}
int NUM_print_vec(double *vec, int neq)
{
int i;
for (i = 0; i < neq; i++)
printf("% .5e ", vec[i]);
printf("\n");
return 0;
}

+ 31
- 0
libnum/src/ptfix.c View File

@ -0,0 +1,31 @@
#include <math.h>
#include <stdio.h>
#include "num.h"
int NUM_ptfix(double (*f)(double x), double x0, double nmax,
double epsilon, double *ans)
{
int i = 0;
double x1;
double delta;
do
{
if (i >= nmax)
{
return NO_CONVERGENCE;
}
x1 = f(x0);
delta = fabs(x1 - x0)/fabs(x1);
x0 = x1;
i++;
} while (delta > epsilon);
*ans = x1;
return 0;
}

+ 107
- 0
libnum/src/rk4.c View File

@ -0,0 +1,107 @@
#include <stdlib.h>
#include <math.h>
#include "num.h"
int NUM_rk4(int (*f)(int neq, double time, double *y, double *dy, void *data),
int neq, double step, double duration, double *ic,
double **y, void *data)
{
int i;
int n;
int status;
int length;
double t = 0.0;
double *tmp;
double *dy;
double *K1, *K2, *K3, *K4;
double *a;
tmp = (double *) malloc(sizeof(double) * neq);
dy = (double *) malloc(sizeof(double) * neq);
K1 = (double *) malloc(sizeof(double) * neq);
K2 = (double *) malloc(sizeof(double) * neq);
K3 = (double *) malloc(sizeof(double) * neq);
K4 = (double *) malloc(sizeof(double) * neq);
/* allocation of the answer vector */
length = (int)ceil(duration/step) + 1;
a = *y = (double *) malloc(sizeof(double) * neq * length);
for (i = 0; i < neq; i++)
{
tmp[i] = a[i + neq*0] = ic[i]; /* initials conditions */
}
for (n = 0; n < Round(duration/step); n++)
{
for (i = 0; i < neq; i++)
{
status = f(neq, t, tmp, dy, data);
if (status)
return status;
K1[i] = step * dy[i];
tmp[i] = a[i + neq*n] + K1[i]/2; /* for the next step */
}
/* FIXME: verify the coefficient t + step/2 */
for (i = 0; i < neq; i++)
{
status = f(neq, t + step/2, tmp, dy, data);
if (status)
return -1;
K2[i] = step * dy[i];
tmp[i] = a[i + neq*n] + K2[i]/2;
}
for (i = 0; i < neq; i++)
{
status = f(neq, t + step/2, tmp, dy, data);
if (status)
return status;
K3[i] = step * dy[i];
tmp[i] = a[i + neq*n] + K3[i];
}
for (i = 0; i < neq; i++)
{
status = f(neq, t + step, tmp, dy, data);
if (status)
return -1;
K4[i] = step * dy[i];
}
for (i = 0; i < neq; i++)
a[i + neq*(n+1)] = a[i + neq*n] +
(1.0/6.0)*(K1[i] + 2.0*K2[i] + 2.0*K3[i] + K4[i]);
t = t + step;
}
free(tmp);
free(dy);
free(K1);
free(K2);
free(K3);
free(K4);
return length;
}

+ 179
- 0
libnum/src/rkf.c View File

@ -0,0 +1,179 @@
#include <stdlib.h>
#include <math.h>
#include <float.h>
#include "num.h"
/* neq: number of equations
* step: initial time step
* duration: total duration of the simulation
* ic: initial conditions vector
* y: solution vector
* epsil: precision on the data
* data: pointer to data structure
*/
/* Runge-Kutta-Fehlberg 4-5 order */
int NUM_rkf(int (*f)(int neq, double time, double *y, double *dy, void *data),
int neq, double step, double duration, double *ic,
double **y, double epsil, void *data)
{
int i;
int n;
int col;
double h;
double t = 0.0;
double *a;
double *tmp;
double *dy;
double *K1, *K2, *K3, *K4, *K5, *K6;
double *E; /* Error vector of the error */
double err; /* maximum error */
double beta;
tmp = (double *) malloc(sizeof(double) * neq);
dy = (double *) malloc(sizeof(double) * neq);
E = (double *) malloc(sizeof(double) * neq);
K1 = (double *) malloc(sizeof(double) * neq);
K2 = (double *) malloc(sizeof(double) * neq);
K3 = (double *) malloc(sizeof(double) * neq);
K4 = (double *) malloc(sizeof(double) * neq);
K5 = (double *) malloc(sizeof(double) * neq);
K6 = (double *) malloc(sizeof(double) * neq);
h = step;
n = 0;
col = neq + 1;
a = *y = (double *) malloc(sizeof(double) * col * (n + 1));
for (i = 0; i < neq; i++)
{
tmp[i] = a[i + col*0] = ic[i]; /* initial conditions */
}
while (t < duration)
{
a = *y = (double *) realloc(*y, sizeof(double) * col * (n + 2));
for (i = 0; i < neq; i++)
{
f(neq, t, tmp, dy, data);
K1[i] = h * dy[i];
tmp[i] = a[i + col*n] + K1[i]/4.0; /* for the next step */
}
for (i = 0; i < neq; i++)
{
f(neq, t + h/4.0, tmp, dy, data);
K2[i] = h * dy[i];
tmp[i] = a[i + col*n] + 3.0*K1[i]/32.0 + 9.0*K2[i]/32.0;
}
for (i = 0; i < neq; i++)
{
f(neq, t + 3.0*h/8.0, tmp, dy, data);
K3[i] = h * dy[i];
tmp[i] = a[i + col*n] + 1932.0*K1[i]/2197.0 - 7200.0*K2[i]/2197.0 +
7296.0*K3[i]/2197.0;
}
for (i = 0; i < neq; i++)
{
f(neq, t + 12.0*h/13.0, tmp, dy, data);
K4[i] = h * dy[i];
tmp[i] = a[i + col*n] + 439.0*K1[i]/216.0 - 8.0*K2[i] +
3680.0*K3[i]/513.0 - 845.0*K4[i]/4104.0;
}
for (i = 0; i < neq; i++)
{
f(neq, t + h, tmp, dy, data);
K5[i] = h * dy[i];
tmp[i] = a[i + col*n] - 8.0*K1[i]/27.0 + 2.0*K2[i] -
3544.0*K3[i]/2565.0 + 1859.0*K4[i]/4104.0 - 11.0*K5[i]/40.0;
}
for (i = 0; i < neq; i++)
{
f(neq, t + h/2.0, tmp, dy, data);
K6[i] = h * dy[i];
}
err = 0.0;
for (i = 0; i < neq; i++)
{
E[i] = fabs(K1[i]/360.0 - 128.0*K3[i]/4275.0 - 2197.0*K4[i]/75240.0 +
K5[i]/50.0 + 2.0*K6[i]/55.0); /* /h ?? */
//printf("E[%d] = %f\n", i, E[i]);
err = ((E[i] > err) ? E[i] : err);
}
//printf("err = %e\n", err);
if ((err < epsil) || (h <= step/1000) )
{
t += h;
for (i = 0; i < neq; i++)
{
a[i + col*(n+1)] = a[i + col*n] + 25.0*K1[i]/216.0 +
1408.0*K3[i]/2565.0 + 2197.0*K4[i]/4104.0 - 0.2*K5[i];
}
/* store the time */
a[neq + col*(n+1)] = t;
n++;
}
beta = pow(epsil/(2*err), 0.25);
if (beta < 0.1)
{
h = 0.1* h;
}
else if (beta > 4)
{
h = 4.0*h;
}
else
{
h = beta * h;
}
/* we have to prevent too little h*/
if (h < step/1000)
h = step/1000;
/* prevent too big */
if (h > duration/16)
h = duration/16;
if (t + h > duration)
{
h = duration - t;
}
}
return n+1;
}

+ 33
- 0
libnum/src/sec.c View File

@ -0,0 +1,33 @@
#include <math.h>
#include <stdio.h>
#include "num.h"
/* Resolution of non-linear equation of the for
f(x) = 0 with the secante method which is a modified
newton method using secante instead of derivative */
int NUM_sec(double (*f)(double x), double x0, double x1, int nmax,
double epsilon, double *ans)
{
int i = 0;
double x2;
double delta;
do
{
if (i >= nmax)
{
return NO_CONVERGENCE;
}
x2 = x1 - f(x1)*(x1 - x0)/(f(x1) - f(x0));
delta = fabs(x2 - x1)/fabs(x2);
x0 = x1;
x1 = x2;
i++;
} while (delta > epsilon);
*ans = x2;
return 0;
}

+ 49
- 0
libnum/src/simpson.c View File

@ -0,0 +1,49 @@
#include <math.h>
int simpson(double *data, int n_point, int col, int off, double *integral)
{
int i;
double val = 0;
double x0, x1, x2, fx0, fx1, fx2;
double dd_x0x1;
double dd_x1x2;
double dd_x0x1x2;
int beg = 0;
if ((n_point%2) != 1)
{
beg = 1;
x0 = data[0 + 0*col];
x1 = data[0 + 1*col];
fx0 = data[off + 0*col];
fx1 = data[off + 1*col];
val += (fx0+fx1)*(x1-x0)/2;
}
for (i = beg; i < n_point - 2; i += 2)
{
x0 = data[0 + (i+0)*col];
x1 = data[0 + (i+1)*col];
x2 = data[0 + (i+2)*col];
fx0 = data[off + (i+0)*col];
fx1 = data[off + (i+1)*col];
fx2 = data[off + (i+2)*col];
dd_x0x1 = (fx1 - fx0)/(x1 - x0);
dd_x1x2 = (fx2 - fx1)/(x2 - x1);
dd_x0x1x2 = (dd_x1x2 - dd_x0x1)/(x2 - x0);
val += (fx0 - dd_x0x1*x0 + dd_x0x1x2*x0*x1)*(x2 - x0) +
(dd_x0x1 - dd_x0x1x2*(x0+x1))*(pow(x2, 2)-pow(x0, 2))/2 +
dd_x0x1x2*(pow(x2, 3) - pow(x0,3))/3;
}
*integral = val;
return 0;
}

+ 108
- 0
libnum/src/spline.c View File

@ -0,0 +1,108 @@
/* spline.c - Cubic spline interpolation
* $Id: spline.c,v 1.1 2001/06/10 21:06:00 antoine Exp $
* Copyright (C) 2000
* Antoine Lefebvre <antoine.lefebvre@polymtl.ca>
*
*
* Licensed under the GPLv2
*/
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "num.h"
#define OUT_OF_RANGE -1
/* Computation of natural spline.
*/
int create_spline(double *data, int n_point, double *spline)
{
int i;
int col;
double hi0, hi1, hi2;
double fi0, fi1, fi2;
double *matrix;
col = 2;
matrix = (double *) calloc (n_point*(n_point+1), sizeof(double));
/* create the linear system */
matrix[0 + 0] = 1;
for (i = 1; i < n_point - 1; i++)
{
hi0 = data[0 + (i+0)*col] - data[0 + (i-1)*col];
hi1 = data[0 + (i+1)*col] - data[0 + (i-0)*col];
hi2 = data[0 + (i+1)*col] - data[0 + (i-1)*col];
fi0 = data[1 + (i-1)*col]; /* f(x_(i-1)) */
fi1 = data[1 + (i-0)*col]; /* f(x_i) */
fi2 = data[1 + (i+1)*col]; /* f(x_(i+1)) */
matrix[i + (i-1)*n_point] = hi0/(hi0+hi1);
matrix[i + (i-0)*n_point] = 2;
matrix[i + (i+1)*n_point] = hi1/(hi0+hi1);
matrix[i + n_point*n_point] = 6*( (fi2-fi1)/hi1 - (fi1-fi0)/hi0)/hi2;
}
matrix[n_point - 1 + (n_point - 1)*n_point] = 1;
NUM_print_matrix(matrix, n_point);
NUM_lu(matrix, spline, n_point);
NUM_print_vec(spline, n_point);
free(matrix);
return 0;
}
int eval_spline(double *data, double *spline, int n_point, double x, double *y)
{
int i;
int col = 2;
double hi0;
double xi0;
double xi1;
double fi0;
double fi1;
double d2f0;
double d2f1;
/* we must find the interval in which x is located */
i = 0;
if ((x < data[0]) || (x > data[0 + (n_point - 1)*col]))
{
printf("Out of range: %f\n", x);
return OUT_OF_RANGE;
}
for (i = 0; x > data[0 + i*col]; i++);
xi0 = data[0 + (i-1)*col];
xi1 = data[0 + i*col];
hi0 = xi1 - xi0;
fi0 = data[1 + (i-1)*col];
fi1 = data[1 + i*col];
d2f0 = spline[i-1];
d2f1 = spline[i];
/* evaluation of the spline at the specified point */
*y = -d2f0*pow(x-xi1, 3)/(6*hi0) + d2f1*pow(x-xi0, 3)/(6*hi0)
-(fi0/hi0 - hi0*d2f0/6)*(x-xi1) + (fi1/hi0 - hi0*d2f1/6)*(x-xi0);
return 0;
}

+ 86
- 0
libnum/src/sysnewton.c View File

@ -0,0 +1,86 @@
/* sysnewton.c - Solve system of non-linear equations with newton's method
* $Id: sysnewton.c,v 1.1 2000/10/20 20:17:20 antoine Exp $
* Copyright (C) 2000
* Antoine Lefebvre <antoine.lefebvre@polymtl.ca>
*
* Licensed under the GPL
*/
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "num.h"
double norme(double *x, int n);
/* Jac : Pointer to a matrix of pointer to function (Jacobian matrix)
* R : Pointer to a vector of pointer to function (Residue vector)
* x : Initial estimate of the solution (will be overwrite by the answer)
* nvar: Number of variable in the system
* nmax: Maximal number of iterations
* eps : Precision on the answer
*/
int NUM_sysnewton(func_t *Jac, func_t *R, double *x, int nvar,
int nmax, double eps)
{
int i, j, l;
double *r;
double *dx; /* solution of the system */
double *matrix; /* the matrix to be solve */
/* Allow space for the left hand side */
matrix = (double *) malloc (sizeof(double) * nvar * (nvar + 1));
r = (double *) malloc (sizeof(double) * nvar);
dx = (double *) malloc(sizeof(double) * nvar);
l = 0;
do
{
/* set up the matrix */
for (i = 0; i < nvar; i++) /* line */
{
for (j = 0; j < nvar; j++) /* column */
{
matrix[i + nvar*j] = Jac[i + nvar*j](x);
}
r[i] = matrix[i + nvar*nvar] = -R[i](x);
}
/* if the matrix is singular */
if (NUM_lu(matrix, dx, nvar))
return NO_CONVERGENCE;
for (i = 0; i < nvar; i++)
{
x[i] = x[i] + dx[i];
}
if ((norme(dx, nvar)/norme(x, nvar) < eps) &&
(norme(r, nvar) <= eps))
{
/* the solution converged */
return 0;
}
l++;
} while (l < nmax);
return NO_CONVERGENCE;
}
double norme(double *x, int n)
{
int i;
double a = 0.0;
for (i = 0; i < n; i++)
{
a += pow(x[i], 2);
}
return sqrt(a);
}

+ 344
- 0
libnum/src/test.c View File

@ -0,0 +1,344 @@
/* test.c - Testing the functionnality of the various method
* $Id: test.c,v 1.5 2001/06/10 21:06:00 antoine Exp $
* Copyright (C) 2000
* Antoine Lefebvre <antoine.lefebvre@polymtl.ca>
*
* Licensed under the GPL
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
//#include <time.h>
#include "num.h"
FILE * errorfile;
FILE * outputfile;
int test_rk4(void);
int test_lu(void);
int test_sysnewton(void);
int test_sec(void);
int test_newton(void);
int test_ptfix(void);
int test_spline(void);
/* g1(x) = x + 1 - ln(x) */
double g1(double x) {
return x + 1 - log(x);
}
/* f1(x) = ln(x) - 1 */
double f1(double x) {
return log(x) - 1;
}
/* f1'(x) = 1/x */
double df1(double x) {
return 1/x;
}
double dg1(double x) {
return 1 - 1/x;
}
/* f(x) = (x-1)^3 */
double f(double x) {
return pow(x-1, 3);
}
int function(int neq, double time, double *y, double *dy,
void *data)
{
dy[0] = y[1];
dy[1] = -9.8;
dy[2] = y[3];
dy[3] = 0;
return 0;
}
/* functions to test the sysnewton algorythm
*
* The system to be solve is the following
* r1(x1, x2) = e^x1 - x2 = 0
* r2(x1, x2) = x1^2 + x2^2 - 16 = 0
*
*/
double r1(double *x)
{
return exp(x[0]) - x[1];
}
double r2(double *x)
{
return pow(x[0], 2) + pow(x[1], 2) - 16;
}
/* We need partial derivative of these function with each variable
* dr1_dx1(x1, x2) = e^x1
* dr1_dx2(x1, x2) = -1
* dr2_dx1(x1, x2) = 2*x1
* dr2_dx2(x1, x2) = 2*x2
*/
double dr1_dx1(double *x)
{
return exp(x[0]);
}
double dr1_dx2(double *x)
{
return -1;
}
double dr2_dx1(double *x)
{
return 2*x[0];
}
double dr2_dx2(double *x)
{
return 2*x[1];
}
int main(void)
{
test_lu();
test_spline();
test_rk4();
test_sysnewton();
test_sec();
test_newton();
test_ptfix();
return 0;
}
int test_sec(void)
{
double ans;
printf("Testing Secante method\n");
if (NUM_sec(f1, 1, 2, 100, 0.0001, &ans))
printf("No solution: error in the method.\n\n");
else
printf("Solution: %f\n\n", ans);
return 0;
}
int test_newton(void)
{
double ans;
printf("Testing Newton method\n");
if (NUM_newton(f1, df1, 1, 100, 0.0001, &ans))
printf("No solution: error in the method.\n\n");
else
printf("Solution: %f\n\n", ans);
return 0;
}
int test_ptfix(void)
{
double ans;
printf("Testing fixed point method\n");
if (NUM_ptfix(g1, 1, 100, 0.0001, &ans))
printf("No solution: error in the method.\n");
else
printf("Solution: %f\n\n", ans);
return 0;
}
int test_sysnewton(void)
{
func_t *jac;
func_t *r;
int nvar = 2;
double x[2]; /* solution vector, contain initially the initial conditions */
printf("Testing newton method for solving"
" non-linear system of equations.\n");
jac = (func_t *) malloc (sizeof(func_t) * nvar * nvar);
r = (func_t *) malloc (sizeof(func_t) * nvar);
/* Initialize the functions pointers array */
r[0] = r1;
r[1] = r2;
jac[0] = dr1_dx1;
jac[1] = dr2_dx1;
jac[2] = dr1_dx2;
jac[3] = dr2_dx2;
/* set the initial estimate */
x[0] = 2.8;
x[1] = 2.8;
/* call the sysnewton function */
NUM_sysnewton(jac, r, x, 2, 100, 1e-8);
/* print the solution */
printf("Solution: x1 = %f, x2 = %f\n", x[0], x[1]);
printf("\n");
return 0;
}
int test_lu(void)
{
int i;
double *matrix;
double *solution;
int size = 8;
printf("Testing the LU factorisation algotythm.\n");
matrix = (double *) malloc (sizeof(double)*size*(size+1));
solution = (double *) malloc (sizeof(double)*size);
matrix[0] = 4.77088e-02; matrix[8] = 1.17204e-01; matrix[16] = 1.88670e-02;
matrix[1] = 1.17204e-01; matrix[9] = 4.07815e-01; matrix[17] = 1.25752e-02;
matrix[2] = 1.88670e-02; matrix[10] = 1.25752e-02; matrix[18] = 4.40215e-02;
matrix[3] = 0.00000e+00; matrix[11] = 0.00000e+00; matrix[19] = 0.00000e+00;
matrix[4] = 0.00000e+00; matrix[12] = 0.00000e+00; matrix[20] = 0.00000e+00;
matrix[5] = 1.00000e+00; matrix[13] = 0.00000e+00; matrix[21] = 3.00000e+00;
matrix[6] = 2.97603e-02; matrix[14] = 8.67031e-02; matrix[22] = 2.51546e-02;
matrix[7] = 5.15962e+01; matrix[15] = 1.67940e+02; matrix[23] = -7.46975e+01;
matrix[24] = 0.00000e+00;
matrix[25] = 0.00000e+00;
matrix[26] = 0.00000e+00;
matrix[27] = 1.28681e-02;
matrix[28] = 0.00000e+00;
matrix[29] = 0.00000e+00;
matrix[30] = 6.43406e-03;
matrix[31] = -7.23674e-01;
matrix[32] = 0.0000e+00; matrix[40] = 1.00000e+00; matrix[48] = 2.97603e-02;
matrix[33] = 0.0000e+00; matrix[41] = 0.00000e+00; matrix[49] = 8.67031e-02;
matrix[34] = 0.0000e+00; matrix[42] = 3.00000e+00; matrix[50] = 2.51546e-02;
matrix[35] = 0.0000e+00; matrix[43] = 0.00000e+00; matrix[51] = 6.43406e-03;
matrix[36] = 0.0000e+00; matrix[44] = 2.00000e+00; matrix[52] = 0.00000e+00;
matrix[37] = 2.0000e+00; matrix[45] = 0.00000e+00; matrix[53] = 0.00000e+00;
matrix[38] = 0.0000e+00; matrix[46] = 0.00000e+00; matrix[54] = 1.45616e-02;
matrix[39] = 0.0000e+00; matrix[47] =-9.68727e+03; matrix[55] =-3.06747e+01;
matrix[56] = 5.15962e+01; matrix[64] =-1.12677e+01;
matrix[57] = 1.67940e+02; matrix[65] = 8.29437e+00;
matrix[58] =-7.46975e+01; matrix[66] =-7.39145e+01;
matrix[59] =-7.23674e-01; matrix[67] =-5.99249e-01;
matrix[60] = 0.00000e+00; matrix[68] = 1.58804e-02;
matrix[61] =-9.68727e+03; matrix[69] =-9.62706e+03;
matrix[62] =-3.06747e+01; matrix[70] =-4.63904e+01;
matrix[63] = 4.68590e+05; matrix[71] = 2.37298e+05;
//NUM_matscale(matrix, size);
NUM_print_matrix(matrix, size);
if (NUM_lu(matrix, solution, size))
printf("No solution: Error in the numerical method,\n");
else
NUM_print_vec(solution, size);
/*
for (i = 0; i < size; i++)
{
if (solution[i] != 1.0)
{
printf("Error found in the solution.\n");
}
}
*/
printf("\n");
return 0;
}
int test_rk4(void)
{
int i, n;
double *ans;
double *ic;
printf("\nTesting the RK4 and RKF algorythm.\n");
ic = (double *) malloc(sizeof(double) * 4);
ic[0] = 0;
ic[1] = 100;
ic[2] = 0;
ic[3] = 10;
/* it return the length of the answer vector */
//n = NUM_rk4 (function, 4, 0.1, 10, ic, &ans, NULL);
//for (i = 0; i < n; i++)
//{
// printf("%f %f %f %f \n", ans[4*i], ans[1 + 4*i], ans[2+4*i], ans[3+4*i]);
//}
n = NUM_rkf (function, 4, 0.1, 20, ic, &ans, 1e-4, NULL);
printf("n = %i\n", n);
for( i = 0; i < n; i++)
{
printf("%f %f %f %f %f\n", ans[4 + 5*i], ans[5*i],
ans[1+5*i], ans[2 + 5*i], ans[3 + 5*i]);
}
free(ic);
free(ans);
return 0;
}
int test_spline(void)
{
int i;
double *data;
double *spline;
int size = 10;
double ans;
printf("Testing the spline function.\n\n");
data = malloc (2 * size * sizeof(double));
spline = malloc (size * sizeof(double));
data[0] = 0; /* x0 */
data[1] = 55; /* y0 */
data[2] = 5; /* x1 */
data[3] = 60; /* y1 */
data[4] = 10; /* ... */
data[5] = 58;
data[6] = 15;
data[7] = 54;
data[8] = 20;
data[9] = 55;
data[10] = 25;
data[11] = 60;
data[12] = 30;
data[13] = 54;
data[14] = 35;
data[15] = 57;
data[16] = 40;
data[17] = 52;
data[18] = 45;
data[19] = 49;
create_spline(data, size, spline);
for (i = 0; i < 45; i++)
{
eval_spline(data, spline, size, (double)i, &ans);
printf("%d %f\n", i, ans);
}
printf("Spline test finish\n");
return 0;
}

+ 16
- 0
libnum/src/trapeze.c View File

@ -0,0 +1,16 @@
int trapeze(double *data, int n_point, int col, int off, double *integral)
{
int i;
double val = 0.0;
for (i = 0; i < n_point - 1; i++)
{
val += (data[off + i*col] + data[off + (i + 1)*col])*
(data[0 + (i + 1)*col] - data[0 + i*col])/2;
}
*integral = val;
return 0;
}

+ 43
- 0
libsimulation/Makefile View File

@ -0,0 +1,43 @@
CXX = g++
CC = gcc
CXXFLAGS = -g -Wall
CFLAG = -g -Wall
LEXER = motor
CXXSRC = simulation.cc modeles.cc rocket.cc lsode.cc rk4.cc
CXXOBJS = simulation.o modeles.o rocket.o lsode.o rk4.o
COBJS = motor.yy.o
LIBNAME = librocket.a
.SUFFIXES: .cc
.cc.o:
$(CXX) $(DEF) $(INCLUDE) $(CXXFLAGS) -c $*.cc -o $*.o
$(LIBNAME): $(CXXOBJS) $(COBJS)
ar -r $@ $(CXXOBJS) $(COBJS)
ranlib $@
$(COBJS): $(LEXER).yy.c
$(CXX) $(CFLAG) -c $< -o $@
$(LEXER).yy.c: $(LEXER).l
flex -o$(LEXER).yy.c $<
clean:
rm -f *.o *~
clean-all: clean
rm $(LIBNAME)
.PHONY: clean

+ 2
- 0
libsimulation/TODO View File

@ -0,0 +1,2 @@
1- There is a memory leak in the lexer. I don't find how to free the
buffer that was allocated by flex...

+ 51
- 0
libsimulation/c++rocket.h View File

@ -0,0 +1,51 @@
/* c++rocket.h - Simulation of rocket flight */
/* Copyright (C) 2000 */
/* Antoine Lefebvre <antoine.lefebvre@polymtl.ca> */
/* This program is free software; you can redistribute it and/or modify*/
/* it under the terms of the GNU General Public License as published by*/
/* the Free Software Foundation; either version 2 of the License, or */
/* (at your option) any later version. */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* You should have received a copy of the GNU General Public License */
/* along with this program; if not, write to the Free Software */
/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#if !defined (cxx_rocket_h)
#define cxx_rocket_h 1
class simulation;
#ifndef PI
#define PI 3.14159265358979323846
#endif
#define MAXPROP 3 // Maximum number of stage on the rocket
// pointer to the actual simulation
extern simulation *simptr;
extern const double R; // Perfect gaz constant
extern const double g; // Earth gravitational accélération
extern const double G; // universal gravitational constant
typedef enum
{
AERO_MODEL,
SIMPLE_MODEL,
MODEL_LAST
} Model_t;
#endif

+ 193
- 0
libsimulation/lsode.cc View File

@ -0,0 +1,193 @@
#include <cmath>
#include <iostream>
#include "lsode.h"
//#include "simulation.h"
#include "c++rocket.h"
//typedef int (* ModelFunc)(const int &, const double &, double *,
// double *, int &);
char *error_msg(State s);
static int ModelNeq[MODEL_LAST] = { 7, 5 };
lsode::lsode(Model_t model) {
memory = 0;
neq = ModelNeq[model];
//dy = new double*[7];
time = 0.0;
itol = 1;
rtol = 1.49012e-08;
atol = 1.49012e-08;
itask = 1;
istate = 1;
iopt = 0;
rwork = new double[20+16*neq];
lrw = 20+16*neq;
iwork = new int[20];
liw = 20;
mf = 10;
state = new double[neq];
if (!rwork) {
cout << "Allocation error\n";
exit(-1);
}
switch (model)
{
case AERO_MODEL:
md = model_1;
break;
case SIMPLE_MODEL:
md = model_2;
break;
default:
exit(-1);
}
}
lsode::~lsode() {
if (memory) {
for (int j = 0; j < neq; j++)
delete [] dy[j];
delete dy;
}
delete [] state;
delete [] iwork;
delete [] rwork;
cout << "Freeing memory...\n" ;
}
int lsode::solve(double *st, double duration, double step)
{
reset();
if (memory) {
for (int j = 0; j < neq; j++)
delete [] dy[j];
delete dy;
memory = 0;
}
length = (int)rint(duration/step);
// on alloue la memoire
dy = new double*[neq];
for (int j = 0; j < neq; j++)
dy[j] = new double[length];
memory = 1; // pour indiquer que l'on a alloue la memoire
// on simule et on remplie l'array
for (int i = 0; i < length; i++) {
tout = i*step;
lsode_((ModelFunc_t)md, neq, st, time, tout, itol, rtol, atol,
itask, istate, iopt, rwork, lrw, iwork, liw, NULL, mf);
for (int j = 0; j < neq ; j++)
dy[j][i] = st[j];
if (istate < 0) // if any error, stop the simulation
{
cout << "ERROR: " << error_msg ((State)istate) << endl;
cout << i << " points out of " << length << " were found."
<< endl;
return i;
}
}
cout << "Simulation completed successfully." << endl;
cout << length << " " << "points computed" << endl;
return length;
}
void lsode::reset()
{
tout = 0.0; // restart the simulation at 0
time = 0.0; // restart the time at 0
istate = 1; // should reset the istate
}
void lsode::print() {
for (int i = 0; i < length; i++) {
for (int j = 0; j < neq; j++) {
cout << dy[j][i] << "\t";
}
cout << "\n";
}
}
void lsode::get_data(double** a)
{
for (int i = 0; i < length; i++)
for (int j = 0; j < neq; j++)
a[j][i] = dy[j][i];
}
char *error_msg(State s)
{
switch (s)
{
case TOO_MUCH_WORK:
return "Excess work done on this call (perhaps wrong mf).";
break;
case TOO_MUCH_ACC:
return "Excess Accuracy Requested (Tolerances too small).";
break;
case ILLEGAL_INPUT:
return "Illegal input detected.";
break;
case ERR_FAILURE:
return "Repeated error test failures.";
break;
case CONV_FAILURE:
return "Repeated convergence failures.";
break;
case ERROR_WEIGHT:
return "Error weight became zero during problem.";
break;
case EXIT_IN_FUNCTION:
return "Exit requested in ode function.";
break;
default:
return "Unrecognize error state.";
}
}

+ 93
- 0
libsimulation/lsode.h View File

@ -0,0 +1,93 @@
#if !defined (lsode_h)
#define lsode_h 1
#include "c++rocket.h"
extern int model_1(const int& neq, const double& time,
double* z, double* dy,
int& ierr);
extern int model_2(const int& neq, const double& time,
double* z, double* dy,
int& ierr);
extern "C" int lsode_ (int (*)(const int&, const double&,
double*, double*, int&),
int&, double*, double&, double&, int&,
double&, double&, int&, int&, int&,
double*, int&, int*, int&,
int (*)(const int&, const double&,
double*, const int&, const int&,
double*, const int&),
int&);
typedef int (*ModelFunc_t) (const int&, const double&,
double*, double*, int&);
class lsode
{
int memory; // est vrai si la memoire a ete alloue
// ce sont des variables utilises par lsode_
int neq;
int length;
double **dy;
double time;
double tout;
int itol;
double rtol;
double atol;
int itask;
int istate;
int iopt;
double *rwork;
int lrw;
int *iwork;
int liw;
int mf;
double *state;
void *md;
//int (*func)(const int&, const double&, double*, double*, int&)
void reset();
public:
lsode(Model_t model);
~lsode();
void print();
void set_atol(double tol) { atol = tol; }
void set_rtol(double tol) { rtol = tol; }
int solve(double *st, double duration, double step);
int get_length(void) { return length; };
void get_data(double**);
int get_neq(void) { return neq; };
};
typedef enum
{
SUCCES = 2,
TOO_MUCH_WORK = -1,
TOO_MUCH_ACC = -2,
ILLEGAL_INPUT = -3,
ERR_FAILURE = -4,
CONV_FAILURE = -5,
ERROR_WEIGHT = -6,
EXIT_IN_FUNCTION = -13
} State;
#endif

+ 234
- 0
libsimulation/modeles.cc View File

@ -0,0 +1,234 @@
/* modeles.cc - Simulation of rocket flight */
/* Copyright (C) 2000 */
/* Antoine Lefebvre <antoine.lefebvre@polymtl.ca> */
/* This program is free software; you can redistribute it and/or modify*/
/* it under the terms of the GNU General Public License as published by*/
/* the Free Software Foundation; either version 2 of the License, or */
/* (at your option) any later version. */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* You should have received a copy of the GNU General Public License */
/* along with this program; if not, write to the Free Software */
/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <cmath>
#include "simulation.h"
#include "c++rocket.h"
// modified arctan function
double Atan(double x, double y);
double coef(double v);
double T(double time);
double mass(double time);
int model_1(int neq, double time,
double *z, double *dy, int ierr);
int model_2(int neq, double time,
double* z, double* dy, int ierr);
extern simulation *simptr;
/**********************************************************************
MODEL_1: This model takes care of the principal aerodynamic effects
that takes place in a rocket flight. The mathematical relation
come from 'Mathematical theory of rocket flight' McGraw-Hill
Book company. Author are J. Barkley Rosser, Robert R. Newton,
George L. Gross.
COMMENTS: I will eventually explain the theory in some documentation
**********************************************************************/
int model_1(int neq, double time,
double *z, double *dy, int ierr)
{
//double s = z[0]; not use
double x = z[1]; // position in the x coordinate
double y = z[2]; // position in the y coordinate
double theta = z[3]; // angle about the horizontal
double phi = z[4]; // angle of the rocket axis about the horizontal
double v = z[5]; // speed
double dphi = z[6]; // first derivative of phi
double h = sqrt(pow(x,2) + pow(y,2));
double g = G*simptr->p_data[masse]/(pow(h,2));
double delta = phi - theta;
double rho = simptr->densiteatm(h - simptr->p_data[rayon]);
double drag_correction = coef(v)/0.15;
double Drag = -simptr->r_data[Kdrag]*(1+simptr->r_data[Kdd]*pow(delta,2))\
*rho*pow(simptr->r_data[Diameter],2)*pow(v,2)*drag_correction;
double Lift = simptr->r_data[Klift]*rho*pow(simptr->r_data[Diameter],2) * pow(v,2)*sin(delta - simptr->r_data[dlift]);
double Spin = simptr->r_data[Kspin]*rho*pow(simptr->r_data[Diameter],3)*v*dphi;
double Moment = -simptr->r_data[Kmoment]*rho*pow(simptr->r_data[Diameter],3)*pow(v,2)*sin(delta-simptr->r_data[dmoment]);
double Damping = -simptr->r_data[Kdamping]*rho*pow(simptr->r_data[Diameter],4)*v*dphi;
double thrust = T(time);
double dmasse = 0; // mass flow
double angle = Atan(x, y);
dy[0] = v;
dy[1] = v*cos(theta);
dy[2] = v*sin(theta);
dy[3] = (thrust* sin( delta - simptr->r_data[dt] ) - mass(time)*g*cos(theta + PI/2 - angle) + Lift + Spin*cos(delta))/(mass(time)*v); //dtheta
dy[4] = dphi;
dy[5] = (thrust*cos(delta-simptr->r_data[dt])-mass(time)*g*sin(theta+PI/2-angle) + Drag + Spin*sin(delta))/mass(time);
dy[6] = (thrust*simptr->r_data[rcm_throat]*sin(simptr->r_data[dt]) + Moment + Damping - dmasse*dphi*(simptr->r_data[rcm_throat]*simptr->r_data[rcm_exit]-pow(simptr->r_data[k],2)))/(mass(time)*pow(simptr->r_data[k],2));
return 0;
}
double Atan(double x, double y)
{
double angle;
if ((x == 0)&&(y > 0))
angle = PI/2;
else if ((x == 0)&&(y < 0))
angle = -PI/2;
else if ((x > 0))
angle = atan(y/x);
else if ((x < 0))
angle = PI + atan(y/x);
return angle;
}
// table de variation des du coefficient de frottement en
// fonction de la vitesse
// table of the drag coefficient variation with speed
//
double coef(double v)
{
static const int V[] = {0, 50, 100, 150, 200, 250, 300, 350, 400, 450,
500, 550, 600, 650, 700, 750, 800, 850, 900, 950,
1000, 1050, 1100, 1150, 1200};
static const double C[] = {0.15, 0.13, 0.125, 0.12, 0.135, 0.15, 0.2,
0.3, 0.37, 0.39, 0.38, 0.37, 0.36, 0.35, 0.34,
0.33, 0.32, 0.315, 0.31,0.305, 0.302, 0.3,
0.299, 0.298, 0.297};
if (v > 1200)
return 0.295;
else {
int b = (int)floor(v/50)+1;
return ( (C[b+1]-C[b]) / (V[b+1]-V[b]) )*(v-V[b]) + C[b];
}
}
double mass(double time)
{
double trel = 0;
double M = simptr->r_data[Mass];
if (simptr->n_prop() == 0)
return M;
for (int i = 0; i < simptr->n_prop(); i++)
M += simptr->prop[i].M(0);
if (time < simptr->ta[0])
return M;
M -= simptr->prop[0].M(0);
for (int i = 0; i < simptr->n_prop(); i++)
if (time < (simptr->tl[i]+simptr->ta[i]+simptr->prop[i].burntime+trel) )
return (M + simptr->prop[i].M(time - trel - simptr->ta[i]));
else
{
trel += simptr->ta[i] + simptr->tl[i] + simptr->prop[i].burntime;
M -= simptr->prop[i].M(0);
}
return simptr->r_data[Mass];
}
// give the thrust of the rocket in function of time, flight program and
// motor that are loaded
double T(double time)
{
double trel = 0;
if (simptr->n_prop() == 0)
return 0.0;
if (time < simptr->ta[0])
return 0.0;
for (int i = 0; i < simptr->n_prop(); i++) {
if (time < (simptr->tl[i]+simptr->ta[i]+simptr->prop[i].burntime+trel) )
return simptr->prop[i].T(time - trel - simptr->ta[i]);
else
trel += simptr->ta[i] + simptr->tl[i] + simptr->prop[i].burntime;
}
return 0.0;
}
/**********************************************************************
MODEL_2: Simple model that do not take care of aerodynamic parameter
**********************************************************************/
int model_2(int neq, double time,
double* z, double* dy, int ierr)
{
//double s = z[0];
double x = z[1];
double y = z[2];
double theta = z[3];
double v = z[4];
double h = sqrt(pow(x,2) + pow(y,2));
double g = G*simptr->p_data[masse]/(pow(h,2));
double rho = simptr->densiteatm(h - simptr->p_data[rayon]);
double drag_correction = coef(v)/0.15;
double Drag = -simptr->r_data[Kdrag]*rho*pow(simptr->r_data[Diameter],2)*pow(v,2)*drag_correction;
double thrust = T(time);
//double dmasse = 0; //mass flow
double angle = Atan(x, y);
dy[0] = v;
dy[1] = v*cos(theta);
dy[2] = v*sin(theta);
dy[3] = (thrust - mass(time)*g*cos(theta+PI/2-angle) )/(mass(time)*v); //dtheta
dy[4] = (thrust-mass(time)*g*sin(theta+PI/2-angle) + Drag )/mass(time);
return 0;
}

+ 146
- 0
libsimulation/motor.l View File

@ -0,0 +1,146 @@
/* motor.l - Simulation of rocket flight */
/* Copyright (C) 2000 */
/* Antoine Lefebvre <antoine.lefebvre@polymtl.ca> */
/* This program is free software; you can redistribute it and/or modify*/
/* it under the terms of the GNU General Public License as published by*/
/* the Free Software Foundation; either version 2 of the License, or */
/* (at your option) any later version. */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* You should have received a copy of the GNU General Public License */
/* along with this program; if not, write to the Free Software */
/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
%{
#define YY_DECL int motorscan(char *name, double *diameter, double *length, double *masse_totale, double *masse_poudre, double **thrust, int *ndata)
double P[2][200];
char bidon[32];
int foo;
int count;
int i;
int j;
int tmp1, tmp2, tmp3;
double dtmp1, dtmp2;
%}
%x body
%%
<*>#+.*\n ; /* elimination of the character #, \t, \n, space, ; */
^[ ]+ ;
<*>^\t+ ;
<*>\n ;
<INITIAL>";"+.*\n ;
01.*[ ].* {
sscanf(yytext, "%s%s%s", bidon, bidon, name);
/*printf("%s\n", name);*/
count = 0;
}
07.*[ ].* {
sscanf(yytext, "%s%s%lf", bidon, bidon, &dtmp1);
diameter[0] = dtmp1*2.54/100;
/*printf("%f\n", diameter[0]);*/
}
08.*[ ].*[ ].* {
sscanf(yytext, "%s%s%s%lf", bidon, bidon, bidon, &dtmp1);
length[0] = dtmp1*2.54/100;
/*printf("%f\n", length[0]);*/
}
11.*[ ].*[ ].*[ ].* {
sscanf(yytext, "%s%s%s%s%lf", bidon, bidon, bidon, bidon, &dtmp1);
masse_poudre[0] = dtmp1/1000;
/*printf("%f\n", masse_poudre[0]);*/
}
12.*[ ].*[ ].*[ ].* {
sscanf(yytext, "%s%s%s%s%lf", bidon, bidon, bidon, bidon, &dtmp1);
masse_totale[0] = dtmp1/1000;
/*printf("%f\n", masse_totale[0]);*/
}
20.*[ ].*[ ].*[ ].* {
sscanf(yytext, "%s%s%s%lf%lf", bidon, bidon, bidon, &P[0][count], &P[1][count]);
count++;
}
64.* {
// allocate the memory
thrust[0] = new double[count];
thrust[1] = new double[count];
ndata[0] = count;
for (j = 0; j < count; j++)
{
thrust[0][j] = P[0][j];
thrust[1][j] = P[1][j] * 4.448221615; //1lb X 9.80665 X 0.45359237 kg/lb
}
}
[0-9]{2}.*[ ].* { /*garbage all other data*/
}
[A-Z0-9]+[ ]*[0-9]+[ ]*[0-9]+[ ]*[0-9]+[ ]*[0-9]+"."[0-9]+[ ]*[0-9]+"."[0-9]+[ ]*[A-Z0-9]+[ ]* {
sscanf(yytext, "%s%d%d%d%lf%lf%s", name, &tmp1, &tmp2, &foo, masse_poudre, masse_totale, bidon);
diameter[0] = (double)tmp1/1000;
length[0] = (double)tmp2/1000;
count = 0;
BEGIN(body);
}
<body>[0-9]+"."[0-9]+[ ]*[0-9]+"."[0-9]+[ ]* {
sscanf(yytext, "%lf%lf", &P[0][count], &P[1][count]);
count++;
}
<body>";"+.*\n {
thrust[0] = new double[count];
thrust[1] = new double[count];
ndata[0] = count;
for (i = 0; i < 2; i++)
for (j = 0; j < count; j++)
thrust[i][j] = P[i][j];
BEGIN(INITIAL);
}
%%
int yywrap()
{
return 1;
}

+ 118
- 0
libsimulation/rk4.cc View File

@ -0,0 +1,118 @@
/* rk4.cc - Simulation of rocket flight */
/* Copyright (C) 2000 */
/* Antoine Lefebvre <antoine.lefebvre@polymtl.ca> */
/* This program is free software; you can redistribute it and/or modify*/
/* it under the terms of the GNU General Public License as published by*/
/* the Free Software Foundation; either version 2 of the License, or */
/* (at your option) any later version. */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* You should have received a copy of the GNU General Public License */
/* along with this program; if not, write to the Free Software */
/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdlib.h>
#include <stdio.h>
#include <cmath>
#include <iostream>
#include <fstream.h>
#include "rk4.h"
#include "c++rocket.h"
static int ModelNeq[MODEL_LAST] = { 7, 5 };
rk4_solver::rk4_solver(Model_t model)
{
neq = ModelNeq[model];
time = 0.0;
memory = 0;
switch (model)
{
case AERO_MODEL:
md = model_1;
break;
case SIMPLE_MODEL:
md = model_2;
break;
default:
exit(-1);
}
}
rk4_solver::~rk4_solver()
{
if (memory) {
for (int j = 0; j < length; j++)
delete [] ans[j];
delete ans;
}
cout << "Freeing memory...\n" ;
}
int rk4_solver::solve(double *st, double duration, double step)
{
int i;
length = (int)rint(duration/step) + 1;
// memory allocation
ans = new double*[length];
for (int j = 0; j < length; j++)
ans[j] = new double[neq];
memory = 1;
// fill the ans array
rk4 ( (ModelFunc_t)md, neq, step, duration, st, ans, NULL);
return length;
}
// print the data to screen
void rk4_solver::print()
{
for (int i = 0; i < length; i++)
{
for (int j = 0; j < neq; j++)
{
cout << ans[i][j] << "\t";
}
cout << "\n";
}
}
// export the data in filename with the format need by octave
// for the function load. It will maybe work with matlab to
// but i'm not sure
void rk4_solver::export_octave(char *filename)
{
ofstream out(filename);
out << "# Create by c++rocket" << endl;
out << "# name: M" << endl;
out << "# type: matrix" << endl;
out << "# rows: " << length << endl;
out << "# columns: " << neq << endl;
for (int i = 0; i < length; i++)
{
for (int j = 0; j < neq; j++)
{
out << ans[i][j] << " ";
}
out << endl;
}
}

+ 65
- 0
libsimulation/rk4.h View File

@ -0,0 +1,65 @@
/* rk4.h - Simulation of rocket flight */
/* Copyright (C) 2000 */
/* Antoine Lefebvre <antoine.lefebvre@polymtl.ca> */
/* This program is free software; you can redistribute it and/or modify*/
/* it under the terms of the GNU General Public License as published by*/
/* the Free Software Foundation; either version 2 of the License, or */
/* (at your option) any later version. */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* You should have received a copy of the GNU General Public License */
/* along with this program; if not, write to the Free Software */
/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#if !defined (rk4_h)
#define rk4_h 1
#include "c++rocket.h"
extern int model_1(int neq, double time,
double* z, double* dy,
int ierr);
extern int model_2(int neq, double time,
double* z, double* dy,
int ierr);
typedef int (*ModelFunc_t) (int, double,
double*, double*, int);
extern "C" int rk4( int (*f)(int neq, double time,
double *y, double *dy,
int ierr),
int neq, double step, double duration,
double *ic, double **y );
class rk4_solver
{
private:
void *md; // pointer to the model function
int memory;
double time;
int neq;
int length;
double **ans;
public:
rk4_solver(Model_t model);
~rk4_solver();
void print();
void export_octave(char *filename);
int solve(double *st, double duration, double step);
};
#endif

+ 314
- 0
libsimulation/rocket.cc View File

@ -0,0 +1,314 @@
/* cpropep.c - Calculation of Complex Chemical Equilibrium */
/* Copyright (C) 2000 */
/* Antoine Lefebvre <antoine.lefebvre@polymtl.ca> */
/* This program is free software; you can redistribute it and/or modify*/
/* it under the terms of the GNU General Public License as published by*/
/* the Free Software Foundation; either version 2 of the License, or */
/* (at your option) any later version. */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* You should have received a copy of the GNU General Public License */
/* along with this program; if not, write to the Free Software */
/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <iostream>
#include <stdio.h>
#include <cmath>
#include "c++rocket.h"
#include "rocket.h"
extern FILE* yyin; // file pointer for the file parser
// function generate by the flex lexer generator (motor.l)
extern int motorscan(char *name, double *diameter,
double *length, double *masse_totale,
double *masse_poudre, double **thrust,
int *ndata);
simulation *simptr; // this is the pointer to the active simulation
const double G = 6.67259e-11; // universal gaz constant
const double R = 8.3145; // perfect gaz constant
const double g = 9.80665; // Earth gravitational constant
// default value for the initialisation
static double rocket_default[PARA_ROCKET_LAST] = { 0.204,
2,
2.33,
20.4,
6.32,
31.6,
0,
0,
0.1143,
16,
1,
1.1,
0.229,
0 };
static double planete_default[PLANETE_DATA_LAST] = { 5.98e24,
6370000 };
static double atmosphere_default[ATM_DATA_LAST] = { 1.013e5,
0.0289644,
273.15 };
propulseur::~propulseur()
{
cout << "Destroying propulseur\n";
if (!(ndata == 0))
{
delete [] thrust[0];
delete [] thrust[1];
delete [] thrust;
}
}
int propulseur::print_data(void)
{
if (!(check()))
return -1;
cout << "Motor:\t\t\t" << name << endl;
cout << "Diameter:\t\t" << diameter << " m" << endl;
cout << "Length:\t\t" << length << " m" << endl;
cout << "Mass de propergol:\t" << masse_poudre << " Kg" << endl;
cout << "Total mass:\t\t" << masse_totale << " Kg" << endl;
//cout << ndata << endl;
cout << endl;
cout << "Time (s)\t" << "Thrust (N)" << endl;
for (int k = 0; k < ndata; k++)
cout << thrust[0][k] << "\t\t" << thrust[1][k] << endl;
return 0;
}
int propulseur::load_data(char file[32])
{
FILE *file_in = NULL;
if ((file_in = fopen(file, "r")) == NULL)
{
cout << "No such file or directory " << file << endl;
return -1;
}
yyin = file_in;
thrust = new double*[2];
motorscan(name, &diameter, &length, &masse_totale,
&masse_poudre, thrust, &ndata);
fclose(file_in);
burntime = thrust[0][ndata-1];
return 0;
}
//#ifdef WITH_GTK
//int propulseur::plot_data(void) {
// cout << "I plot the data...\n";
// return 0;
//}
//#endif
int propulseur::check(void)
{
if (ndata == 0)
{
cout << "No data loaded\n";
return -1;
}
return 1;
}
double propulseur::T(double time)
{
if (!(check()))
return 0; // no thrust
double pousse;
// there is file with no data at time 0
if (time < thrust[0][0])
return (thrust[1][0]/thrust[0][0])*time;
// after the last data, the thrust is 0
if (time > thrust[0][ndata-1])
return 0;
// linear interpolation ( should be interesting
// to add quadratic interpolation
for (int i = 1; i < ndata; i++)
if ((thrust[0][i] > time) && (thrust[0][i-1] <= time))
{
pousse = (thrust[1][i]-thrust[1][i-1])/
(thrust[0][i]-thrust[0][i-1])*(time-thrust[0][i-1]) +
thrust[1][i-1];
}
return pousse;
}
double propulseur::M(double time)
{
if (!(check()))
return 0;
if (time > burntime)
return (masse_totale - masse_poudre);
else
return (masse_totale - time*(masse_totale-masse_poudre)/burntime);
return 0;
}
double propulseur::impulse(void)
{
if (!(check()))
return -1;
double I = 0;
for (int i = 0; i < (ndata - 1); i++)
I += (thrust[1][i]+thrust[1][i+1])*(thrust[0][i+1]-thrust[0][i])/2;
return I;
}
double propulseur::favg(void)
{
if (check())
return (impulse()/burntime);
return -1;
}
double propulseur::vg(void)
{
if (check())
return impulse()/masse_poudre;
return -1;
}
double propulseur::isp(void)
{
if (check())
return vg()/g;
return -1;
}
double propulseur::propellant_mass_fraction(void)
{
if (check())
return masse_poudre/masse_totale;
return -1;
}
double propulseur::impulse_to_weight(void)
{
if (check())
return impulse()/(masse_totale*g);
return -1;
}
rocket::rocket(void)
{
nprop = 0;
r_data = rocket_default;
}
rocket::rocket(double *r)
{
nprop = 0;
for (int i = 0; i < PARA_ROCKET_LAST; i++)
r_data[i] = r[i];
}
int rocket::set_propulseurs(int stage, char file[128])
{
if (stage > MAXPROP)
return -1;
if (!(stage == 1))
if (prop[stage-2].ndata == 0) {
cout << "Stage " << stage-1 << " not loaded.\n";
return -1;
}
prop[stage-1].load_data(file);
nprop = stage;
return 0;
}
planete::planete(void)
{
p_data = planete_default;
}
planete::planete(double *p)
{
for (int i = 0; i < PLANETE_DATA_LAST; i++)
p_data[i] = p[i];
}
planete::planete(double *p, double *a) : atmosphere(a)
{
for (int i = 0; i < PLANETE_DATA_LAST; i++)
p_data[i] = p[i];
}
double planete::densiteatm(double altitude)
{
double d = (((a_data[pression_sol] * a_data[masse_molaire]) / (R*a_data[temperature]))* exp(( (a_data[masse_molaire]*G*p_data[masse])/(R*a_data[temperature]) ) * ( (1/(p_data[rayon] + altitude)) - (1/p_data[rayon]) ) ));
return d;
}
atmosphere::atmosphere(void)
{
a_data = atmosphere_default;
}
atmosphere::atmosphere(double* a)
{
for (int i = 0; i < ATM_DATA_LAST; i++)
a_data[i] = a[i];
}
flight_program::flight_program(void)
{
for (int i = 0; i < MAXPROP; i++)
{
ta[i] = 0;
tl[i] = 0;
}
}
int flight_program::set_prog(int stage, double allumage, double largage)
{
if ( (stage < 1) || (stage > MAXPROP) )
return -1;
ta[stage - 1] = allumage;
tl[stage - 1] = largage;
return 0;
}

+ 174
- 0
libsimulation/rocket.h View File

@ -0,0 +1,174 @@
/* cpropep.c - Calculation of Complex Chemical Equilibrium */
/* Copyright (C) 2000 */
/* Antoine Lefebvre <antoine.lefebvre@polymtl.ca> */
/* This program is free software; you can redistribute it and/or modify*/
/* it under the terms of the GNU General Public License as published by*/
/* the Free Software Foundation; either version 2 of the License, or */
/* (at your option) any later version. */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* You should have received a copy of the GNU General Public License */
/* along with this program; if not, write to the Free Software */
/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#if !defined (rocket_h)
#define rocket_h 1
#include <iostream>
#include "c++rocket.h"
// enumeration for data
typedef enum
{
pression_sol, // ground pressure in Pa
masse_molaire, // molar mass of the atmosphere
temperature, // temperature of the atmosphere
ATM_DATA_LAST
} AtmData;
typedef enum
{
masse, // mass of the plenet in Kg
rayon, // radius of the planet in m
PLANETE_DATA_LAST
} PlaneteData;
typedef enum
{
Kdrag, // drag coefficient
Kdd, // Kd variation with delta
Klift, // lift coefficient
Kspin, // cross-spin coefficient
Kmoment, // moment coefficient
Kdamping, // damping coefficient
dmoment, // restoring moment asymetry
dlift, // lift asymetry
Diameter, // diameter of the rocket in m
Mass, // rocket mass in kg (without booster)
rcm_throat, // distance between mass center and throat throat
rcm_exit, // distance between mass center and 'exit area'
k, // radius of geryration about a transverse axis in meter
// this field should become a function of time
dt, // angle of the thrust about the rocket axis
PARA_ROCKET_LAST
} ParaRocket;
// Classes ********************************************
class propulseur {
char name[32];
double diameter;
double length;
double masse_poudre;
double masse_totale;
double **thrust; // table of thrust in function of time
int check(void); // function to verify if there is data loaded
public:
double burntime;
int ndata; // number of point in **thrust
int load_data(char*); // char* is the file name
int print_data(void);
//#ifdef WITH_GTK
//int plot_data(void); //plot a graph of the thrust as a fonction of time
//#endif
propulseur(void) { ndata = 0; }
~propulseur(void);
double T(double time); // thrust in function of time
double M(double time); // mass in function of time
// to be verify
double impulse(void); // total impulse of the motor
double favg(void); // mean thrust of the motor
double vg(void); // gaz speed at the exit
double isp(void); // specific impulse
double propellant_mass_fraction(void);
double impulse_to_weight(void);
};
class rocket
{
int nprop; // nomber of stage
public:
char name[32]; // name of the rocket
double r_data[PARA_ROCKET_LAST];
class propulseur prop[MAXPROP];
// set a stage of the rocket (file is the path name of the data file)
int set_propulseurs(int stage, char file[128]);
int n_prop(void) { return nprop; }
rocket(void);
rocket(double *);
~rocket() { cout << "Destroying rocket\n"; }
};
class atmosphere
{
public:
double a_data[ATM_DATA_LAST];
atmosphere(void);
atmosphere(double *);
~atmosphere() { cout << "Destroying atmosphere\n";}
};
class planete : public atmosphere
{
public:
double p_data[PLANETE_DATA_LAST];
double densiteatm(double); // g/cm^3
planete(void);
planete(double *);
planete(double *planete_data, double *atm_data);
~planete() { cout << "Destroying planete\n"; }
};
class flight_program
{
public:
double ta[MAXPROP]; //temps de l'allumage (depuis le largage du précédent)
double tl[MAXPROP]; //temps du largage (après la fin de la combustion)
int set_prog(int stage, double allumage, double largage);
flight_program(void);
~flight_program(void) { }
};
#endif

+ 51
- 0
libsimulation/simulation.cc View File

@ -0,0 +1,51 @@
/* cpropep.c - Calculation of Complex Chemical Equilibrium */
/* Copyright (C) 2000 */
/* Antoine Lefebvre <antoine.lefebvre@polymtl.ca> */
/* This program is free software; you can redistribute it and/or modify*/
/* it under the terms of the GNU General Public License as published by*/
/* the Free Software Foundation; either version 2 of the License, or */
/* (at your option) any later version. */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* You should have received a copy of the GNU General Public License */
/* along with this program; if not, write to the Free Software */
/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <iostream.h>
#include "simulation.h"
//extern int model_1(const int& neq, const double& time,
// double* z, double* dy,
// int& ierr);
extern simulation *simptr;
simulation::simulation(Model_t model) : rk4_solver(model)
{
simptr = this;
sim_name = new char[128];
//model = model_1;
}
simulation::~simulation()
{
//delete rocket.prop;
delete sim_name;
cout << "Destroying simulation\n";
};

+ 74
- 0
libsimulation/simulation.h View File

@ -0,0 +1,74 @@
/* cpropep.c - Calculation of Complex Chemical Equilibrium */
/* Copyright (C) 2000 */
/* Antoine Lefebvre <antoine.lefebvre@polymtl.ca> */
/* This program is free software; you can redistribute it and/or modify*/
/* it under the terms of the GNU General Public License as published by*/
/* the Free Software Foundation; either version 2 of the License, or */
/* (at your option) any later version. */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* You should have received a copy of the GNU General Public License */
/* along with this program; if not, write to the Free Software */
/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#if !defined (simulation_h)
#define simulation_h 1
#include <iostream>
#include "c++rocket.h"
#include "rocket.h"
#include "rk4.h"
//extern int model_1(const int& neq, const double& time,
// double* z, double* dy,
// int& ierr);
class simulation : public flight_program,
public rocket,
public planete,
public rk4_solver
//public lsode
{
public:
char *sim_name;
simulation(Model_t model);
simulation(double* r, double* p, Model_t model ) :
rocket(r), planete(p), rk4_solver(model) {
cout << "Constructing simulation\n";
}
simulation(double* r, double* p, double* a, Model_t model) :
rocket(r), planete(p, a), rk4_solver(model) {
cout << "Constructing simulation\n";
}
~simulation(void);
//int model_1(const int& neq, const double& time,
// double* z, double* dy,
// int& ierr);
};
#endif

+ 348
- 0
libsimulation/simulator/.ccmalloc View File

@ -0,0 +1,348 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% generic configureation file for %%%%
%%%% the ccmalloc memory profiler %%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%-----------------------------------------------------------------%
% COPY THIS FILE TO `.ccmalloc' in your project or home directory %
%-----------------------------------------------------------------%
##############################################################################
## (C) 1997-1998 Armin Biere, 1998 Johannes Keukelaar
## $Id: .ccmalloc,v 1.1.1.1 2000/02/08 02:52:02 antoine Exp $
##############################################################################
%%% `%' and `#' are comments !!!!!!!
% This file must be called `.ccmalloc' and is searched for in the
% current directory and in the home directory of the user. If it
% does not exist then the default values mentioned below are used.
% It is also the currently only available user manual ;-) So here
% is a reading hint. First have a look at the short one line
% descriptions of each option ...
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% with `file' the executable is specified [a.out]
% ----------------------------------------------------------------------
% This should not be necessary for Linux and Solaris because the proc
% file system can be used to find argv[0].
%
% (the rest of this comment only applies to other OS)
%
% For other OS you should use this option unless the executable is
% in the current directory or its name is `a.out'.
%
% If you do not specify this then ccmalloc tries to find an executable
% in the current directory that matches the running program starting
% with `a.out'. For this process it must call `nm' on each executable
% file in the directory which may be time consuming. With this option
% you can speed up this process.
%
% You can also specify absolute or relative path names. This is
% necessary if you do not start your program from the current directory.
% But you can also simply link or name your program to `a.out'.
%file FILE
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% `log' specify the logfile [stderr]
% ----------------------------------------------------------------------
% The default is to use stderr. The argument to `log' is the name of
% the file you want to write to. It can also be `stdout' or `-' which
% sets stdout as logfile. If the logfile is stdout or stderr and is
% connected to a terminal then the output is slightly different.
%
% For big programs the logfile can be really big. To reduce the size
% you can use a small chain length (see `chain-length' below). The other
% possibility is to use compressed logfiles. This can be done by
% specifying a logfile name with a `.gz' (or a `.Z') suffix. This means
% that gnuzip (resp. compress) is used to compress the output.
log c++rocket.log
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% `logpid' specify the logfile
% ----------------------------------------------------------------------
% Can be used alternatively to the `log' command if you want to use
% ccmalloc for debugging parallel applications where several copies of
% the program you are debugging must be run simoultaneously. In this
% case you can not use `log' because you do not want to write to the same
% log file. Using `logpid' uses a file name ending with the <pid> of
% the process which means the name is unique even if several copies of
% your program are run simoultaneously.
%
% If you use the compressing suffixes then the <pid> is inserted before
% the suffix (e.g. `logpid ccmalloc.log.gz' uses `ccmalloc.log.<pid>.gz'
% as the name for the log file).
%logpid FILE
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% `dont-log-chain' skip info about certain chains []
% ----------------------------------------------------------------------
% This command may be repeated any number of times. The argument to this
% command is a comma-separated list of function-or-file-and-line
% specifications. Garbage allocated from a callchain that contains this
% subchain anywhere will _not_ be logged.
%
% The comma-separated list should not contain any spaces. E.g. not:
% main, foo, bar
% but:
% main,foo,bar
% A function-or-file-and-line specification is a string followed by an
% optional colon and number, for example: main or main:14 or main.c or
% main.c:15. Note that the string is compared with both the function and
% the file name, if available. If main.c happens to be a function name,
% that will cause a match (for that string at least).
% Not specifying a line number will match any line number. If line number
% information is not available, anything will match!
% Not specifying a name (e.g. ,,,) will match an unknown function name.
% Not giving any parameters at all, will match a chain containing at least
% one unknown function.
%
% Note that if you say
% dont-log-chain wrapper.c
% _nothing_ will be logged...
%dont-log-chain
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% `only-log-chain' skip info about other chains []
% ----------------------------------------------------------------------
% The obvious counterpart to dont-log-chain. In this case, only matching
% chains will be reported. Non-matching chains will not be reported.
% Can be repeated any number of times; if the chain matches any of the
% instances, it will be reported.
%only-log-chain
########################################################################
# #
# This is the `flag' section #
# #
# `set FLAG' is the same as `set FLAG 1' #
# #
# The default values are those set below. If `silent' is disabled #
# then you will find the banner in the log file (or it is listed on #
# stdout or stderr). The banner describes the current settings of all #
# these flags. #
# #
########################################################################
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% with `only-count' ccmalloc only counts garbage - no call chains [0]
% ----------------------------------------------------------------------
% If only-count is set to one then only one additional pointer for
% each allocated data is used and no call chain is generated. This is
% the fasted and most space efficient mode ccmalloc can operate
% in. In this mode you get at least the size of garbage produced.
%
% Note that `check-free-space' does not work at all with `only-count'
% set and over writes (`check-overwrites') are only checked when
% calling free.
%set only-count 0
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% `load-dynlibs' load dynamic linked libraries into gdb [0]
% ----------------------------------------------------------------------
% If your program is linked with dynamic libraries, function and file
% name information is not available for addresses in those libraries,
% unless you set `load-dynlibs' to 1.
%set load-dynlibs 0
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% `keep-deallocated-data' does not recycle deallocated data [0]
% ----------------------------------------------------------------------
% If you enable keep-deallocated-data then all data deallocated with
% `free' (or `delete' in C++) is not given back to the free store
% but stays associated with the call chain of its allocation. This is
% very useful if your program does multiple deallocation of the
% same data.
%set keep-deallocated-data 0
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% `check-overwrites' detect overwrites [0]
% ----------------------------------------------------------------------
% If you want to detect `off by n bytes' errors you should set
% `checking-overwrites' to n/4 (on 32-Bit machines).
%
% ccmalloc inserts a boundary above allocated data. This boundary
% consists of `check-overwrites' words. If your program writes to
% this area then ccmalloc can detect this (see also check-start
% and check-interval). `ccmalloc' also does checking for overwrites
% at non word boundaries (e.g. strcpy(malloc(strlen("hello")),"hello");)
%set check-overwrites 0
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% `check-underwrites' detect overwrites [0]
% ----------------------------------------------------------------------
% same with writes below allocated data. You do not have to set this
% option if you only want detect `off (below) by one' errors because
% ccmalloc keeps a magic value just before the user data.
%set check-overwrites 0
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% `check-free-space' can be used to find dangling pointers. [0]
% ----------------------------------------------------------------------
% A very serious type of bug is to write on data that has already been
% freed. If this happens the free space management of malloc is in
% trouble and you will perhaps encounter non deterministic behaviour of
% your program. To test this first enable `keep-deallocated-data' and
% restart your program. If the problem goes away and ccmalloc does not
% report anything then you should *also* enable `check-free-space'. Now
% ccmalloc checks already deallocated data for corruption.
%
% Note that to perform this check `keep-deallocated-data' also must
% be enabled and `only-count' disabled.
%set check-free-space 0
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% `check-interval' can be used to speed up checks [0]
% ----------------------------------------------------------------------
% If check-overwrite, check-underwrites or check-free-space is set then
% the default is to do `write checks' when data is deallocated and
% to do `free space checks' when reporting together with
% `write checks' for garbage. When you want these checks to be
% performed more often then you should set `check-interval' to a
% positive number. This number is the interval between the number of
% calls to free or malloc without performing the checks.
%set check-interval 0
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% `check-start' can be used to speed up checks [0]
% ----------------------------------------------------------------------
% The flag `check-start' delays the start of checks until the given
% number of calls to free and malloc have occured. Together with
% `check-interval' you can use a binary search to find an aproximation
% when a corruption occured! If you simply set check-interval to 1 and
% check-start to 0 then this will slow done your program too much.
%set check-start 0
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% `silent' disables banner [0]
% ----------------------------------------------------------------------
% If you don't want to see the banner of ccmalloc then set
% `silent' to 1 (f.e. when logging to stderr)
%set silent
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% `file-info' en/disables file and line number information [1]
% ----------------------------------------------------------------------
% If your program was compiled with debugging information (-g) then
% ccmalloc can generate line number and file info for call chains opening
% a pipe to gdb. For very big programs this method is slow. In this case
% you can set `file-info' to zero and you will only get the function
% names. For SunOS 4.3.1 `nm' does not `demangle' C++ identifiers
% very well. So gdb is called instead but only if `file-info' is
% not set to 0.
%set file-info 1
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% `continue' if ccmalloc aborts when something weired happened [0]
% ----------------------------------------------------------------------
% If the free function of ccmalloc is called with an argument that does
% not make sense to ccmalloc or that has already been freed then you
% probably want the program to stop at this point. This is also
% the default behaviour. But you can force ccmalloc also to ignore
% this if you set `continue' to 1. This flag also controls the behaviour
% of ccmalloc when free space is found to be corrupted or a write
% boundary has been overwritten.
%set continue 0
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% `chain-length' is the length of the maximal call chain [0 = infinite]
% ----------------------------------------------------------------------
% You can restrict the length of call chains by setting `chain-length'
% to a number greater than zero. If `chain-length' is zero (the default)
% then chains are as long as possible (on a non x86 system only call
% chains with a finite maximal length can be generated). For big
% programs especially if keep-deallocated-data is enabled this can
% reduce the size of the log file from over 100MB to several MB!
%set chain-length 0
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% `print-addresses' of data [0]
% ----------------------------------------------------------------------
% If you want to see the addresses of the allocated data (and
% deallocated data if keep-deallocated-data is set to 1) set
% `print-addresses' to 1.
%set print-addresses 0
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% `print-on-one-line' shortens log file [0]
% ----------------------------------------------------------------------
% The default is to print function names and file/line number info
% on separate lines. With `print-on-one-line' set 1 all are printed
% on one line.
%set print-on-one-line 0
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% `additional-line' enlarges readability [1]
% ----------------------------------------------------------------------
% When printing call chains an empty line is printed between to
% call points. Set `additional-line' to 0 to disable this feature.
%set additional-line 1
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% `statistics' enables more accurate profiling [0]
% ----------------------------------------------------------------------
% Calculate number of allocations and deallocations and bytes also on
% a per call chain basis. This uses 4 additional pointers for each
% call chain.
%set statistics 0
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% set order for sorting of call chains [1] [1]
% ----------------------------------------------------------------------
% When printing the report to the log file the call chains are sorted by
% default with respect to the largest accumulated garbage produced by
% that call chain. This can be changed with setting `sort-by-wasted'
% to 0. In this case they are sorted by the number of allocated bytes.
% If you want the number of allocations (only possible if `statistics'
% is enabled) as sorting criteria instead then set `sort-by-size' to 0.
%set sort-by-wasted 1
%set sort-by-size 1
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% report library chains [0]
% ----------------------------------------------------------------------
% Some external libraries (like libg++) have memory leaks. On some
% systems even a call to printf produces a leak. ccmalloc tries to
% detect this (only heuristically!) and with this flag you can control
% if leaks produced by such library calls are reported.
%
% Since version 0.2.1 some similar effect can be achieved by using
% `dont-log-chain' with no argument.
%set library-chains 0
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% print debugging information [X] (compile time dependend)
% ----------------------------------------------------------------------
%set debug X
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% align memory on 8 byte boundary [0] (no effect on SunOS or Solaris)
% ----------------------------------------------------------------------
%set align-8-byte 0

+ 35
- 0
libsimulation/simulator/Makefile View File

@ -0,0 +1,35 @@
CXX = c++
CC = gcc
CXXFLAGS = -g -Wall
CFLAG = -g -Wall
LIBS = -lm -lrocket -lnum -lcruft -lf2c -ldl
LIBDIR = -L/usr/lib -L/usr/lib/octave-2.0.14.93 -L../ -L../../libnum/
INCLUDE += -I../ -I../../libnum/
SRC = c++rocket.cc
OBJS = c++rocket.o #ccmalloc.o
PROG = c++rocket
.cc.o:
$(CXX) $(DEF) $(CXXFLAGS) $(INCLUDE) -c $*.cc -o $*.o
$(PROG): $(OBJS)
$(CXX) $(DEF) $(OBJS) $(LIBDIR) $(LIBS) -o $@
clean:
rm -f *.o *~
clean-all: clean
rm $(PROG)
.PHONY: clean

+ 78
- 0
libsimulation/simulator/c++rocket.cc View File

@ -0,0 +1,78 @@
#include <iostream>
#include <fstream.h>
#include "c++rocket.h"
#include "rocket.h"
#include "simulation.h"
//extern simulation *simptr;
int main(int argc, char *argv[]) {
simulation muty(AERO_MODEL);
simulation simple(SIMPLE_MODEL);
//simptr = &muty;
muty.set_propulseurs(1,"/home/antoine/debian/rocketsim-0.3/thrust/AEJ125.edx");
muty.set_propulseurs(2,"/home/antoine/debian/rocketsim-0.3/thrust/AEJ180T.eng");
// muty.set_propulseurs(3,"/home/antoine/debian/rocketsim-0.3/thrust/AEK250W.eng");
muty.set_prog(0,0,0);
//cout << muty.tl[2] << endl;
//simptr = &muty;
double state[7] = {0, 0, 6370000, PI/3, PI/3, 100, 0};
double state2[5] = {0, 0, 6370000, PI/3, 1000};
//lsode ode;
//int flag = ode.solve(state, 10, 0.1);
muty.solve(state, 50, 0.01);
simple.solve(state2, 1, 0.001);
// cout << simptr->prop[0].impulse() << endl;
// cout << simptr->prop[0].favg() << endl;
// cout << simptr->prop[0].vg() << endl;
// cout << simptr->prop[0].propellant_mass_fraction() << endl;
// cout << simptr->prop[0].impulse_to_weight() << endl;
// cout << simptr->prop[0].isp() << endl;
//simptr->prop[0].plot_data();
//for (int i = 0; i<MAXPROP; i++)
// simptr->prop[i].print_data();
//for (int i = 0; i < 40; i++)
// cout << mass((double)i/2) << endl;
//muty.print();
//muty.export_octave("test");
//simple.print();
//ode.print();
//simptr->print();
//cout << flag << endl;
return 0;
}

+ 11
- 0
libthermo/Makefile View File

@ -0,0 +1,11 @@
all:
@mkdir -p lib
make -C src all
clean:
@rm -rf lib
make -C src clean
deep-clean: clean
make -C src deep-clean

+ 50
- 0
libthermo/Makefile.win View File

@ -0,0 +1,50 @@
CC = bcc32
CPP32 = cpp32
LIBRARIAN = tlib
LINKER = ilink32
RC = brc32
COPT = -3 -O2 -w-8004 -w-8012 -w-8057 -IC:\borland\bcc55\include
LDOPT = -LC:\borland\bcc55\lib
INCLUDEDIR = -I..\..\libnum\ -I.
DEF = -DBORLAND
COMPAT_LIBNAME = compat.lib
CPROPEP_LIBNAME = cpropep.lib
THERMO_LIBNAME = thermo.lib
COMPAT_LIBOBJS = compat.obj getopt.obj
THERMO_LIBOBJS = load.obj thermo.obj
CPROPEP_LIBOBJS = equilibrium.obj print.obj performance.obj derivative.obj
TLIBCOMPAT = +compat.obj +getopt.obj
TLIBTHERMO = +load.obj +thermo.obj
TLIBCPROPEP = +equilibrium.obj +print.obj +performance.obj +derivative.obj
.SUFFIXES: .c
all: $(CPROPEP_LIBNAME) $(THERMO_LIBNAME) $(COMPAT_LIBNAME)
.c.obj:
$(CC) $(DEF) $(INCLUDEDIR) $(COPT) -c $*.c -o $*.obj
$(COMPAT_LIBNAME): $(COMPAT_LIBOBJS)
tlib $@ $(TLIBCOMPAT)
$(CPROPEP_LIBNAME): $(CPROPEP_LIBOBJS)
tlib $@ $(TLIBCPROPEP)
$(THERMO_LIBNAME): $(THERMO_LIBOBJS)
tlib $@ $(TLIBTHERMO)
clean:
del *.obj
del *.bak
del *.tds
deep-clean: clean
del $(COMPAT_LIBNAME)
del $(CPROPEP_LIBNAME)
del $(THERMO_LIBNAME)

+ 56
- 0
libthermo/include/load.h View File

@ -0,0 +1,56 @@
#ifndef load_h
#define load_h
/***************************************************************
FUNCTION: Load the propellant data contain in filename
PARAMETER: filename should be the path of the file containing
the information on propellant. It should be exactly
in the format of the file propellant.dat include
in the distribution.
COMMENTS: It load the information in the global variable
propellant_list[MAX_PROPELLANT] that is of type
propellant_t
AUTHOR: Antoine Lefebvre
modification bye Mark Pinese
****************************************************************/
int load_propellant(char *filename);
/***************************************************************
FUNCTION: Load the thermo data contain in filename
PARAMETER: filename should be the path of the file containing
the thermo information . It should be exactly
in the format of the file thermo.dat include
in the distribution.
COMMENTS: It load the information in the global variable
thermo_list[MAX_THERMO] that is of type
thermo_t
AUTHOR: Antoine Lefebvre
modification bye Mark Pinese
****************************************************************/
int load_thermo(char *filename);
/***************************************************************
Removes trailing ' ' in str. If str is all ' ', removes all
but the first.
str - pointer to a character array (not necessarily a string)
len - length of str.
AUTHOR: Mark Pinese
****************************************************************/
void trim_spaces(char *str, unsigned int len);
#endif

+ 218
- 0
libthermo/include/thermo.h View File

@ -0,0 +1,218 @@
#ifndef thermo_h
#define thermo_h
#include "equilibrium.h"
#include "const.h"
/* MACRO: Number of symbol in the symbol table */
#define N_SYMB 102
/***************************************************************
TYPE: Structure to hold information of species contain in the
thermo data file
****************************************************************/
typedef struct _thermo
{
char name[19];
char comments[57];
int nint; /* number of different temperature interval */
char id[7]; /* identification code */
int elem[5];
int coef[5];
state_t state;
double weight; /* molecular weight */
float heat; /* heat of formation at 298.15 K (J/mol) */
double dho; /* HO(298.15) - HO(0) */
float range[4][2]; /* temperature range */
int ncoef[4]; /* number of coefficient for Cp0/R */
int ex[4][8]; /* exponent in empirical equation */
double param[4][9];
/* for species with data at only one temperature */
/* especially condensed */
float temp;
float enth;
} thermo_t;
/***************************************************************
TYPE: Structure to hold information of species contain in the
propellant data file
****************************************************************/
typedef struct _propellant
{
char name[120]; /* name of the propellant */
int elem[6]; /* element in the molecule (atomic number) max 6 */
int coef[6]; /* stochiometric coefficient of this element
(0 for none) */
float heat; /* heat of formation in Joule/gram */
float density; /* density in g/cubic cm */
} propellant_t;
extern propellant_t *propellant_list;
extern thermo_t *thermo_list;
extern const float molar_mass[];
extern const char symb[][3];
extern unsigned long num_thermo;
extern unsigned long num_propellant;
/*************************************************************
FUNCTION: Search in the field name of thermo_list and return
the value of the found item.
PARAMETER: A string corresponding to what we search,
example: "CO2"
COMMENTS: If nothing is found, it return -1
AUTHOR: Antoine Lefebvre
modification bye Mark Pinese
**************************************************************/
int thermo_search(char *str);
int propellant_search(char *str);
int atomic_number(char *symbole);
int propellant_search_by_formula(char *str);
/*************************************************************
FUNCTION: Return the enthalpy of the molecule in thermo_list[sp]
at the temperature T in K. (Ho/RT)
PARAMETER: sp is the position in the array of the molecule
T is the temperature in K
COMMENTS: It use the parametric form explain in the documentation
to compute the value from the data read in the file
thermo.dat
AUTHOR: Antoine Lefebvre
**************************************************************/
double enthalpy_0(int sp, float T);
/*************************************************************
FUNCTION: Return the entropy of the molecule in thermo_list[sp]
at the temperature T in K. (So/RT)
PARAMETER: sp is the position in the array of the molecule
T is the temperature in K
COMMENTS: It use the parametric form explain in the documentation
to compute the value from the data read in the file
thermo.dat
AUTHOR: Antoine Lefebvre
**************************************************************/
double entropy_0(int sp, float T);
double entropy(int sp, state_t st, double ln_nj_n, float T, float P);
/*************************************************************
FUNCTION: Return the specific heat (Cp) of the molecule in
thermo_list[sp] at the temperature T in K. (Cp/RT)
PARAMETER: sp is the position in the array of the molecule
T is the temperature in K
COMMENTS: It use the parametric form explain in the documentation
to compute the value from the data read in the file
thermo.dat
AUTHOR: Antoine Lefebvre
**************************************************************/
double specific_heat_0(int sp, float T);
double mixture_specific_heat_0(equilibrium_t *e, double temp);
/*************************************************************
FUNCTION: Return true if the thermochemical data are define for
this temperature.
PARAMETER: The same as for entropy
COMMENTS: It is useful to determine if a specie is present at
a given temperature.
AUTHOR: Antoine Lefebvre
**************************************************************/
int temperature_check(int sp, float T);
double transition_temperature(int sp, float T);
/*************************************************************
FUNCTION: Return the variation of enthalpy of the molecule in
thermo_list[sp] between the temperature T in K and
298.15 K.
PARAMETER: sp is the position in the array of the molecule
T is the temperature in K
COMMENTS: It call enthalpy(...) for the enthalpy at temperature
T and use the field heat of thermo_t for the enthalpy
at 298.15
AUTHOR: Antoine Lefebvre
**************************************************************/
double delta_enthalpy(int sp, float T);
double propellant_enthalpy(equilibrium_t *e);
double product_enthalpy(equilibrium_t *e);
double product_entropy(equilibrium_t *e);
double propellant_mass(equilibrium_t *e);
int compute_density(composition_t *c);
/*************************************************************
FUNCTION: Return the gibbs free energy of the molecule in
thermo_list[sp] at temperature T. (uo/RT)
PARAMETER: sp is the position in the array of the molecule
T is the temperature in K
COMMENTS: g = H - ST where H is the enthalpy, T the temperature
and S the entropy.
**************************************************************/
double gibbs_0(int sp, float T);
/*************************************************************
FUNCTION: Return the gibbs free energy of the molecule in
thermo_list[sp] at temperature T, pressure P. (u/RT)
PARAMETER: sp is the position in the array of the molecule
T is the temperature in K
COMMENTS: g = uo + ln(nj/n) + ln(P) for gazes
g = uo for condensed
AUTHOR: Antoine Lefebvre
**************************************************************/
//double gibbs(int sp, state_t st, double nj, double n, float T, float P);
double gibbs(int sp, state_t st, double nj_n_n, float T, float P);
/***************************************************************
FUNCTION: Return the heat of formation of a propellant in kJ/mol
****************************************************************/
double heat_of_formation(int molecule);
/*************************************************************
FUNCTION: Return the molar mass of a propellant (g/mol)
PARAMETER: molecule is the number in propellant_list
**************************************************************/
double propellant_molar_mass(int molecule);
double propellant_mass(equilibrium_t *e);
#endif

+ 31
- 0
libthermo/src/Makefile View File

@ -0,0 +1,31 @@
CC = gcc
COPT = -g -Wall -O3 # -pg
ROOT = ../..
INCLUDEDIR = -I$(ROOT)/libcpropep/include \
-I$(ROOT)/libcompat/include \
-I$(ROOT)/libnum/include \
-I../include/
DEF = -DGCC
LIBNAME = libthermo.a
LIBOBJS = load.o thermo.o
all: $(LIBNAME)
.c.o:
$(CC) $(DEF) $(INCLUDEDIR) $(COPT) -c $*.c -o $*.o
$(LIBNAME): $(LIBOBJS)
ar -r $@ $(LIBOBJS)
ranlib $@
mv $(LIBNAME) ../lib/
clean:
rm -f *.o *~
deep-clean: clean
rm -f ../lib/$(LIBNAME)

+ 520
- 0
libthermo/src/load.c View File

@ -0,0 +1,520 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "equilibrium.h"
#include "load.h"
#include "thermo.h"
#include "conversion.h"
#include "return.h"
/***************************************************************************
Initial format of thermo.dat:
interval variable type size description
-----------------------------------------------------------------------------
(0, 18) name string 18 compound name
(18, 73) comments string 55 comment
(73, 75) nint int 2 the number of temperature intervals
(75, 81) id string 6 the material id
81 state int 1 0 - GAS, else CONDENSED
(82, 95) weight float 13 molecular weight
(95, 108) enth/heat float 13 enthaply if nint == 0
else heat of formation
...
rest of file
...
***************************************************************************/
int load_thermo(char *filename)
{
FILE *fd;
int i = 0;
int j, k, l;
bool ok;
char buf[88], *buf_ptr, tmp[32], *tmp_ptr;
buf_ptr = &buf[0];
tmp_ptr = &tmp[0];
/* open the file for reading */
if ((fd = fopen(filename, "r")) == NULL )
return ERR_FOPEN;
if (global_verbose)
{
printf("Scanning thermo data file...");
fflush(stdout);
}
num_thermo = 0;
/* Scan thermo.dat to find the number of positions in thermo_list
to allocate */
while (fgets(buf_ptr, 88, fd))
{
/*
All that is required is to count the number of lines not
starting with ' ', '!' or '-'
*/
if (*buf_ptr != ' ' && *buf_ptr != '!' && *buf_ptr != '-')
num_thermo++;
}
/* Reset the file pointer */
fseek(fd, 0, SEEK_SET);
if (global_verbose)
{
printf("\nScan complete. %ld records found. Allocating memory...",
num_thermo);
}
if ((thermo_list = (thermo_t *)malloc (sizeof(thermo_t) * num_thermo)) ==
NULL)
{
printf("\n\nMemory allocation error with thermo_t thermo_list[%ld], %ld bytes required", num_thermo, sizeof(thermo_t) * num_thermo);
return ERR_MALLOC;
}
if (global_verbose)
{
printf("\nSuccessful. Loading thermo data file...");
fflush(stdout);
}
for (i = 0; i < num_thermo; i++)
{
/* Read in the next line and check for EOF */
if (!fgets(buf_ptr, 88, fd))
{
fclose(fd);
free(thermo_list);
return ERR_EOF;
}
/* Skip commented lines */
while (*buf_ptr == '!')
{
if (!fgets(buf_ptr, 88, fd))
{
fclose(fd);
free(thermo_list);
return ERR_EOF;
}
}
/* Read in the name and the comments */
strncpy((thermo_list + i)->name, buf_ptr, 18);
trim_spaces((thermo_list + i)->name, 18);
strncpy((thermo_list + i)->comments, buf_ptr + 18, 55);
trim_spaces((thermo_list + i)->comments, 55);
// Read in the next line and check for EOF
if (!fgets(buf_ptr, 88, fd))
{
fclose(fd);
free(thermo_list);
return ERR_EOF;
}
strncpy(tmp_ptr, buf_ptr, 3);
(thermo_list + i)->nint = atoi(tmp_ptr);
strncpy((thermo_list + i)->id, buf_ptr + 3, 6);
trim_spaces((thermo_list + i)->id, 6);
/* get the chemical formula and coefficient */
/* grep the elements (5 max) */
for (k = 0; k < 5; k++)
{
tmp[0] = buf[k * 8 + 10];
tmp[1] = buf[k * 8 + 11];
tmp[2] = '\0';
/* Check for an empty place (no more atoms) */
if (strcmp(tmp, " "))
{
/* Atoms still to be processed */
/* find the atomic number of the element */
(thermo_list + i)->elem[k] = atomic_number(tmp);
/* And the number of atoms */
strncpy(tmp_ptr, buf_ptr + k * 8 + 13, 6);
tmp[6] = '\0';
/* Should this be an int? If so, why is it stored in x.2 format? */
(thermo_list + i)->coef[k] = (int) atof(tmp_ptr);
}
else
{
/* No atom here */
(thermo_list + i)->coef[k] = 0;
}
}
/* grep the state */
if (buf[51] == '0')
(thermo_list + i)->state = GAS;
else
(thermo_list + i)->state = CONDENSED;
/* grep the molecular weight */
strncpy(tmp_ptr, buf_ptr + 52, 13);
tmp[13] = '\0';
(thermo_list + i)->weight = atof(tmp_ptr);
/* grep the heat of formation (J/mol) or enthalpy if condensed */
/* The values are assigned in the if block following */
strncpy(tmp_ptr, buf_ptr + 65, 15);
tmp[15] = '\0';
/* now get the data */
/* there is '(thermo_list + i)->nint' set of data */
if ((thermo_list + i)->nint == 0)
{
/* Set the enthalpy */
(thermo_list + i)->enth = atof(tmp_ptr);
/* condensed phase, different info */
/* Read in the next line and check for EOF */
if (!fgets(buf_ptr, 88, fd))
{
fclose(fd);
free(thermo_list);
return ERR_EOF;
}
/* treat the line */
/* get the temperature of the assigned enthalpy */
strncpy(tmp_ptr, buf_ptr + 1, 10);
tmp[10] = '\0';
(thermo_list + i)->temp = atof(tmp_ptr);
}
else
{
/* Set the heat of formation */
(thermo_list + i)->heat = atof(tmp_ptr);
/* I'm not quite sure this is necessary */
/* if the value is 0 and this is the same substance as
the previous one but in a different state ... */
if ((thermo_list + i)->heat == 0 && i != 0)
{
ok = true;
for (j = 0; j < 5; j++)
{
/* set to the same value as the previous one if the same */
if (!((thermo_list+i)->coef[j] == (thermo_list+i-1)->coef[j] &&
(thermo_list+i)->elem[j] == (thermo_list+i-1)->elem[j]))
ok = false;
}
if (ok)
(thermo_list+i)->heat = (thermo_list+i-1)->heat;
}
for (j = 0; j < (thermo_list + i)->nint; j++)
{
/* Get the first line of three */
/* Read in the line and check for EOF */
if (!fgets(buf_ptr, 88, fd))
{
fclose(fd);
free(thermo_list);
return ERR_EOF;
}
/* low */
strncpy(tmp_ptr, buf_ptr + 1, 10);
tmp[10] = '\0';
(thermo_list + i)->range[j][0] = atof(tmp_ptr);
/* high */
strncpy(tmp_ptr, buf_ptr + 11, 10);
tmp[10] = '\0';
(thermo_list + i)->range[j][1] = atof(tmp_ptr);
tmp[0] = buf[22];
tmp[1] = '\0';
(thermo_list + i)->ncoef[j] = atoi(tmp_ptr);
/* grep the exponent */
for (l = 0; l < 8; l++)
{
strncpy(tmp_ptr, buf_ptr + l * 5 + 23, 5);
tmp[5] = '\0';
(thermo_list + i)->ex[j][l] = atoi(tmp_ptr);
}
/* HO(298.15) -HO(0) */
strncpy(tmp_ptr, buf_ptr + 65, 15);
tmp[15] = '\0';
(thermo_list + i)->dho = atof(tmp);
/* Get the second line of three */
/* Read in the line and check for EOF */
if (!fgets(buf_ptr, 88, fd))
{
fclose(fd);
free(thermo_list);
return ERR_EOF;
}
/* grep the first data line */
/* there are 5 coefficients */
for (l = 0; l < 5; l++)
{
strncpy(tmp_ptr, buf_ptr + l * 16, 16);
tmp[16] = '\0';
(thermo_list + i)->param[j][l] = atof(tmp_ptr);
//(thermo_list + i)->param[j][l] = strtod(tmp_ptr, NULL);
}
/* Get the third line of three */
/* Read in the line and check for EOF */
if (!fgets(buf_ptr, 88, fd))
{
fclose(fd);
free(thermo_list);
return ERR_EOF;
}
/* grep the second data line */
for (l = 0; l < 2; l++)
{
strncpy(tmp_ptr, buf_ptr + l * 16, 16);
tmp[16] = '\0';
(thermo_list + i)->param[j][l + 5] = atof(tmp_ptr);
}
for (l = 0; l < 2; l++)
{
strncpy(tmp_ptr, buf_ptr + l * 16 + 48, 16);
tmp[16] = '\0';
(thermo_list + i)->param[j][l + 7] = atof(tmp_ptr);
}
}
}
}
fclose(fd);
if (global_verbose)
printf("%d species loaded.\n", i);
return i;
}
int load_propellant(char *filename)
{
FILE *fd;
int i = 0, j, len, name_start, name_end, name_len;
/* temporary string to store string in order to treat the informations */
char buf[88], *buf_ptr, tmp[70], *tmp_ptr;
buf_ptr = &buf[0];
tmp_ptr = &tmp[0];
/* open the file for reading */
if ((fd = fopen(filename, "r")) == NULL )
return ERR_FOPEN;
if (global_verbose)
{
printf("Scanning propellant data file...");
fflush(stdout);
}
num_propellant = 0;
/* Scan propellant.dat to find the number of positions in propellant_list
to allocate */
while (fgets(buf_ptr, 88, fd))
{
/* All that is required is to count the number of lines not starting
with '*' or '+' */
if (*buf_ptr != '*' && *buf_ptr != '+')
num_propellant++;
}
/* Reset the file pointer */
fseek(fd, 0, SEEK_SET);
if (global_verbose)
{
printf("\nScan complete. %ld records found. Allocating memory...",
num_propellant);
fflush(stdout);
}
if ((propellant_list = (propellant_t *) malloc(sizeof(propellant_t) *
num_propellant)) == NULL)
{
printf ("\n\nMemory allocation error with propellant_t propellant_list[%ld], %ld bytes required", num_propellant, sizeof(propellant_t) * num_propellant);
return ERR_MALLOC;
}
if (global_verbose)
{
printf("\nSuccessful. Loading propellant data file...");
fflush(stdout);
}
if (!fgets(buf_ptr, 88, fd))
{
fclose(fd);
free(propellant_list);
return ERR_EOF;
}
for (i = 0; i < num_propellant; i++)
{
/* Skip commented code */
do
{
if (!fgets(buf_ptr, 88, fd))
{
fclose(fd);
free(propellant_list);
return ERR_EOF;
}
}
while (*buf_ptr == '*');
/* Check for a continued name */
while (*buf_ptr == '+')
{
/* A continued name found */
strncpy(tmp_ptr, buf_ptr + 9, 70);
/* Find the end of the whitespaces. name_start + 1 is used to leave
one space. */
for (name_start = 0; name_start < 70; name_start++)
{
if (*(tmp_ptr + name_start + 1) != ' ')
break;
}
/* Find the end of the name. > 0 is used to be consistent with the
one space left */
/* when finding name_start */
for (name_end = 69; name_end > 0; name_end--)
{
if (*(tmp_ptr + name_end) != ' ')
break;
}
name_len = name_end - name_start + 1;
len = strlen((propellant_list + i - 1)->name);
/* Check for room in the destination string. Take into account
the possibility of a
multiple line continuation
TODO - > 120 or >= 120 */
if (len + name_len >= 120)
{
/* Not enough room - copy as much as possible and leave the
name alone */
strncpy((propellant_list + i - 1)->name + len,
tmp_ptr + name_start, 119 - len);
*((propellant_list + i - 1)->name + 119) = '\x0';
}
else
{
/* Concatenate the entire string */
strncpy((propellant_list + i - 1)->name + len,
tmp_ptr + name_start, name_len);
*((propellant_list + i - 1)->name + len + name_len) = '\x0';
}
/* Processing of this line is done, so get the next one */
if (!fgets(buf_ptr, 88, fd))
{
fclose(fd);
free(propellant_list);
return ERR_EOF;
}
}
/* grep the name */
strncpy((propellant_list + i)->name, buf_ptr + 9, 30);
trim_spaces((propellant_list + i)->name, 30);
for (j = 0; j < 6; j++)
{
tmp[0] = buf[j * 5 + 39];
tmp[1] = buf[j * 5 + 40];
tmp[2] = buf[j * 5 + 41];
tmp[3] = '\0';
(propellant_list + i)->coef[j] = atoi(tmp);
tmp[0] = buf[j * 5 + 42];
tmp[1] = buf[j * 5 + 43];
tmp[2] = '\0';
/* find the atomic number of the element */
/*
for (k = 0; k < N_SYMB; k++)
{
if (!(strcmp(tmp, symb[k])))
{
(propellant_list + i)->elem[j] = k;
break;
}
}
*/
(propellant_list + i)->elem[j] = atomic_number(tmp);
}
strncpy(tmp_ptr, buf_ptr + 69, 5);
tmp[5] = '\0';
propellant_list[i].heat = atof(tmp) * CAL_TO_JOULE;
strncpy(tmp_ptr, buf_ptr + 75, 5);
tmp[5] = '\0';
propellant_list[i].density = atof(tmp) * LBS_IN3_TO_G_CM3;
}
fclose(fd);
if (global_verbose)
printf("%d species loaded.\n", i);
return i;
}
void trim_spaces(char *str, unsigned int len)
{
unsigned int i;
for (i = len - 1; i > 0; i--)
{
if (*(str + i) != ' ' && *(str + i) != '\t')
{
*(str + i + 1) = '\0';
return;
}
}
*(str + 1) = '\0';
}

+ 563
- 0
libthermo/src/thermo.c View File

@ -0,0 +1,563 @@
/* thermo.c - Compute thermodynamic properties of individual
species and composition of species */
/* $Id: thermo.c,v 1.2 2001/02/22 19:48:44 antoine Exp $ */
/* Copyright (C) 2000 */
/* Antoine Lefebvre <antoine.lefebvre@polymtl.ca> */
/* Mark Pinese <pinese@cyberwizards.com.au> */
/* */
/* Licensed under the GPLv2 */
#include <math.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include "thermo.h"
#include "compat.h"
#include "conversion.h"
/**************************************************************
These variables hold the number of records for propellant and thermo data
***************************************************************/
unsigned long num_propellant, num_thermo;
/* global variable containing the information about chemical species */
propellant_t *propellant_list;
thermo_t *thermo_list;
/****************************************************************
VARIABLE: Contain the molar mass of element by atomic number
molar_mass[0] contain hydrogen and so on.
Data come from Sargent-Welch 1996
*****************************************************************/
const float molar_mass[N_SYMB] = {
1.00794, 4.002602, 6.941, 9.012182, 10.811, 12.0107,
14.00674, 15.9994, 18.9984032, 20.11797, 22.989770, 24.305,
26.981538, 28.0855, 30.973761, 32.066, 35.4527, 39.948,
39.0983, 40.078, 44.95591, 47.88, 50.9415, 51.996,
54.938, 55.847, 58.9332, 58.6934, 63.546, 65.39,
69.723, 72.61, 74.9216, 78.96, 79.904, 83.80,
85.4678, 87.62, 88.9059, 91.224, 92.9064, 95.94,
98.0, 101.07, 102.9055, 106.42, 107.868, 112.41,
114.82, 118.71, 121.757, 127.60, 126.9045, 131.29,
132.9054, 137.33, 138.9055, 140.12, 140.9077, 144.24,
145., 150.36, 151.965, 157.25, 158.9253, 162.50,
164.9303, 167.26, 168.9342, 173.04, 174.967, 178.49,
180.9479, 183.85, 186.207, 190.2, 192.22, 195.08,
196.9665, 200.59, 204.383, 207.2, 208.9804, 209.,
210., 222., 223., 226.0254, 227., 232.0381,
231.0359, 238.029, 237.0482, 244., 12.011, 9.01218,
10.811, 24.305, 26.98154, 257.0, 0, 2};
/****************************************************************
VARIABLE: Contain the symbol of the element in the same way as
for the molar mass.
COMMENTS: It is use in the loading of the data file to recognize
the chemical formula.
*****************************************************************/
const char symb[N_SYMB][3] = {
"H ","HE","LI","BE","B ","C ","N ","O ",
"F ","NE","NA","MG","AL","SI","P ","S ","CL","AR","K ","CA",
"SC","TI","V ","CR","MN","FE","CO","NI","CU","ZN","GA","GE",
"AS","SE","BR","KR","RB","SR","Y ","ZR","NB","MO","TC","RU",
"RH","PD","AG","CD","IN","SN","SB","TE","I ","XE","CS","BA",
"LA","CE","PR","ND","PM","SM","EU","GD","TB","DY","HO","ER",
"TM","YB","LU","HF","TA","W ","RE","OS","IR","PT","AU","HG","TL",
"PB","BI","PO","AT","RN","FR","RA","AC","TH","PA","U ","NP",
"U6","U5","U1","U2","U3","U4","FM",
"E ", "D " }; /* the E stand for electron and D for deuterium*/
/* Enthalpy in the standard state (Dimensionless) */
double enthalpy_0(int sp, float T)
{
thermo_t *s = (thermo_list + sp);
double val;
int pos = 0, i;
if (T < s->range[0][0]) /* Temperature below the lower range */
{
pos = 0;
} /*Temperature above the higher range */
else if (T >= s->range[s->nint-1][1])
{
pos = s->nint - 1;
}
else
{
for (i = 0; i < s->nint; i++) /* Find the range */
{
if ((T >= s->range[i][0]) && (T < s->range[i][1]))
pos = i;
}
}
/* parametric equation for dimentionless enthalpy */
val = -s->param[pos][0]*pow(T, -2) + s->param[pos][1]*pow(T, -1)*log(T)
+ s->param[pos][2] + s->param[pos][3]*T/2 + s->param[pos][4]*pow(T, 2)/3
+ s->param[pos][5]*pow(T, 3)/4 + s->param[pos][6]*pow(T, 4)/5
+ s->param[pos][7]/T;
return val; /* dimensionless enthalpy */
}
/* Entropy in the standard state (Dimensionless)*/
double entropy_0(int sp, float T)
{
thermo_t *s = (thermo_list + sp);
double val;
int pos = 0, i;
if (T < s->range[0][0])
{
pos = 0;
}
else if (T >= s->range[s->nint-1][1])
{
pos = s->nint - 1;
}
else
{
for (i = 0; i < s->nint; i++)
{
if ((T >= s->range[i][0]) && (T < s->range[i][1]))
pos = i;
}
}
/* parametric equation for dimentionless entropy */
val = -s->param[pos][0]*pow(T, -2)/2 - s->param[pos][1]*pow(T, -1)
+ s->param[pos][2]*log(T) + s->param[pos][3]*T
+ s->param[pos][4]*pow(T, 2)/2
+ s->param[pos][5]*pow(T, 3)/3 + s->param[pos][6]*pow(T, 4)/4
+ s->param[pos][8];
return val;
}
/* Specific heat in the standard state (Dimensionless) */
double specific_heat_0(int sp, float T)
{
thermo_t *s = (thermo_list + sp);
double val;
int pos = 0, i;
if (T < s->range[0][0])
{
pos = 0;
}
else if (T >= s->range[s->nint-1][1])
{
pos = s->nint - 1;
}
else
{
for (i = 0; i < s->nint; i++)
{
if ((T >= s->range[i][0]) && (T < s->range[i][1]))
pos = i;
}
}
/* parametric equation for dimentionless specific_heat */
val = s->param[pos][0]*pow(T, -2) + s->param[pos][1]*pow(T, -1)
+ s->param[pos][2] + s->param[pos][3]*T + s->param[pos][4]*pow(T, 2)
+ s->param[pos][5]*pow(T, 3) + s->param[pos][6]*pow(T, 4);
return val;
}
/* Dimensionless Gibbs free energy in the standard state */
double gibbs_0(int sp, float T)
{
return enthalpy_0(sp, T) - entropy_0(sp, T); /* dimensionless */
}
/* Check if the species is in its range of definition
0 if out of range, 1 if ok */
int temperature_check(int sp, float T)
{
thermo_t *s = (thermo_list + sp);
if ((T > s->range[s->nint-1][1]) || (T < s->range[0][0]))
return 0;
return 1;
}
/* This function return the transition temperature of the species
considered which is nearest of the temperature T */
double transition_temperature(int sp, float T)
{
thermo_t *s = (thermo_list + sp);
/* first assume that the lowest temperature is the good one */
double transition_T = s->range[0][0];
/* verify if we did the good bet */
if (fabs(transition_T - T) > fabs(s->range[s->nint-1][1] - T))
{
transition_T = s->range[s->nint-1][1];
}
return transition_T;
}
double entropy(int sp, state_t st, double ln_nj_n, float T, float P)
{
double s;
switch (st)
{
case GAS:
/* The thermodynamic data are based on a standard state pressure
of 1 bar (10^5 Pa) */
s = entropy_0(sp, T) - ln_nj_n - log(P * ATM_TO_BAR);
break;
case CONDENSED:
s = entropy_0(sp, T);
break;
default:
s = 0;
}
return s;
}
/* J/mol T is in K, P is in atm */
double gibbs(int sp, state_t st, double ln_nj_n, float T, float P)
{
double g;
switch (st)
{
case GAS:
g = gibbs_0(sp, T) + ln_nj_n + log(P * ATM_TO_BAR);
break;
case CONDENSED:
g = gibbs_0(sp, T);
break;
default:
g = 0;
}
return g;
}
double propellant_molar_mass(int molecule)
{
int i = 0, coef;
double ans = 0;
while ((coef = (propellant_list + molecule)->coef[i]))
{
ans += coef * molar_mass[(propellant_list + molecule)->elem[i]];
i++;
}
return ans;
}
/* J/mol */
double heat_of_formation(int molecule)
{
double hf = (propellant_list + molecule)->heat *
propellant_molar_mass(molecule);
return hf;
}
/* should not be in thermo.c */
double propellant_enthalpy(equilibrium_t *e)
{
int i;
double h = 0.0;
for (i = 0; i < e->propellant.ncomp; i++)
{
h += e->propellant.coef[i] * heat_of_formation (e->propellant.molecule[i])
/ propellant_mass (e);
}
return h;
}
/* should not be in thermo.c */
double product_enthalpy(equilibrium_t *e)
{
int i;
double h = 0.0;
for (i = 0; i < e->product.n[GAS]; i++)
{
h += e->product.coef[GAS][i] * enthalpy_0(e->product.species[GAS][i], e->properties.T);
}
for (i = 0; i < e->product.n[CONDENSED]; i++)
{
h += e->product.coef[CONDENSED][i] * enthalpy_0(e->product.species[CONDENSED][i], e->properties.T);
}
return h;
}
/* should not be in thermo.c */
double product_entropy(equilibrium_t *e)
{
int i;
double ent = 0.0;
for (i = 0; i < e->product.n[GAS]; i++)
{
ent += e->product.coef[GAS][i]*entropy(e->product.species[GAS][i], GAS,
e->itn.ln_nj[i] - e->itn.ln_n,
e->properties.T, e->properties.P);
}
for (i = 0; i < e->product.n[CONDENSED]; i++)
{
ent += e->product.coef[CONDENSED][i]*entropy(e->product.species[CONDENSED][i],
CONDENSED, 0, e->properties.T, e->properties.P);
}
return ent;
}
/* should not be in thermo.c */
/* The specific heat of the mixture for frozen performance */
double mixture_specific_heat_0(equilibrium_t *e, double temp)
{
int i;
double cp = 0.0;
/* for gases */
for (i = 0; i < e->product.n[GAS]; i++)
{
cp += e->product.coef[GAS][i]*specific_heat_0(e->product.species[GAS][i], temp);
}
/* for condensed */
for (i = 0; i < e->product.n[CONDENSED]; i++)
{
cp += e->product.coef[CONDENSED][i]*
specific_heat_0(e->product.species[CONDENSED][i], temp);
}
return cp;
}
int thermo_search(char *str)
{
int i;
int last = -1;
for (i = 0; i < num_thermo; i++)
{
if (!(STRNCASECMP(str, (thermo_list + i)->name, strlen(str))))
{
last = i;
printf("%-5d %s\n", i, (thermo_list + i)->name);
}
}
return last;
}
int propellant_search(char *str)
{
int i;
int last = -1;
for (i = 0; i < num_propellant; i++)
{
if (!(STRNCASECMP(str, (propellant_list + i)->name, strlen(str))))
{
last = i;
printf("%-5d %s\n", i, (propellant_list + i)->name);
}
}
return last;
}
int atomic_number(char *symbole)
{
int i;
int element = -1;
/* find the atomic number of the element */
for (i = 0; i < N_SYMB; i++)
{
if (!STRCASECMP(symbole, symb[i]))
{
element = i;
break;
}
}
return element;
}
int compute_density(composition_t *c)
{
short i;
double mass = 0;
c->density = 0.0;
for (i = 0; i < c->ncomp; i++)
{
mass += c->coef[i] * propellant_molar_mass(c->molecule[i]);
}
for (i = 0; i < c->ncomp; i++)
{
if ((propellant_list + c->molecule[i])->density != 0.0)
{
c->density += c->coef[i] * propellant_molar_mass(c->molecule[i])
/ (mass * (propellant_list + c->molecule[i])->density);
}
}
if (c->density != 0.0)
{
c->density = 1/c->density;
}
return 0;
}
/* This fonction return the offset of the molecule in the propellant_list
the argument is the chemical formula of the molecule */
int propellant_search_by_formula(char *str)
{
int i = 0, j ;
char tmp[5];
char *ptr;
int elem[6] = {0, 0, 0, 0, 0, 1};
int coef[6] = {0, 0, 0, 0, 0, 0};
int molecule = -1;
ptr = str; /* beginning of the string */
while ( (i < 6) && ((ptr - str) < strlen(str)) )
{
if (isupper(*ptr) && islower(*(ptr+1)) && (isupper(*(ptr+2)) ||
iscntrl(*(ptr+2))) )
{
tmp[0] = *ptr;
tmp[1] = toupper(*(ptr+1));
tmp[2] = '\0';
/* find the atomic number of the element */
elem[i] = atomic_number(tmp);
coef[i] = 1;
i++;
ptr += 2;
}
else if (isupper(*ptr) && (isupper(*(ptr+1)) ||
iscntrl(*(ptr+1))) )
{
tmp[0] = *ptr;
tmp[1] = ' ';
tmp[2] = '\0';
elem[i] = atomic_number(tmp);
coef[i] = 1;
i++;
ptr++;
}
else if (isupper(*ptr) && isdigit(*(ptr+1)))
{
tmp[0] = *ptr;
tmp[1] = ' ';
tmp[2] = '\0';
elem[i] = atomic_number(tmp);
j = 0;
do
{
tmp[j] = *(ptr + 1 + j);
j++;
} while (isdigit(*(ptr + 1 + j)));
tmp[j] = '\0';
coef[i] = atoi(tmp);
i++;
ptr = ptr + j + 1;
}
else if (isupper(*ptr) && islower(*(ptr+1)) && isdigit(*(ptr+2)))
{
tmp[0] = *ptr;
tmp[1] = toupper(*(ptr+1));
tmp[2] = '\0';
elem[i] = atomic_number(tmp);
j = 0;
while (isdigit(*(ptr + 2 + j)))
{
tmp[j] = *(ptr + 1 + j);
j++;
}
tmp[j] = '\0';
coef[i] = atoi(tmp);
i++;
ptr = ptr + j + 2;
}
}
/*
for (i = 0; i < 6; i++)
{
if (elem[i] != -1)
printf("%s %d\n", symb[elem[i]], coef[i]);
}
*/
for (i = 0; i < num_propellant; i++)
{
for (j = 0; j < 6; j++)
{
/* set to the same value as the previous one if the same */
if (!( ((propellant_list+i)->coef[j] == coef[j]) &&
((propellant_list+i)->elem[j] == elem[j]) ))
break;
}
/* Now search in propellant list for this molecule */
/*
for (j = 0; j < num_propellant; j++)
{
for (i = 0; i < 6; i++)
{
if ( (coef[i] != propellant_element_coef(elem[i], j)) &&
(propellant_list + i)
break;
}
*/
if (j == 5) /* we found the molecule ! */
{
/* check if the inverse is true */
molecule = i;
break;
}
}
return molecule;
}
/* Mass of propellant in gram */
double propellant_mass(equilibrium_t *e)
{
int i;
double mass = 0.0;
for (i = 0; i < e->propellant.ncomp; i++)
{
mass += e->propellant.coef[i] *
propellant_molar_mass(e->propellant.molecule[i]);
}
return mass;
}

+ 9
- 0
prop/Makefile View File

@ -0,0 +1,9 @@
all:
make -C src all
clean:
make -C src clean
deep-clean: clean
make -C src deep-clean

+ 38
- 0
prop/Makefile.win View File

@ -0,0 +1,38 @@
CC = bcc32
CPP32 = cpp32
LIBRARIAN = tlib
LINKER = ilink32
RC = brc32
COPT = -3 -O2 -w-8012 -w-8004 -w-8057 -IC:\borland\bcc55\include
LDOPT = -LC:\borland\bcc55\lib
LIB = compat.lib thermo.lib
LIBDIR = -L..\lib\
IDIR = -I..\lib\
DEF = -DBORLAND
PROG = prop.exe
OBJS = prop.obj getopt.obj
.SUFFIXES: .c
all: $(PROG)
.c.obj:
$(CC) $(DEF) $(COPT) $(IDIR) -c $*.c -o $*.obj
$(PROG): $(OBJS)
$(CC) $(LDOPT) $(LIBDIR) $(LIB) $(OBJS)
clean:
del *.obj
del *.bak
del *.tds
deep-clean: clean
del $(PROG)

+ 36
- 0
prop/src/Makefile View File

@ -0,0 +1,36 @@
CC = gcc
COPT = -g -Wall -O3 #-pg
LIB = -lthermo -lm
ROOT = ../..
LIBDIR = -L$(ROOT)/libnum/lib/ \
-L$(ROOT)/libthermo/lib/
INCDIR = -I$(ROOT)/libnum/include/ \
-I$(ROOT)/libcompat/include/ \
-I$(ROOT)/libcpropep/include/ \
-I$(ROOT)/libthermo/include/
DEF = -DGCC
PROG = prop
OBJS = prop.o
.SUFFIXES: .c
all: $(PROG)
.c.o:
$(CC) $(DEF) $(INCDIR) $(COPT) -c $*.c -o $*.o
$(PROG): $(OBJS)
$(CC) $(COPT) $(OBJS) $(LIBDIR) $(LIB) -o $@
clean:
rm -f *.o *~ *.m
deep-clean: clean
rm -f $(PROG)

+ 334
- 0
prop/src/plot.c View File

@ -0,0 +1,334 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "thermo.h"
#include "load.h"
int global_verbose = 0;
#define MAX_MOL 100
typedef enum _unit_
{
DIMENSIONLESS,
SPECIFIC,
MOLAR
} units_t;
typedef struct _prop_
{
char symb[3];
char unit_1[12];
char unit_2[12];
char title[24];
double (*f)(int n, double T);
} prop_t;
typedef enum _value_
{
CP = 0,
H = 1,
U = 2,
S = 3
} value_t;
double SpecificHeat(int n, double T);
double Enthalpy(int n, double T);
double InternalEnergy(int n, double T);
double Entropy(int n, double T);
prop_t properties[] = {
{"cp", "Cp/R", "kJ/%s-K", "Specific Heat (Cp)", SpecificHeat},
{"h", "H/RT", "kJ/%s", "Enthalpy", Enthalpy},
{"u", "U/RT", "kJ/%s", "Internal Energy", InternalEnergy},
{"s", "S/R", "kJ/%s-K", "Entropy", Entropy},
{"\0", "\0", "\0", "\0", NULL}
};
double SpecificHeat(int n, double T)
{
return specific_heat_0(n, T);
}
double Enthalpy(int n, double T)
{
return enthalpy_0(n, T) -
((thermo_list + n)->heat - (thermo_list + n)->dho)/(R*T);
}
double InternalEnergy(int n, double T)
{
return (enthalpy_0(n, T) - ((thermo_list + n)->heat -
(thermo_list + n)->dho)/(R*T) - 1);
}
double Entropy(int n, double T)
{
return entropy_0(n, T);
}
int main(int argc, char *argv[])
{
FILE *fdres;
FILE *fdplot;
double T;
int i, c, n;
int num_mol;
int mol[MAX_MOL];
char thermo_file[FILENAME_MAX] = "../data/thermo.dat";
char propellant_file[FILENAME_MAX] = "../data/propellant.dat";
value_t val;
units_t units;
double Ti, Tf, step;
char temp[128];
char *ptr;
char *token;
char *running;
bool _molec = false;
bool _value = false;
bool _units = false;
bool _range = false;
if (load_thermo (thermo_file) < 0)
{
printf("Error loading thermo data file: %s\n", thermo_file);
return -1;
}
if (load_propellant (propellant_file) < 0)
{
printf("Error loading propellant file: %s\n", propellant_file);
return -1;
}
if ((fdres = fopen("result.m", "w")) == NULL)
{
printf("Error opening file.\n");
return -1;
}
if ((fdplot = fopen("plotres.m", "w")) == NULL)
{
printf("Error opening file.\n");
return -1;
}
num_mol = 0;
while (1)
{
c = getopt(argc, argv, "m:p:u:T:");
if (c == EOF)
break;
switch (c)
{
/* the output file */
case 'm':
/* duplicate the string */
if ((running = strdup(optarg)) == NULL)
{
printf("Not enough memory.\n");
return -1;
}
ptr = running;
token = strsep(&running, "-");
/* get each molecule */
while (token != NULL)
{
mol[num_mol] = atoi(token);
num_mol++;
token = strsep(&running, "-");
}
free(ptr);
_molec = true;
break;
case 'p':
if (strcmp(optarg, "cp") == 0)
val = CP;
else if (strcmp(optarg, "h") == 0)
val = H;
else if (strcmp(optarg, "u") == 0)
val = U;
else if (strcmp(optarg, "s") == 0)
val = S;
else
{
printf("Unknown properties: %s\n", optarg);
break;
}
_value = true;
break;
case 'u':
if (strcmp(optarg, "dimensionless") == 0)
units = DIMENSIONLESS;
else if (strcmp(optarg, "specific") == 0)
units = SPECIFIC;
else if (strcmp(optarg, "molar") == 0)
units = MOLAR;
else
{
printf("Unknown units: %s\n", optarg);
break;
}
_units = true;
break;
case 'T':
/* duplicate the string */
if ((running = strdup(optarg)) == NULL)
{
printf("Not enough memory.\n");
return -1;
}
ptr = running;
if ((token = strsep(&running, ":")) == NULL)
{
printf("Not enought arguments to temperature.\n");
break;
}
Ti = atof(token);
if ((token = strsep(&running, ":")) == NULL)
{
printf("Not enought arguments to temperature.\n");
break;
}
step = atof(token);
if ((token = strsep(&running, ":")) == NULL)
{
printf("Not enought arguments to temperature.\n");
break;
}
Tf = atof(token);
free(ptr);
_range = true;
break;
}
}
/*
for (i = 0; i < num_mol; i++)
{
printf("%d\n", mol[i]);
}
printf("%d\n", val);
printf("%d\n", units);
printf("%f - %f - %f\n", Ti, step, Tf);
return 0;
*/
if (!(_molec == _value == _units == _range == true))
{
printf("Missing arguments. Aborted.\n");
return -1;
}
fprintf(fdplot, "result;\n");
fprintf(fdplot, "hold on;\n");
fprintf(fdplot, "gset grid\n");
fprintf(fdplot, "gset title \"%s as a function of Temperature in the standard state\"\n",
properties[val].title);
fprintf(fdplot, "gset xlabel \"Temperature (K)\"\n");
if (units == DIMENSIONLESS)
{
fprintf(fdplot, "gset ylabel \"%s\"\n", properties[val].unit_1);
}
else
{
sprintf(temp, "gset ylabel \"%s\"\n", properties[val].unit_2);
if (units == SPECIFIC)
{
fprintf(fdplot, temp, "kg");
}
else
{
fprintf(fdplot, temp, "mol");
}
}
for (i = 0; i < num_mol; i++)
{
n = mol[i];
fprintf(fdres, "M%d = [\n", n);
fprintf(fdplot, "plot(M%d(:,1),M%d(:,2), ';%s;')\n", n, n,
(thermo_list + n)->name);
switch (units)
{
case DIMENSIONLESS:
for (T = Ti; T < Tf; T += step)
{
fprintf(fdres, "%.1f, %.3f,\n", T, properties[val].f(n, T));
}
break;
case SPECIFIC:
if ((val == CP) || (val == S))
{
for (T = Ti; T < Tf; T += step)
{
fprintf(fdres, "%.1f, %.3f,\n", T,
properties[val].f(n, T)*R/(thermo_list + n)->weight);
}
}
else
{
for (T = Ti; T < Tf; T += step)
{
fprintf(fdres, "%.1f, %.3f,\n", T,
properties[val].f(n, T)*R*T/(thermo_list + n)->weight);
}
}
break;
case MOLAR:
if ((val == CP) || (val == S))
{
for (T = Ti; T < Tf; T += step)
{
fprintf(fdres, "%.1f, %.3f,\n", T, properties[val].f(n, T)*R);
}
}
else
{
for (T = Ti; T < Tf; T += step)
{
fprintf(fdres, "%.1f, %.3f,\n", T, properties[val].f(n, T)*R*T);
}
}
break;
}
fprintf(fdres, "];\n");
}
fclose(fdres);
fclose(fdplot);
return 0;
}

+ 611
- 0
prop/src/prop.c View File

@ -0,0 +1,611 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#ifdef GCC
#include <unistd.h>
#else
#include "getopt.h"
#endif
#include "thermo.h"
#include "load.h"
#define MAX_LINE 500
#define ARG_LENGTH 32
#define PROMPT "PROP>"
#define VERSION "1.0"
/* Dimensionless Enthalpy */
#define ENTHALPY(n, T) (enthalpy_0(n, T) - ((thermo_list + n)->heat -\
(thermo_list + n)->dho)/(R*T))
/* Dimensionless Entropy */
#define ENTROPY(n, T) entropy_0(n, T)
/* Dimensionless Internal Energy */
#define INTERNAL_ENERGY(n, T) (enthalpy_0(n, T) - ((thermo_list + n)->heat -\
(thermo_list + n)->dho)/(R*T) - 1)
/* Dimensionless Specific Heat */
#define SPECIFIC_HEAT(n, T) specific_heat_0(n, T)
/* Dimensionless gibbs function */
#define GIBBS(n, T) gibbs_0(n, T)
#define MOLAR_MASS(n) (thermo_list + n)->weight
#define NAME(n) (thermo_list + n)->name
int global_verbose = 0;
typedef struct _command_
{
char name[64];
int num_arg;
void (*function)(char **arg);
char description[512];
char syntax[256];
} command_t;
void help(char **arg);
void molarMass(char **arg);
void Entropy(char **arg);
void Gibbs(char **arg);
void Enthalpy(char **arg);
void Specific_heat(char **arg);
void Internal_energy(char **arg);
void Properties(char **arg);
void List(char **arg);
void Info(char **arg);
int converti(char *string, unsigned int *number);
int convertd(char *string, double *number);
command_t command_list[] = {
{"properties", 2, (void*)Properties,
"All properties.\n", "<molecule> <temp>"},
{"enthalpy", 2, (void*)Enthalpy,
"Enthalpy.\n", "<molecule> <temp>"},
{"internal_energy", 2, (void*)Internal_energy,
"Internal energy.\n", "<molecule> <temp>"},
{"entropy", 2, (void*)Entropy,
"Entropy.\n", "<molucule> <temp>"},
{"specific_heat", 2, (void*)Specific_heat,
"Specific heat (Cp).\n", "<molecule> <temp>"},
{"gibbs", 2, (void*)Gibbs,
"Gibbs free energy.\n", "<molecule> <temp>"},
{"molar_mass", 1, (void*)molarMass,
"Molar mass.\n", "<molucule>"},
{"info", 1, (void*)Info,
"Reference information.\n", "<molecule>"},
{"list", 1, (void*)List,
"List molecule code beginning by formula.\n", "<formula>"},
{"quit", 0, (void*)exit, "Exit the program.\n", ""},
{"bye", 0, (void*)exit, "Exit the program.\n", ""},
{"exit", 0, (void*)exit, "Exit the program.\n", ""},
{"help", 0, (void*)help, "Display help message.\n", ""},
{"\0", 0, NULL, "\0"}
};
void help(char **arg)
{
int i = 0;
printf("\n");
printf("%-36s %s\n", "Command", "Description");
printf("%-36s %s\n", "-------", "-----------");
while (command_list[i].name[0] != '\0')
{
printf("%-15s %-20s %s", command_list[i].name, command_list[i].syntax,
command_list[i].description);
i++;
}
printf("\n");
printf("Arguments\n");
printf("---------\n");
printf("<molecule> Number representing a specific molecule in\n");
printf(" the database.\n");
printf("<temp> Temperature in deg K.\n");
printf("<formula> Chemical notation (ex: Fe2Cl)\n");
printf("\n");
}
void usage(void)
{
printf("Usage:\n");
printf(" -d data_file\n");
printf(" -fh\n\n");
printf("Arguments:\n");
printf("-d data_file Path of the thermodynamics data file\n");
printf("-f Supress introduction message\n");
printf("-h Help message\n");
}
void List(char **arg)
{
int i;
#ifdef BORLAND
int j = 0;
#endif
char formula[128];
strncpy(formula, arg[0], 128);
for (i = 0; i < num_thermo; i++)
{
if ((STRNCASECMP(NAME(i), formula, strlen(formula)-1)) == 0)
{
#ifdef BORLAND
j++;
if (j%22 == 0)
{
printf("(Press any key to continue)");
getchar();
}
#endif
printf("%4d: %s\n", i, NAME(i));
}
}
return;
}
void Info(char **arg)
{
unsigned int n;
/* molecule temperature pressure */
if (converti(arg[0], &n) != 0)
{
printf("Error converting number.\n");
return;
}
if (n > num_thermo)
{
printf("Value out of range.\n");
return;
}
printf("\nInformation about %s data.\n", NAME(n));
printf("---------------------------\n");
printf("Reference: %s\n", (thermo_list + n)->comments);
printf("Id : %s\n\n", (thermo_list + n)->id);
return;
}
void Properties(char **arg)
{
unsigned int n;
double T;
/* molecule temperature pressure */
if (converti(arg[0], &n) != 0)
{
printf("Error converting number.\n");
return;
}
if (n > num_thermo)
{
printf("Value out of range.\n");
return;
}
if (convertd(arg[1], &T) != 0)
{
printf("Error converting number.\n");
return;
}
printf("\nProperties of %s at %.2f deg K\n", NAME(n), T);
printf("---------------------------------\n");
printf(" Enthalpy - Internal energy - Entropy\n");
printf("%9.3f %-11s %9.3f %-9s %9.3f %-10s\n",
ENTHALPY(n, T), "(-)",
INTERNAL_ENERGY(n, T), "(-)",
ENTROPY(n, T), "(-)");
printf("%9.3f %-11s %9.3f %-9s %9.3f %-10s\n",
ENTHALPY(n, T)*R*T/1000, "(kJ/mol)",
INTERNAL_ENERGY(n, T)*R*T/1000, "(kJ/mol)",
ENTROPY(n, T)*R, "(kJ/kmol-K)");
printf("%9.3f %-11s %9.3f %-9s %9.3f %-10s\n\n",
ENTHALPY(n, T)*R*T/MOLAR_MASS(n), "(kJ/kg)",
INTERNAL_ENERGY(n, T)*R*T/MOLAR_MASS(n), "(kJ/kg)",
ENTROPY(n, T)*R/MOLAR_MASS(n), "(kJ/kg-K)");
printf(" Specific Heat - Gibbs free energy\n");
printf("%9.3f %-11s %9.3f %-9s\n",
SPECIFIC_HEAT(n, T), "(-)",
GIBBS(n, T), "(-)");
printf("%9.3f %-11s %9.3f %-9s\n",
SPECIFIC_HEAT(n, T)*R, "(kJ/kmol-K)",
GIBBS(n, T)*R*T/1000, "(kJ/mol)");
printf("%9.3f %-11s %9.3f %-9s\n\n",
SPECIFIC_HEAT(n, T)*R/MOLAR_MASS(n), "(kJ/kg-K)",
GIBBS(n, T)*R*T/MOLAR_MASS(n), "(kJ/kg)");
}
void Internal_energy(char **arg)
{
unsigned int n;
double T;
/* molecule temperature pressure */
if (converti(arg[0], &n) != 0)
{
printf("Error converting number.\n");
return;
}
if (n > num_thermo)
{
printf("Value out of range.\n");
return;
}
if (convertd(arg[1], &T) != 0)
{
printf("Error converting number.\n");
return;
}
printf("\nInternal Energy of %s at %.2f\n", NAME(n), T);
printf("%9.3f (-)\n%9.3f (kJ/mol)\n %9.3f (kJ/kg)\n\n",
INTERNAL_ENERGY(n, T),
INTERNAL_ENERGY(n, T)*R*T/1000,
INTERNAL_ENERGY(n, T)*R*T/MOLAR_MASS(n));
return;
}
void Entropy(char **arg)
{
unsigned int n;
double T;
/* molecule temperature pressure */
if (converti(arg[0], &n) != 0)
{
printf("Error converting number.\n");
return;
}
if (n > num_thermo)
{
printf("Value out of range.\n");
return;
}
if (convertd(arg[1], &T) != 0)
{
printf("Error converting number.\n");
return;
}
printf("\nEntropy of %s at %.2f deg K\n", NAME(n), T);
printf("%9.3f (-)\n%9.3f kJ/kmol-K\n%9.3f kJ/kg-K\n\n",
ENTROPY(n, T),
ENTROPY(n, T)*R,
ENTROPY(n, T)*R/MOLAR_MASS(n));
return;
}
void Gibbs(char **arg)
{
unsigned int n;
double T;
/* molecule temperature pressure */
if (converti(arg[0], &n) != 0)
{
printf("Error converting number.\n");
return;
}
if (n > num_thermo)
{
printf("Value out of range.\n");
return;
}
if (convertd(arg[1], &T) != 0)
{
printf("Error converting number.\n");
return;
}
printf("\nGibbs function of %s at %.2f deg K\n", NAME(n), T);
printf("%9.3f (-)\n%9.3f (kJ/mol)\n%9.3f (kJ/kg)\n\n",
GIBBS(n, T),
GIBBS(n, T)*R*T/1000,
GIBBS(n, T)*R*T/MOLAR_MASS(n));
return;
}
void Enthalpy(char **arg)
{
unsigned int n;
double T;
/* molecule temperature pressure */
if (converti(arg[0], &n) != 0)
{
printf("Error converting number.\n");
return;
}
if (n > num_thermo)
{
printf("Value out of range.\n");
return;
}
if (convertd(arg[1], &T) != 0)
{
printf("Error converting number.\n");
return;
}
printf("\nEnthalpy of %s at %.2f deg K\n", NAME(n), T);
printf("%9.3f (-)\n%9.3f (kJ/mol)\n%9.3f (kJ/kg)\n\n",
ENTHALPY(n, T),
ENTHALPY(n, T)*R*T/1000,
ENTHALPY(n, T)*R*T/MOLAR_MASS(n));
return;
}
void Specific_heat(char **arg)
{
unsigned int n;
double T;
/* molecule temperature pressure */
if (converti(arg[0], &n) != 0)
{
printf("Error converting number.\n");
return;
}
if (n > num_thermo)
{
printf("Value out of range.\n");
return;
}
if (convertd(arg[1], &T) != 0)
{
printf("Error converting number.\n");
return;
}
printf("\nSpecific heat (Cp) of %s at %.2f\n", NAME(n), T);
printf("%9.3f (-)\n%9.3f (kJ/kmol-K)\n%9.3f (kJ/kg-K)\n\n",
SPECIFIC_HEAT(n, T),
SPECIFIC_HEAT(n, T)*R,
SPECIFIC_HEAT(n, T)*R/MOLAR_MASS(n));
return;
}
void molarMass(char **arg)
{
unsigned int n;
if (converti(arg[0], &n) != 0)
{
printf("Error converting number.\n");
return;
}
if (n > num_thermo)
{
printf("Value out of range.\n");
return;
}
printf("\nMolar mass of %s\n", NAME(n));
printf("%9.4f g/mol\n\n", MOLAR_MASS(n));
return;
}
void welcome(void)
{
printf("PROP, version %s (GPL License).\n", VERSION);
printf("Ideal Gas Thermochemical Properties.\n");
printf("Interface to the NASA Gleen Research Center Database\n");
printf("provide by Bonnie J. McBride.\n");
printf("Copyright (C) 2000 Antoine Lefebvre.\n");
printf("For command list, type `help'.\n\n");
}
int converti(char *string, unsigned int *number)
{
char *ptr;
if (string[0] == '\0')
{
return -1;
}
errno = 0;
*number = strtoul(string, &ptr, 10);
if (errno == ERANGE)
{
return -1;
}
if (ptr[0] == string[0])
{
return -1;
}
return 0;
}
int convertd(char *string, double *number)
{
char *ptr;
if (string[0] == '\0')
{
return -1;
}
errno = 0;
*number = strtod(string, &ptr);
if (errno == ERANGE)
{
return -1;
}
if (ptr[0] == string[0])
{
return -1;
}
return 0;
}
int main(int argc, char *argv[])
{
int i, j, n, c;
bool found;
bool ok;
bool msg = true;
char line[MAX_LINE];
char *ptr;
char *running;
char *token;
char **arg;
char thermo_file[FILENAME_MAX] = "../../data/thermo.dat";
/* parse the command line */
while (1)
{
c = getopt(argc, argv, "fhd:");
if (c == EOF)
break;
switch (c)
{
case 'd':
strncpy(thermo_file, optarg, FILENAME_MAX);
break;
case 'f':
msg = false;
break;
case 'h':
usage();
return 0;
}
}
if (msg)
welcome();
if (load_thermo (thermo_file) < 0)
{
printf("Error loading thermo data file: %s\n", thermo_file);
return -1;
}
while (1)
{
printf("%s", PROMPT);
if (fgets(line, MAX_LINE, stdin) == NULL)
{
printf("\n");
return 0;
}
if (line[0] != '\n')
{
i = 0;
found = false;
/* duplicate the string */
if ((running = strdup(line)) == NULL)
{
printf("Not enough memory.\n");
return -1;
}
/* keep the adress in memory to free it later */
ptr = running;
/* first get the command name */
token = strtok(running, " \n");
while ((command_list[i].name[0] != '\0') && (found == false))
{
if (STRNCASECMP(command_list[i].name, token,
strlen(token)) == 0)
{
found = true;
ok = true;
/* number of arguments for this command */
n = command_list[i].num_arg;
/* allocate the memory for the arguments */
arg = (char **) malloc(n * sizeof(char*));
for (j = 0; j < n; j++)
arg[j] = (char *) malloc(ARG_LENGTH * sizeof(char));
/* get each arguments */
for (j = 0; j < n; j++)
{
if ((token = strtok(NULL, " ")) == NULL)
{
printf("Not enough arguments.\n");
ok = false;
break;
}
/* copy it */
if (ok)
strncpy(arg[j], token, ARG_LENGTH);
}
if (ok)
{
/* verify if there is more arguments than needed */
if ((token = strtok(NULL, " ")) != NULL)
printf("Too much arguments. Need only %d.\n", n);
/* execute the command */
command_list[i].function(arg);
}
/* free memory */
for (j = 0; j < n; j++)
free(arg[j]);
free(arg);
}
i++;
}
free(ptr);
if (found == false)
{
printf("?Invalid command\n");
}
}
}
return 0;
}

+ 47
- 0
rocketworkbench/BUILD View File

@ -0,0 +1,47 @@
Building Rocketworkbench (20011016)
====================================
These build instructions were written by Geoff O'Callaghan for building the
Debian package for rocketworkbench. They are generic enough to be useful
on just about any Unix/Linux system. They are brief!
1. Getting the source.... If you're reading this then you've probably
already got the source code. If you're reading this and you don't have the
source code then hey don't worry :-)
For anonymous readonly access
export CVSROOT=:pserver:anonymous@cvs.rocketworkbench.sourceforge.net:/cvsroot/rocketworkbench
cvs login
Password is 'null' - ie. just hit enter
cvs -z6 -q co rocketworkbench
2. Compiling the source
Rocketworkbench relies on a library called GPCP. This is a separate
development by Antoine and his brother. In order to compile rocketworkbench
you'll need to obtain the GPCP library and place it in the
sources/libraries directory.
<need a download location for gpcp!>
ie.
cd rocketworkbench/sources/libraries
tar zxvf gpcp.tgz
will create a gpcp directory and rocketworkbench is already configured to
build using GPCP in this location.
In order to compile cpropep-web and lrd-web you will also require cgilib.
cgilib can be obtained on Debian systems using:
apt-get install cgilib
Once all thats done. Just type in 'make' in the rocketworkbench directory and
it should ALL HAPPEN.

+ 14
- 0
rocketworkbench/Documentation/analyser/examples/H.conf View File

@ -0,0 +1,14 @@
datafile = "H.dat"
format = (
column = 2,
time = (col = 1, units = "s"),
thrust = (col = 2, units = "lbf"),
comments = "#"
)
motor = (propellant_mass = (val = 117.,
units = "g"),
total_mass = (val = 200.,
units = "g")
)

+ 114
- 0
rocketworkbench/Documentation/analyser/examples/H.dat View File

@ -0,0 +1,114 @@
# Test of H booster
# time (s) thrust (lbf)
0 4
0.01 9.6
0.02 14
0.03 18.3
0.04 21.9
0.05 24.9
0.06 27.4
0.07 29.5
0.08 31.3
0.09 35
0.1 39
0.11 43.8
0.12 48.6
0.13 51
0.14 54.7
0.15 57.5
0.16 59.5
0.17 62.5
0.18 63.2
0.19 65
0.2 65.9
0.21 66.8
0.22 66.8
0.23 67.5
0.24 67.4
0.25 67.8
0.26 67.7
0.27 68.2
0.28 68.6
0.29 68.4
0.3 68.3
0.31 68.5
0.32 67.9
0.33 65.4
0.34 64
0.35 62.1
0.36 61.2
0.37 59.7
0.38 58.9
0.39 57.4
0.4 56.8
0.41 55.7
0.42 54.9
0.43 54.5
0.44 52.9
0.45 51.4
0.46 50.2
0.47 48.3
0.48 46.9
0.49 45.8
0.5 44.8
0.51 44.1
0.52 43.3
0.53 42.3
0.54 41.8
0.55 41.2
0.56 39.8
0.57 39.6
0.58 37.9
0.59 37.5
0.6 36.6
0.61 36
0.62 35.3
0.63 34.9
0.64 34.3
0.65 34
0.66 33.1
0.67 32.5
0.68 30.8
0.69 29.8
0.7 28.7
0.71 27.1
0.72 26.1
0.73 25.2
0.74 24.2
0.75 23.6
0.76 23.4
0.77 22.6
0.78 21.9
0.79 20.3
0.8 19
0.81 17.8
0.82 16.6
0.83 14.8
0.84 14
0.85 12.5
0.86 12.2
0.87 11.2
0.88 11
0.89 9.8
0.9 9
0.91 8.3
0.92 7.2
0.93 6.3
0.94 5.7
0.95 4.6
0.96 4.2
0.97 3.6
0.98 2.9
0.99 2.7
1 2.3
1.01 2.1
1.02 1.9
1.03 1.3
1.04 1.3
1.05 1.2
1.06 0.8
1.07 0.6
1.08 0.5
1.09 0.5
1.1 0.5

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save