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 *
This commit is contained in:
commit
eb05416991
13
CVSROOT/checkoutlist
Normal file
13
CVSROOT/checkoutlist
Normal 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
CVSROOT/commitinfo
Normal file
15
CVSROOT/commitinfo
Normal 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
CVSROOT/config
Normal file
11
CVSROOT/config
Normal 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
CVSROOT/cvswrappers
Normal file
23
CVSROOT/cvswrappers
Normal 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
CVSROOT/editinfo
Normal file
21
CVSROOT/editinfo
Normal 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
CVSROOT/loginfo
Normal file
26
CVSROOT/loginfo
Normal 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
CVSROOT/modules
Normal file
26
CVSROOT/modules
Normal 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
CVSROOT/notify
Normal file
12
CVSROOT/notify
Normal 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
CVSROOT/rcsinfo
Normal file
13
CVSROOT/rcsinfo
Normal 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
CVSROOT/taginfo
Normal file
20
CVSROOT/taginfo
Normal 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
CVSROOT/verifymsg
Normal file
21
CVSROOT/verifymsg
Normal 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
analyser/src/Makefile
Normal file
35
analyser/src/Makefile
Normal 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
analyser/src/analyser.c
Normal file
365
analyser/src/analyser.c
Normal 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
analyser/src/analyser.h
Normal file
51
analyser/src/analyser.h
Normal 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
analyser/src/essai.txt
Normal file
4
analyser/src/essai.txt
Normal file
@ -0,0 +1,4 @@
|
||||
0 0
|
||||
1 0.25
|
||||
2 1
|
||||
3 2.25
|
14
analyser/src/test.conf
Normal file
14
analyser/src/test.conf
Normal 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
analyser/src/test2.txt
Normal file
114
analyser/src/test2.txt
Normal 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
cpropep-web/Makefile
Normal file
11
cpropep-web/Makefile
Normal 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
cpropep-web/src/Makefile
Normal file
40
cpropep-web/src/Makefile
Normal 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
cpropep-web/src/cgitest.c
Normal file
351
cpropep-web/src/cgitest.c
Normal 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
cpropep/Makefile
Normal file
17
cpropep/Makefile
Normal 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
cpropep/doc/thermo.html
Normal file
135
cpropep/doc/thermo.html
Normal 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
cpropep/src/Makefile
Normal file
31
cpropep/src/Makefile
Normal 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
cpropep/src/Makefile.win
Normal file
36
cpropep/src/Makefile.win
Normal 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
cpropep/src/README.txt
Normal file
31
cpropep/src/README.txt
Normal 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
cpropep/src/cpropep.c
Normal file
764
cpropep/src/cpropep.c
Normal 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
cpropep/src/cpropep.conf
Normal file
2
cpropep/src/cpropep.conf
Normal file
@ -0,0 +1,2 @@
|
||||
thermo /usr/share/rocketworkbench/cpropep/thermo.dat
|
||||
propellant /usr/share/rocketworkbench/cpropep/propellant.dat
|
102
cpropep/src/input.pro
Normal file
102
cpropep/src/input.pro
Normal 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
data/propellant.dat
Normal file
1098
data/propellant.dat
Normal file
File diff suppressed because it is too large
Load Diff
24
data/references.txt
Normal file
24
data/references.txt
Normal 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
data/thermo.dat
Normal file
14517
data/thermo.dat
Normal file
File diff suppressed because it is too large
Load Diff
37
libcompat/Makefile
Normal file
37
libcompat/Makefile
Normal 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
libcompat/Makefile.win
Normal file
50
libcompat/Makefile.win
Normal 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
libcompat/include/compat.h
Normal file
68
libcompat/include/compat.h
Normal 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
libcompat/include/getopt.h
Normal file
10
libcompat/include/getopt.h
Normal 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
libcompat/src/compat.c
Normal file
46
libcompat/src/compat.c
Normal 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
libcompat/src/getopt.c
Normal file
83
libcompat/src/getopt.c
Normal 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
libcpropep/Makefile
Normal file
11
libcpropep/Makefile
Normal 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
libcpropep/Makefile.win
Normal file
50
libcpropep/Makefile.win
Normal 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
libcpropep/include/const.h
Normal file
11
libcpropep/include/const.h
Normal 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
libcpropep/include/conversion.h
Normal file
60
libcpropep/include/conversion.h
Normal 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
libcpropep/include/derivative.h
Normal file
8
libcpropep/include/derivative.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef derivative_h
|
||||
#define derivative_h
|
||||
|
||||
#include "equilibrium.h"
|
||||
|
||||
int derivative(equilibrium_t *e);
|
||||
|
||||
#endif
|
156
libcpropep/include/equilibrium.h
Normal file
156
libcpropep/include/equilibrium.h
Normal 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
libcpropep/include/performance.h
Normal file
18
libcpropep/include/performance.h
Normal 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
libcpropep/include/print.h
Normal file
69
libcpropep/include/print.h
Normal 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
libcpropep/include/return.h
Normal file
22
libcpropep/include/return.h
Normal 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
libcpropep/include/type.h
Normal file
161
libcpropep/include/type.h
Normal 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
libcpropep/src/Makefile
Normal file
32
libcpropep/src/Makefile
Normal 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
libcpropep/src/derivative.c
Normal file
241
libcpropep/src/derivative.c
Normal 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
libcpropep/src/equilibrium.c
Normal file
1258
libcpropep/src/equilibrium.c
Normal file
File diff suppressed because it is too large
Load Diff
562
libcpropep/src/performance.c
Normal file
562
libcpropep/src/performance.c
Normal 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
libcpropep/src/print.c
Normal file
427
libcpropep/src/print.c
Normal 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
libnum/Makefile
Normal file
13
libnum/Makefile
Normal 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
libnum/Makefile.win
Normal file
43
libnum/Makefile.win
Normal 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
libnum/include/num.h
Normal file
149
libnum/include/num.h
Normal 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
libnum/src/Makefile
Normal file
38
libnum/src/Makefile
Normal 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
libnum/src/general.c
Normal file
32
libnum/src/general.c
Normal 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
libnum/src/lu.c
Normal file
172
libnum/src/lu.c
Normal 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
libnum/src/newton.c
Normal file
31
libnum/src/newton.c
Normal 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
libnum/src/print.c
Normal file
54
libnum/src/print.c
Normal 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
libnum/src/ptfix.c
Normal file
31
libnum/src/ptfix.c
Normal 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
libnum/src/rk4.c
Normal file
107
libnum/src/rk4.c
Normal 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
libnum/src/rkf.c
Normal file
179
libnum/src/rkf.c
Normal 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
libnum/src/sec.c
Normal file
33
libnum/src/sec.c
Normal 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
libnum/src/simpson.c
Normal file
49
libnum/src/simpson.c
Normal 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
libnum/src/spline.c
Normal file
108
libnum/src/spline.c
Normal 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
libnum/src/sysnewton.c
Normal file
86
libnum/src/sysnewton.c
Normal 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
libnum/src/test.c
Normal file
344
libnum/src/test.c
Normal 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
libnum/src/trapeze.c
Normal file
16
libnum/src/trapeze.c
Normal 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
libsimulation/Makefile
Normal file
43
libsimulation/Makefile
Normal 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
libsimulation/TODO
Normal file
2
libsimulation/TODO
Normal 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
libsimulation/c++rocket.h
Normal file
51
libsimulation/c++rocket.h
Normal 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
libsimulation/lsode.cc
Normal file
193
libsimulation/lsode.cc
Normal 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
libsimulation/lsode.h
Normal file
93
libsimulation/lsode.h
Normal 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
libsimulation/modeles.cc
Normal file
234
libsimulation/modeles.cc
Normal 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
libsimulation/motor.l
Normal file
146
libsimulation/motor.l
Normal 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
libsimulation/rk4.cc
Normal file
118
libsimulation/rk4.cc
Normal 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
libsimulation/rk4.h
Normal file
65
libsimulation/rk4.h
Normal 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
libsimulation/rocket.cc
Normal file
314
libsimulation/rocket.cc
Normal 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
libsimulation/rocket.h
Normal file
174
libsimulation/rocket.h
Normal 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
libsimulation/simulation.cc
Normal file
51
libsimulation/simulation.cc
Normal 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
libsimulation/simulation.h
Normal file
74
libsimulation/simulation.h
Normal 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
libsimulation/simulator/.ccmalloc
Normal file
348
libsimulation/simulator/.ccmalloc
Normal 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
libsimulation/simulator/Makefile
Normal file
35
libsimulation/simulator/Makefile
Normal 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
libsimulation/simulator/c++rocket.cc
Normal file
78
libsimulation/simulator/c++rocket.cc
Normal 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
libthermo/Makefile
Normal file
11
libthermo/Makefile
Normal 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
libthermo/Makefile.win
Normal file
50
libthermo/Makefile.win
Normal 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
libthermo/include/load.h
Normal file
56
libthermo/include/load.h
Normal 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
libthermo/include/thermo.h
Normal file
218
libthermo/include/thermo.h
Normal 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
libthermo/src/Makefile
Normal file
31
libthermo/src/Makefile
Normal 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
libthermo/src/load.c
Normal file
520
libthermo/src/load.c
Normal 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
libthermo/src/thermo.c
Normal file
563
libthermo/src/thermo.c
Normal 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
prop/Makefile
Normal file
9
prop/Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
all:
|
||||
make -C src all
|
||||
|
||||
clean:
|
||||
make -C src clean
|
||||
|
||||
deep-clean: clean
|
||||
make -C src deep-clean
|
38
prop/Makefile.win
Normal file
38
prop/Makefile.win
Normal 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
prop/src/Makefile
Normal file
36
prop/src/Makefile
Normal 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
prop/src/plot.c
Normal file
334
prop/src/plot.c
Normal 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
prop/src/prop.c
Normal file
611
prop/src/prop.c
Normal 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
rocketworkbench/BUILD
Normal file
47
rocketworkbench/BUILD
Normal 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
rocketworkbench/Documentation/analyser/examples/H.conf
Normal file
14
rocketworkbench/Documentation/analyser/examples/H.conf
Normal 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
rocketworkbench/Documentation/analyser/examples/H.dat
Normal file
114
rocketworkbench/Documentation/analyser/examples/H.dat
Normal 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 have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user