Taken from sources in CVS at: https://sourceforge.net/projects/rocketworkbench/ Sources extracted in two steps: 1. Pull entire project tree into a subdir "rwb" via "rsync": rsync -a a.cvs.sourceforge.net::cvsroot/rocketworkbench/ rwb/. 2. Export sources: export CVSROOT=$(pwd)/rwb SUBDIRS="analyser cpropep cpropep-web CVSROOT data libcompat libcpropep libnum libsimulation libthermo prop rocketworkbench rockflight" mkdir rwbx; cd rwbx cvs export -D now ${SUBDIRS} After this (and some backups for safety), the directory content was added to a Git repo: git init . git add *master
@ -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 '#' |
@ -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". |
@ -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 |
@ -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' |
@ -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. |
@ -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 |
@ -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. |
@ -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" |
@ -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". |
@ -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". |
@ -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. |
@ -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) |
@ -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; | |||
} | |||
@ -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 */ |
@ -0,0 +1,4 @@ | |||
0 0 | |||
1 0.25 | |||
2 1 | |||
3 2.25 |
@ -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") | |||
) | |||
@ -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 |
@ -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 |
@ -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/ |
@ -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; | |||
} | |||
@ -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 |
@ -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). |
@ -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) |
@ -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) |
@ -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> | |||
@ -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; | |||
} |
@ -0,0 +1,2 @@ | |||
thermo /usr/share/rocketworkbench/cpropep/thermo.dat | |||
propellant /usr/share/rocketworkbench/cpropep/propellant.dat |
@ -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 |
@ -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) | |||
@ -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) |
@ -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) |
@ -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) */ |
@ -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 */ | |||
@ -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 |
@ -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 */ | |||
} | |||
@ -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 |
@ -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) |
@ -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 |
@ -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 |
@ -0,0 +1,8 @@ | |||
#ifndef derivative_h | |||
#define derivative_h | |||
#include "equilibrium.h" | |||
int derivative(equilibrium_t *e); | |||
#endif |
@ -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 | |||
@ -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 | |||
@ -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 |
@ -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) */ |
@ -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 |
@ -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) |
@ -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; | |||
} | |||
@ -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; | |||
} | |||
@ -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; | |||
} |
@ -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 | |||
@ -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) | |||
@ -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 | |||
@ -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) | |||
@ -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); | |||
} |
@ -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; | |||
} |
@ -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; | |||
} |
@ -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; | |||
} | |||
@ -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; | |||
} |
@ -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; | |||
} | |||
@ -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; | |||
} | |||
@ -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; | |||
} |
@ -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; | |||
} |
@ -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; | |||
} | |||
@ -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); | |||
} |
@ -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; | |||
} | |||
@ -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; | |||
} |
@ -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 | |||
@ -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... |
@ -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 | |||
@ -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."; | |||
} | |||
} | |||
@ -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 | |||
@ -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; | |||
} | |||
@ -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; | |||
} | |||
@ -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; | |||
} | |||
} | |||
@ -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 |
@ -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; | |||
} | |||
@ -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 | |||
@ -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"; | |||
}; | |||
@ -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 | |||
@ -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 |
@ -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 |
@ -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; | |||
} | |||
@ -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 |
@ -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) |
@ -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 | |||
@ -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 |
@ -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) |
@ -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'; | |||
} |
@ -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; | |||
} |
@ -0,0 +1,9 @@ | |||
all: | |||
make -C src all | |||
clean: | |||
make -C src clean | |||
deep-clean: clean | |||
make -C src deep-clean |
@ -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) |
@ -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) |
@ -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; | |||
} |
@ -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; | |||
} |
@ -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. | |||
@ -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") | |||
) | |||
@ -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 |