mirror of
https://git.gfz-potsdam.de/naaice/iphreeqc.git
synced 2025-12-16 16:44:49 +01:00
Will remove cpp and header files and make phreeqc an external directory. git-svn-id: svn://136.177.114.72/svn_GW/phreeqcpp/trunk@785 1feff8c3-07ed-0310-ac33-dd36852eb9cd
1070 lines
33 KiB
C++
1070 lines
33 KiB
C++
#define EXTERNAL extern
|
|
#include "global.h"
|
|
#include "phqalloc.h"
|
|
#include "output.h"
|
|
#include "phrqproto.h"
|
|
|
|
static char const svnid[] = "$Id: spread.c 187 2005-03-16 19:54:17Z charlton $";
|
|
|
|
#define STATIC static
|
|
|
|
#define STRING 11
|
|
#define NUMBER 12
|
|
#define MIXED 13
|
|
#define EOL 14
|
|
|
|
#define OPTION_EOF -1
|
|
#define OPTION_KEYWORD -2
|
|
#define OPTION_ERROR -3
|
|
#define OPTION_DEFAULT -4
|
|
#define OPT_1 -5
|
|
|
|
static int copy_token_tab(char *token_ptr, char **ptr, int *length);
|
|
static int get_option_string (const char **opt_list, int count_opt_list, char **next_char);
|
|
static int spread_row_free(struct spread_row *spread_row_ptr);
|
|
static int spread_row_to_solution(struct spread_row *heading, struct spread_row *units, struct spread_row *data, struct defaults defaults);
|
|
static struct spread_row *string_to_spread_row(char *string);
|
|
#ifdef PHREEQCI_GUI
|
|
static void add_row(struct spread_row *spread_row_ptr);
|
|
static void copy_defaults(struct defaults *dest_ptr, struct defaults *src_ptr);
|
|
void free_spread(void);
|
|
static struct spread_row *copy_row(struct spread_row *spread_row_ptr);
|
|
#endif
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int read_solution_spread(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Reads solution data
|
|
*
|
|
* Arguments:
|
|
* none
|
|
*
|
|
* Returns:
|
|
* KEYWORD if keyword encountered, input_error may be incremented if
|
|
* a keyword is encountered in an unexpected position
|
|
* EOF if eof encountered while reading mass balance concentrations
|
|
* ERROR if error occurred reading data
|
|
*
|
|
*/
|
|
struct spread_row *heading, *row_ptr, *units;
|
|
int i, j, l, j1, num, count;
|
|
int strings, numbers;
|
|
int spread_lines;
|
|
char token[MAX_LENGTH], token1[MAX_LENGTH];
|
|
char *ptr;
|
|
struct defaults defaults = {
|
|
25,
|
|
1,
|
|
"mmol/kgw",
|
|
"pe",
|
|
7,
|
|
4,
|
|
1,
|
|
1,
|
|
iso_defaults,
|
|
};
|
|
int return_value, opt;
|
|
char *next_char;
|
|
const char *opt_list[] = {
|
|
"temp", /* 0 */
|
|
"temperature", /* 1 */
|
|
"dens", /* 2 */
|
|
"density", /* 3 */
|
|
"units", /* 4 */
|
|
"redox", /* 5 */
|
|
"ph", /* 6 */
|
|
"pe", /* 7 */
|
|
"unit", /* 8 */
|
|
"isotope", /* 9 */
|
|
"water", /* 10 */
|
|
"isotope_uncertainty", /* 11 */
|
|
"uncertainty", /* 12 */
|
|
"uncertainties" /* 13 */
|
|
};
|
|
int count_opt_list = 14;
|
|
if (svnid == NULL) fprintf(stderr," ");
|
|
|
|
heading = NULL;
|
|
units = NULL;
|
|
defaults.count_iso = count_iso_defaults;
|
|
defaults.iso = (struct iso *) PHRQ_malloc((size_t) defaults.count_iso * sizeof(struct iso));
|
|
if (defaults.iso == NULL) malloc_error();
|
|
memcpy(defaults.iso, iso_defaults, (size_t) defaults.count_iso * sizeof(struct iso));
|
|
return_value = UNKNOWN;
|
|
spread_lines = 0;
|
|
/*
|
|
* Loop on solutions
|
|
*/
|
|
for (;;) {
|
|
opt = get_option(opt_list, count_opt_list, &next_char);
|
|
if (spread_lines == 0 && opt != OPTION_DEFAULT) {
|
|
row_ptr = string_to_spread_row(line);
|
|
count = 0;
|
|
ptr = line;
|
|
numbers = 0;
|
|
strings = 0;
|
|
while ( ((j = copy_token(token, &ptr, &l)) != EMPTY)) {
|
|
count++;
|
|
if (j == UPPER || j == LOWER) strings++;
|
|
if (j == DIGIT) numbers++;
|
|
}
|
|
#ifdef SKIP
|
|
for (i = 0; i < row_ptr->count; i++) {
|
|
if (row_ptr->type_vector[i] == STRING) {
|
|
strings++;
|
|
} else if (row_ptr->type_vector[i] == NUMBER) {
|
|
numbers++;
|
|
}
|
|
}
|
|
#endif
|
|
/*
|
|
* Is 2nd token all number
|
|
*/
|
|
ptr = line;
|
|
copy_token(token, &ptr, &l);
|
|
j = copy_token(token, &ptr, &l);
|
|
num = FALSE;
|
|
if (j == DIGIT) {
|
|
strtod(token, &ptr);
|
|
j1 = copy_token(token1, &ptr, &l);
|
|
if (j1 != EMPTY) {
|
|
num = FALSE;
|
|
} else {
|
|
num = TRUE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Starts with hyphen
|
|
*/
|
|
ptr = line;
|
|
copy_token(token, &ptr, &l);
|
|
if (token[0] == '-') {
|
|
opt = opt;
|
|
} else {
|
|
switch (opt) {
|
|
case 0: /* temp */
|
|
case 1: /* temperature */
|
|
case 2: /* dens */
|
|
case 3: /* density */
|
|
case 10: /* water */
|
|
if (count == 2 && num == TRUE) {
|
|
opt = opt;
|
|
} else {
|
|
opt = OPTION_DEFAULT;
|
|
}
|
|
break;
|
|
case 6: /* ph */
|
|
case 7: /* pe */
|
|
if ((count == 2 || count == 3 || count == 4) && num == TRUE) {
|
|
opt = opt;
|
|
} else {
|
|
opt = OPTION_DEFAULT;
|
|
}
|
|
break;
|
|
case 5: /* redox */
|
|
case 4: /* units */
|
|
case 8: /* unit */
|
|
if (count == 2) {
|
|
opt = opt;
|
|
} else {
|
|
opt = OPTION_DEFAULT;
|
|
}
|
|
break;
|
|
case 9: /* isotope */
|
|
if (row_ptr->count > 4) {
|
|
opt = OPTION_DEFAULT;
|
|
} else {
|
|
opt = opt;
|
|
}
|
|
break;
|
|
case 11: /* isotope_uncertainty */
|
|
case 12: /* uncertainty */
|
|
case 13: /* uncertainties */
|
|
if (row_ptr->count > 3) {
|
|
opt = OPTION_DEFAULT;
|
|
} else {
|
|
opt = opt;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
spread_row_free(row_ptr);
|
|
}
|
|
if (opt == OPTION_DEFAULT) {
|
|
if (spread_lines == 0) {
|
|
opt = 100;
|
|
}
|
|
spread_lines++;
|
|
}
|
|
switch (opt) {
|
|
case OPTION_EOF: /* end of file */
|
|
return_value = EOF;
|
|
break;
|
|
case OPTION_KEYWORD: /* keyword */
|
|
return_value = KEYWORD;
|
|
break;
|
|
case OPTION_ERROR:
|
|
input_error++;
|
|
error_msg("Unknown input in SOLUTION keyword.", CONTINUE);
|
|
error_msg(line_save, CONTINUE);
|
|
break;
|
|
case OPTION_DEFAULT: /* solution definition */
|
|
row_ptr = string_to_spread_row(line);
|
|
if (spread_lines == 2) {
|
|
numbers = 0;
|
|
strings = 0;
|
|
for (i = 0; i < heading->count; i++) {
|
|
if (row_ptr->type_vector[i] == STRING) {
|
|
strings++;
|
|
} else if (row_ptr->type_vector[i] == NUMBER) {
|
|
numbers++;
|
|
}
|
|
#ifdef SKIP
|
|
if (row_ptr->type_vector[i] == STRING &&
|
|
(strcmp_nocase(heading->char_vector[i],"units") != 0) &&
|
|
(strcmp_nocase(heading->char_vector[i],"unit") != 0) &&
|
|
(strcmp_nocase(heading->char_vector[i],"description") != 0) &&
|
|
(strcmp_nocase(heading->char_vector[i],"desc") != 0) &&
|
|
(strcmp_nocase(heading->char_vector[i],"descriptor") != 0) &&
|
|
(strcmp_nocase(heading->char_vector[i],"redox") != 0) ) {
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
#ifdef SKIP
|
|
if (i < heading->count) {
|
|
units = row_ptr;
|
|
break;
|
|
}
|
|
#endif
|
|
if (numbers == 0) {
|
|
units = row_ptr;
|
|
break;
|
|
}
|
|
}
|
|
spread_row_to_solution(heading, units, row_ptr, defaults);
|
|
#ifdef PHREEQCI_GUI
|
|
add_row(row_ptr);
|
|
#endif
|
|
spread_row_free(row_ptr);
|
|
break;
|
|
case 0: /* temperature */
|
|
case 1:
|
|
sscanf(next_char,SCANFORMAT, &(defaults.temp));
|
|
break;
|
|
case 2: /* density */
|
|
case 3:
|
|
sscanf(next_char,SCANFORMAT, &(defaults.density));
|
|
break;
|
|
case 4: /* units */
|
|
case 8: /* unit */
|
|
if (copy_token (token, &next_char, &l) == EMPTY) break;
|
|
if (check_units (token, FALSE, FALSE, NULL, TRUE) == OK) {
|
|
defaults.units = string_hsave(token);
|
|
} else {
|
|
input_error++;
|
|
}
|
|
break;
|
|
case 5: /* redox */
|
|
if (copy_token (token, &next_char, &l) == EMPTY) break;
|
|
if (parse_couple(token) == OK) {
|
|
defaults.redox = string_hsave(token);
|
|
} else {
|
|
input_error++;
|
|
}
|
|
break;
|
|
case 6: /* ph */
|
|
copy_token (token, &next_char, &l);
|
|
sscanf(token,SCANFORMAT, &(defaults.ph));
|
|
if (copy_token (token, &next_char, &l) != EMPTY) {
|
|
warning_msg("Not possible to use phase name or saturation index in definition of default pH in SOLUTION_SPREAD.");
|
|
}
|
|
break;
|
|
case 7: /* pe */
|
|
copy_token (token, &next_char, &l);
|
|
sscanf(token,SCANFORMAT, &(defaults.pe));
|
|
if (copy_token (token, &next_char, &l) != EMPTY) {
|
|
warning_msg("Not possible to use phase name or saturation index in definition of default pe in SOLUTION_SPREAD.");
|
|
}
|
|
break;
|
|
case 11: /* isotope_uncertainty */
|
|
case 12: /* uncertainty */
|
|
case 13: /* uncertainties */
|
|
if (copy_token(token, &next_char, &l) != DIGIT) {
|
|
input_error++;
|
|
sprintf(error_string, "Expected isotope name to"
|
|
" begin with an isotopic number.");
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
for (i = 0; i < defaults.count_iso; i++) {
|
|
if (strcmp(token, defaults.iso[i].name) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
if (i == defaults.count_iso) {
|
|
defaults.iso = (struct iso *) PHRQ_realloc(defaults.iso, (size_t) (i+1) * sizeof(struct iso));
|
|
if (defaults.iso == NULL) malloc_error();
|
|
defaults.iso[i].name = string_duplicate(token);
|
|
defaults.iso[i].value = NAN;
|
|
defaults.iso[i].uncertainty = NAN;
|
|
defaults.count_iso++;
|
|
}
|
|
|
|
/* read and store isotope ratio uncertainty */
|
|
if ( (j = copy_token(token, &next_char, &l)) != EMPTY) {
|
|
if (j != DIGIT) {
|
|
input_error++;
|
|
sprintf(error_string, "Expected numeric value for uncertainty in isotope ratio.");
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
} else {
|
|
sscanf(token, SCANFORMAT, &(defaults.iso[i].uncertainty));
|
|
}
|
|
} else {
|
|
defaults.iso[i].uncertainty = NAN;
|
|
}
|
|
break;
|
|
case 10: /* water */
|
|
j = copy_token (token, &next_char, &l);
|
|
if (j != DIGIT) {
|
|
input_error++;
|
|
sprintf(error_string, "Expected numeric value for mass of water in solution.");
|
|
error_msg(error_string, CONTINUE);
|
|
} else {
|
|
sscanf(token, SCANFORMAT, &(defaults.water));
|
|
}
|
|
break;
|
|
case 9: /* isotope */
|
|
if (copy_token(token, &next_char, &l) != DIGIT) {
|
|
input_error++;
|
|
sprintf(error_string, "Expected isotope name to"
|
|
" begin with an isotopic number.");
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
for (i = 0; i < defaults.count_iso; i++) {
|
|
if (strcmp(token, defaults.iso[i].name) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
if (i == defaults.count_iso) {
|
|
defaults.iso = (struct iso *) PHRQ_realloc(defaults.iso, (size_t) (i+1) * sizeof(struct iso));
|
|
if (defaults.iso == NULL) malloc_error();
|
|
defaults.iso[i].name = string_duplicate(token);
|
|
defaults.iso[i].value = NAN;
|
|
defaults.iso[i].uncertainty = NAN;
|
|
defaults.count_iso++;
|
|
}
|
|
/* read and store isotope ratio */
|
|
if (copy_token(token, &next_char, &l) != DIGIT) {
|
|
input_error++;
|
|
sprintf(error_string, "Expected numeric value for default isotope ratio.");
|
|
error_msg(error_string, CONTINUE);
|
|
break;
|
|
}
|
|
sscanf(token, SCANFORMAT, &(defaults.iso[i].value));
|
|
/* read and store isotope ratio uncertainty */
|
|
if ( (j = copy_token(token, &next_char, &l)) != EMPTY) {
|
|
if (j != DIGIT) {
|
|
input_error++;
|
|
sprintf(error_string, "Expected numeric value for uncertainty in isotope ratio.");
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
} else {
|
|
sscanf(token, SCANFORMAT, &(defaults.iso[i].uncertainty));
|
|
}
|
|
}
|
|
break;
|
|
case 100: /* read headings */
|
|
heading = string_to_spread_row(line);
|
|
for (i = 0; i < heading->count; i++) {
|
|
while(replace(" ", "", heading->char_vector[i]) == TRUE);
|
|
while(replace(",", "_", heading->char_vector[i]) == TRUE);
|
|
}
|
|
|
|
break;
|
|
}
|
|
if (return_value == EOF || return_value == KEYWORD) break;
|
|
}
|
|
#ifdef PHREEQCI_GUI
|
|
if (heading) g_spread_sheet.heading = copy_row(heading);
|
|
if (units) g_spread_sheet.units = copy_row(units);
|
|
copy_defaults(&g_spread_sheet.defaults, &defaults);
|
|
#endif
|
|
spread_row_free(heading);
|
|
spread_row_free(units);
|
|
/* free non-default iso names */
|
|
for (i = count_iso_defaults; i < defaults.count_iso; i++) {
|
|
defaults.iso[i].name = (char *) free_check_null(defaults.iso[i].name);
|
|
}
|
|
defaults.iso = (struct iso *) free_check_null(defaults.iso);
|
|
return(return_value);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
int spread_row_to_solution(struct spread_row *heading, struct spread_row *units,
|
|
struct spread_row *data, struct defaults defaults)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
int i, j, n, l, next_keyword_save;
|
|
int n_user, n_user_end;
|
|
int default_pe, alk;
|
|
int count_isotopes;
|
|
int max_mass_balance, count_mass_balance;
|
|
char *ptr, *ptr1;
|
|
char *description;
|
|
char token[MAX_LENGTH], token1[MAX_LENGTH];
|
|
char string[2*MAX_LENGTH];
|
|
LDBLE dummy;
|
|
|
|
int return_value, opt;
|
|
char *next_char;
|
|
const char *opt_list[] = {
|
|
"temp", /* 0 */
|
|
"temperature", /* 1 */
|
|
"dens", /* 2 */
|
|
"density", /* 3 */
|
|
"units", /* 4 */
|
|
"redox", /* 5 */
|
|
"ph", /* 6 */
|
|
"pe", /* 7 */
|
|
"unit", /* 8 */
|
|
"isotope", /* 9 */
|
|
"water", /* 10 */
|
|
"description", /* 11 */
|
|
"desc", /* 12 */
|
|
"descriptor" /* 13 */
|
|
|
|
};
|
|
int count_opt_list = 14;
|
|
|
|
/*
|
|
* look for solution number
|
|
*/
|
|
n_user = -1;
|
|
n_user_end = -1;
|
|
description = string_duplicate("");
|
|
for (i = 0; i < heading->count; i++) {
|
|
if (strcmp_nocase(heading->char_vector[i], "number") == 0) {
|
|
break;
|
|
}
|
|
}
|
|
if (i == heading->count || data->type_vector[i] == EMPTY || data->count <= i) {
|
|
n_user = -1;
|
|
#ifdef SKIP
|
|
for (i = 0; i < count_solution; i++) {
|
|
if (n_user <= solution[i]->n_user) {
|
|
n_user = solution[i]->n_user + 1;
|
|
}
|
|
}
|
|
#endif
|
|
} else if (data->type_vector[i] == STRING) {
|
|
input_error++;
|
|
sprintf(error_string,"Expected solution number or number range in 'number' column, found: %s.", data->char_vector[i]);
|
|
error_msg(error_string, CONTINUE);
|
|
} else {
|
|
strcpy(string, "solution_s ");
|
|
strcat(string, data->char_vector[i]);
|
|
ptr = string;
|
|
description = (char *) free_check_null(description);
|
|
next_keyword_save = next_keyword;
|
|
next_keyword = 42;
|
|
read_number_description (ptr, &n_user, &n_user_end, &description);
|
|
next_keyword = next_keyword_save;
|
|
}
|
|
/*
|
|
* set up solution
|
|
*/
|
|
|
|
if (n_user >= 0 && solution_bsearch(n_user, &n, FALSE) != NULL) {
|
|
solution_free(solution[n]);
|
|
} else {
|
|
n=count_solution++;
|
|
if (count_solution >= max_solution) {
|
|
space ((void **) ((void *) &(solution)), count_solution, &max_solution, sizeof (struct solution *) );
|
|
}
|
|
}
|
|
solution[n] = solution_alloc();
|
|
|
|
solution[n]->n_user = n_user;
|
|
solution[n]->n_user_end = n_user_end;
|
|
if (use.solution_in == FALSE) {
|
|
use.solution_in = TRUE;
|
|
use.n_solution_user = n_user;
|
|
}
|
|
max_mass_balance=MAX_MASS_BALANCE;
|
|
/*
|
|
* Set default ph, temp, density, pe, units
|
|
*/
|
|
solution[n]->description = description;
|
|
solution[n]->tc=defaults.temp;
|
|
solution[n]->ph=defaults.ph;
|
|
solution[n]->density=defaults.density;
|
|
solution[n]->solution_pe = defaults.pe;
|
|
solution[n]->mass_water=defaults.water;
|
|
solution[n]->ah2o = 1.0;
|
|
solution[n]->mu = 1e-7;
|
|
solution[n]->cb = 0.0;
|
|
default_pe = 0;
|
|
solution[n]->units = defaults.units;
|
|
solution[n]->totals[0].description=NULL;
|
|
count_mass_balance=0;
|
|
count_isotopes = 0;
|
|
default_pe = pe_data_store (&(solution[n]->pe), defaults.redox);
|
|
/*
|
|
* Read concentration data
|
|
*/
|
|
return_value = UNKNOWN;
|
|
for (i = 0; i < heading->count; i++) {
|
|
if (strcmp_nocase(heading->char_vector[i], "number") == 0) continue;
|
|
if (strcmp_nocase(heading->char_vector[i], "uncertainty") == 0) continue;
|
|
if (strcmp_nocase(heading->char_vector[i], "uncertainties") == 0) continue;
|
|
if (strcmp_nocase(heading->char_vector[i], "isotope_uncertainty") == 0) continue;
|
|
/*
|
|
* Copy in element name
|
|
*/
|
|
if (heading->type_vector[i] == EMPTY) continue;
|
|
strcpy(string, heading->char_vector[i]);
|
|
strcat(string, " ");
|
|
/*
|
|
* Copy in concentration data
|
|
*/
|
|
if (i >= data->count || data->type_vector[i] == EMPTY) continue;
|
|
strcat(string, data->char_vector[i]);
|
|
strcat(string, " ");
|
|
/*
|
|
* Copy in concentration data
|
|
*/
|
|
if (units != NULL && i < units->count && units->type_vector[i] != EMPTY) {
|
|
strcat(string, units->char_vector[i]);
|
|
}
|
|
/*
|
|
* Parse string just like read_solution input
|
|
*/
|
|
next_char = string;
|
|
opt = get_option_string(opt_list, count_opt_list, &next_char);
|
|
if (opt == OPTION_DEFAULT && heading->type_vector[i] == NUMBER) {
|
|
opt = 9;
|
|
}
|
|
switch (opt) {
|
|
case OPTION_EOF: /* end of file */
|
|
return_value = EOF;
|
|
break;
|
|
case OPTION_KEYWORD: /* keyword */
|
|
return_value = KEYWORD;
|
|
break;
|
|
case OPTION_ERROR:
|
|
input_error++;
|
|
error_msg("Unknown input in SOLUTION keyword.", CONTINUE);
|
|
error_msg(line_save, CONTINUE);
|
|
break;
|
|
case 0: /* temperature */
|
|
case 1:
|
|
sscanf(next_char,SCANFORMAT, &(solution[n]->tc));
|
|
break;
|
|
case 2: /* density */
|
|
case 3:
|
|
sscanf(next_char,SCANFORMAT, &(solution[n]->density));
|
|
break;
|
|
case 4: /* units */
|
|
case 8: /* unit */
|
|
if (copy_token (token, &next_char, &l) == EMPTY) break;
|
|
if (check_units (token, FALSE, FALSE, solution[n]->units, TRUE) == OK) {
|
|
solution[n]->units = string_hsave(token);
|
|
} else {
|
|
input_error++;
|
|
}
|
|
break;
|
|
case 5: /* redox */
|
|
if (copy_token (token, &next_char, &l) == EMPTY) break;
|
|
if (parse_couple(token) == OK) {
|
|
default_pe = pe_data_store (&(solution[n]->pe), token);
|
|
} else {
|
|
input_error++;
|
|
}
|
|
break;
|
|
case 6: /* ph */
|
|
next_char = string;
|
|
if ( read_conc(n, count_mass_balance, next_char) == ERROR ) {
|
|
input_error++;
|
|
break;
|
|
}
|
|
solution[n]->ph = solution[n]->totals[count_mass_balance].input_conc;
|
|
if (solution[n]->totals[count_mass_balance].equation_name == NULL ) {
|
|
break;
|
|
}
|
|
solution[n]->totals[count_mass_balance].description = string_hsave("H(1)");
|
|
count_mass_balance++;
|
|
break;
|
|
case 7: /* pe */
|
|
next_char = string;
|
|
if ( read_conc(n, count_mass_balance, next_char) == ERROR ) {
|
|
input_error++;
|
|
break;
|
|
}
|
|
solution[n]->solution_pe = solution[n]->totals[count_mass_balance].input_conc;
|
|
if (solution[n]->totals[count_mass_balance].equation_name == NULL ) {
|
|
break;
|
|
}
|
|
solution[n]->totals[count_mass_balance].description = string_hsave("E");
|
|
count_mass_balance++;
|
|
break;
|
|
case 9: /* isotope */
|
|
next_char = string;
|
|
if (copy_token(token, &next_char, &l) != DIGIT) {
|
|
input_error++;
|
|
sprintf(error_string, "Expected isotope name to"
|
|
" begin with an isotopic number.");
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
solution[n]->isotopes = (struct isotope *) PHRQ_realloc(solution[n]->isotopes, (size_t) (count_isotopes + 1) * sizeof(struct isotope));
|
|
if (solution[n]->isotopes == NULL) malloc_error();
|
|
/* read and save element name */
|
|
ptr1 = token;
|
|
get_num(&ptr1, &(solution[n]->isotopes[count_isotopes].isotope_number));
|
|
if (ptr1[0] == '\0' || isupper((int) ptr1[0]) == FALSE) {
|
|
error_msg("Expecting element name.", CONTINUE);
|
|
error_msg(line_save, CONTINUE);
|
|
input_error++;
|
|
return(ERROR);
|
|
}
|
|
solution[n]->isotopes[count_isotopes].elt_name = string_hsave(ptr1);
|
|
|
|
/* read and store isotope ratio */
|
|
if (copy_token(token, &next_char, &l) != DIGIT) {
|
|
input_error++;
|
|
sprintf(error_string, "Expected numeric value for isotope ratio.");
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
sscanf(token, SCANFORMAT, &(solution[n]->isotopes[count_isotopes].ratio));
|
|
|
|
/* read and store isotope ratio uncertainty */
|
|
/* first choice is next column */
|
|
if ((i + 1) < heading->count &&
|
|
(strcmp_nocase(heading->char_vector[i+1], "uncertainty") == 0 ||
|
|
strcmp_nocase(heading->char_vector[i+1], "isotope_uncertainty") == 0 ||
|
|
strcmp_nocase(heading->char_vector[i+1], "uncertainties") == 0) &&
|
|
(i + 1) < data->count &&
|
|
data->type_vector[i+1] == NUMBER) {
|
|
solution[n]->isotopes[count_isotopes].ratio_uncertainty = data->d_vector[i+1];
|
|
} else {
|
|
next_char = string;
|
|
copy_token (token, &next_char, &l);
|
|
for (j = 0; j < defaults.count_iso; j++) {
|
|
if (strcmp(token, defaults.iso[j].name) == 0) {
|
|
solution[n]->isotopes[count_isotopes].ratio_uncertainty = defaults.iso[j].uncertainty;
|
|
break;
|
|
}
|
|
}
|
|
if (j == defaults.count_iso) {
|
|
solution[n]->isotopes[count_isotopes].ratio_uncertainty = NAN;
|
|
}
|
|
}
|
|
count_isotopes++;
|
|
break;
|
|
case 10: /* water */
|
|
j = copy_token (token, &next_char, &l);
|
|
if (j == EMPTY) {
|
|
solution[n]->mass_water=1.0;
|
|
} else if (j != DIGIT) {
|
|
input_error++;
|
|
sprintf(error_string, "Expected numeric value for mass of water in solution.");
|
|
error_msg(error_string, CONTINUE);
|
|
} else {
|
|
sscanf(token, SCANFORMAT, &dummy);
|
|
solution[n]->mass_water = (LDBLE) dummy;
|
|
}
|
|
break;
|
|
case 11: /* description */
|
|
case 12: /* desc */
|
|
case 13: /* descriptor */
|
|
solution[n]->description = (char *) free_check_null(solution[n]->description);
|
|
solution[n]->description = string_duplicate(next_char);
|
|
break;
|
|
case OPTION_DEFAULT:
|
|
/*
|
|
* Read concentration
|
|
*/
|
|
next_char = string;
|
|
if (copy_token (token, &next_char, &l) == LOWER) continue;
|
|
next_char = string;
|
|
if ( read_conc(n, count_mass_balance, next_char) == ERROR ) {
|
|
#ifdef SKIP
|
|
input_error++;
|
|
break;
|
|
#endif
|
|
}
|
|
count_mass_balance++;
|
|
break;
|
|
}
|
|
if (count_mass_balance + 1 >= max_mass_balance) {
|
|
space ((void **) &(solution[n]->totals), count_mass_balance + 1,
|
|
&max_mass_balance, sizeof (struct conc));
|
|
}
|
|
if (return_value == EOF || return_value == KEYWORD) break;
|
|
}
|
|
/*
|
|
* Sort totals by description
|
|
*/
|
|
qsort (solution[n]->totals,
|
|
(size_t) count_mass_balance,
|
|
(size_t) sizeof(struct conc),
|
|
conc_compare);
|
|
/*
|
|
* fix up default units and default pe
|
|
*/
|
|
for (i=0; i < count_mass_balance; i++) {
|
|
strcpy(token, solution[n]->totals[i].description);
|
|
str_tolower(token);
|
|
if (solution[n]->totals[i].units == NULL) {
|
|
solution[n]->totals[i].units = solution[n]->units;
|
|
} else {
|
|
alk = FALSE;
|
|
if (strstr(token, "alk") == token) alk = TRUE;
|
|
strcpy(token1, solution[n]->totals[i].units);
|
|
if (check_units (token1, alk, TRUE, solution[n]->units, TRUE) == ERROR ) {
|
|
input_error++;
|
|
} else {
|
|
solution[n]->totals[i].units = string_hsave(token1);
|
|
}
|
|
}
|
|
if (solution[n]->totals[i].n_pe < 0) {
|
|
solution[n]->totals[i].n_pe = default_pe;
|
|
}
|
|
}
|
|
solution[n]->default_pe = default_pe;
|
|
/*
|
|
* Mark end of solution
|
|
*/
|
|
solution[n]->totals[count_mass_balance].description = NULL;
|
|
solution[n]->count_isotopes = count_isotopes;
|
|
if (count_isotopes > 0) {
|
|
qsort (solution[n]->isotopes,
|
|
(size_t) count_isotopes,
|
|
(size_t) sizeof(struct isotope),
|
|
isotope_compare);
|
|
} else {
|
|
solution[n]->isotopes = (struct isotope *) free_check_null(solution[n]->isotopes);
|
|
}
|
|
return(return_value);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
struct spread_row *string_to_spread_row(char *string)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
int j, l;
|
|
int length = 10;
|
|
char token[MAX_LENGTH];
|
|
char *ptr;
|
|
struct spread_row *spread_row_ptr;
|
|
/*
|
|
* Allocate space
|
|
*/
|
|
spread_row_ptr = (struct spread_row *) PHRQ_malloc((size_t) sizeof(struct spread_row));
|
|
if (spread_row_ptr == NULL) malloc_error();
|
|
spread_row_ptr->char_vector = (char **) PHRQ_malloc((size_t) length * sizeof(char *));
|
|
if (spread_row_ptr->char_vector == NULL) malloc_error();
|
|
spread_row_ptr->d_vector = (LDBLE *) PHRQ_malloc((size_t) length * sizeof(LDBLE));
|
|
if (spread_row_ptr->d_vector == NULL) malloc_error();
|
|
spread_row_ptr->type_vector = (int *) PHRQ_malloc((size_t) length * sizeof(int));
|
|
if (spread_row_ptr->type_vector == NULL) malloc_error();
|
|
spread_row_ptr->count = 0;
|
|
spread_row_ptr->empty = 0;
|
|
spread_row_ptr->string = 0;
|
|
spread_row_ptr->number = 0;
|
|
ptr = string;
|
|
/*
|
|
* Split by tabs, reallocate space
|
|
*/
|
|
for (;;) {
|
|
if (spread_row_ptr->count + 1 > length) {
|
|
length *= 2;
|
|
|
|
spread_row_ptr->char_vector = (char **) PHRQ_realloc(spread_row_ptr->char_vector, (size_t) length * sizeof(char *));
|
|
if (spread_row_ptr->char_vector == NULL) malloc_error();
|
|
|
|
spread_row_ptr->d_vector = (LDBLE *) PHRQ_realloc(spread_row_ptr->d_vector, (size_t) length * sizeof(LDBLE));
|
|
if (spread_row_ptr->d_vector == NULL) malloc_error();
|
|
|
|
spread_row_ptr->type_vector = (int *) PHRQ_realloc(spread_row_ptr->type_vector, (size_t) length * sizeof(int));
|
|
if (spread_row_ptr->type_vector == NULL) malloc_error();
|
|
}
|
|
j = copy_token_tab(token, &ptr, &l);
|
|
if (j == EOL) break;
|
|
spread_row_ptr->char_vector[spread_row_ptr->count] = string_duplicate(token);
|
|
spread_row_ptr->d_vector[spread_row_ptr->count] = NAN;
|
|
if (j == EMPTY || l == 0) {
|
|
spread_row_ptr->empty++;
|
|
spread_row_ptr->type_vector[spread_row_ptr->count] = EMPTY;
|
|
} else if (j == UPPER || j == LOWER) {
|
|
spread_row_ptr->string++;
|
|
spread_row_ptr->type_vector[spread_row_ptr->count] = STRING;
|
|
} else if (j == DIGIT) {
|
|
spread_row_ptr->number++;
|
|
spread_row_ptr->d_vector[spread_row_ptr->count] = strtod(token, NULL);
|
|
spread_row_ptr->type_vector[spread_row_ptr->count] = NUMBER;
|
|
}
|
|
spread_row_ptr->count++;
|
|
}
|
|
/*
|
|
* Clean up and return
|
|
*/
|
|
if (spread_row_ptr->count == 0) {
|
|
spread_row_ptr->char_vector = (char **) free_check_null(spread_row_ptr->char_vector);
|
|
spread_row_ptr->d_vector = (LDBLE *) free_check_null(spread_row_ptr->d_vector);
|
|
spread_row_ptr->type_vector = (int *) free_check_null(spread_row_ptr->type_vector);
|
|
} else {
|
|
spread_row_ptr->char_vector = (char **) PHRQ_realloc(spread_row_ptr->char_vector, (size_t) spread_row_ptr->count * sizeof(char *));
|
|
if (spread_row_ptr->char_vector == NULL) malloc_error();
|
|
spread_row_ptr->d_vector = (LDBLE *) PHRQ_realloc(spread_row_ptr->d_vector, (size_t) spread_row_ptr->count * sizeof(LDBLE));
|
|
if (spread_row_ptr->d_vector == NULL) malloc_error();
|
|
spread_row_ptr->type_vector = (int *) PHRQ_realloc(spread_row_ptr->type_vector, (size_t) spread_row_ptr->count * sizeof(int));
|
|
if (spread_row_ptr->type_vector == NULL) malloc_error();
|
|
|
|
}
|
|
return (spread_row_ptr);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
int spread_row_free(struct spread_row *spread_row_ptr)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
int i;
|
|
|
|
if (spread_row_ptr == NULL) return(OK);
|
|
for (i = 0; i< spread_row_ptr->count; i++) {
|
|
spread_row_ptr->char_vector[i] = (char *) free_check_null(spread_row_ptr->char_vector[i]);
|
|
}
|
|
|
|
spread_row_ptr->char_vector = (char **) free_check_null(spread_row_ptr->char_vector);
|
|
spread_row_ptr->d_vector = (double *) free_check_null(spread_row_ptr->d_vector);
|
|
spread_row_ptr->type_vector = (int *) free_check_null(spread_row_ptr->type_vector);
|
|
spread_row_ptr = (struct spread_row *) free_check_null(spread_row_ptr);
|
|
return(OK);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int copy_token_tab(char *token_ptr, char **ptr, int *length)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Copies from **ptr to *token_ptr until first tab is encountered.
|
|
*
|
|
* Arguments:
|
|
* *token_ptr output, place to store token
|
|
*
|
|
* **ptr input, character string to read token from
|
|
* output, next position after token
|
|
*
|
|
* length output, length of token
|
|
*
|
|
* Returns:
|
|
* UPPER,
|
|
* LOWER,
|
|
* DIGIT,
|
|
* EMPTY,
|
|
* EOL,
|
|
* UNKNOWN.
|
|
*/
|
|
int i, j, return_value;
|
|
char c;
|
|
/*
|
|
* Strip leading spaces
|
|
*/
|
|
while ( (c=**ptr) == ' ' ) (*ptr)++;
|
|
/*
|
|
* Check what we have
|
|
*/
|
|
if ( isupper((int) c) ) {
|
|
return_value=UPPER;
|
|
} else if ( islower((int) c) ) {
|
|
return_value=LOWER;
|
|
} else if ( isdigit((int) c) || c=='.' || c=='-') {
|
|
return_value=DIGIT;
|
|
} else if ( c == '\0') {
|
|
return_value=EOL;
|
|
return(return_value);
|
|
} else if ( c == '\t') {
|
|
return_value=EMPTY;
|
|
} else {
|
|
return_value=UNKNOWN;
|
|
}
|
|
/*
|
|
* Begin copying to token
|
|
*/
|
|
i=0;
|
|
#ifdef SKIP
|
|
while ( (c=**ptr) != '\t' &&
|
|
c != '\0' ) {
|
|
token_ptr[i]=c;
|
|
(*ptr)++;
|
|
i++;
|
|
}
|
|
#endif
|
|
for (;;) {
|
|
c=**ptr;
|
|
if (c == '\t') {
|
|
(*ptr)++;
|
|
break;
|
|
} else if (c =='\0') {
|
|
break;
|
|
} else {
|
|
token_ptr[i]=c;
|
|
(*ptr)++;
|
|
i++;
|
|
}
|
|
}
|
|
token_ptr[i]='\0';
|
|
*length=i;
|
|
/*
|
|
* Strip trailing spaces
|
|
*/
|
|
for (j = i-1; j >= 0; j--) {
|
|
if (j != ' ') break;
|
|
}
|
|
if (j != i-1) {
|
|
token_ptr[j+1]='\0';
|
|
*length=j+1;
|
|
}
|
|
return(return_value);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
static int get_option_string (const char **opt_list, int count_opt_list, char **next_char)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Read a line and check for options
|
|
*/
|
|
int j;
|
|
int opt_l, opt;
|
|
char *opt_ptr;
|
|
char option[MAX_LENGTH];
|
|
|
|
opt_ptr = *next_char;
|
|
if (opt_ptr[0] == '-') {
|
|
opt_ptr++;
|
|
copy_token(option, &opt_ptr, &opt_l);
|
|
if (find_option(&(option[1]), &opt, opt_list, count_opt_list, FALSE) == OK) {
|
|
j = opt;
|
|
*next_char = opt_ptr;
|
|
} else {
|
|
error_msg("Unknown option.", CONTINUE);
|
|
error_msg(*next_char, CONTINUE);
|
|
input_error++;
|
|
j = OPTION_ERROR;
|
|
}
|
|
} else {
|
|
copy_token(option, &opt_ptr, &opt_l);
|
|
if (find_option(&(option[0]), &opt, opt_list, count_opt_list, TRUE) == OK) {
|
|
j = opt;
|
|
*next_char = opt_ptr;
|
|
} else {
|
|
j = OPTION_DEFAULT;
|
|
}
|
|
}
|
|
return (j);
|
|
}
|
|
#ifdef PHREEQCI_GUI
|
|
/* ---------------------------------------------------------------------- */
|
|
void free_spread(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
int i;
|
|
spread_row_free(g_spread_sheet.heading);
|
|
spread_row_free(g_spread_sheet.units);
|
|
for (i = 0; i < g_spread_sheet.count_rows; i++)
|
|
{
|
|
spread_row_free(g_spread_sheet.rows[i]);
|
|
}
|
|
g_spread_sheet.rows = free_check_null(g_spread_sheet.rows);
|
|
|
|
for (i = 0; i < g_spread_sheet.defaults.count_iso; i++)
|
|
{
|
|
g_spread_sheet.defaults.iso[i].name = free_check_null(g_spread_sheet.defaults.iso[i].name);
|
|
}
|
|
g_spread_sheet.defaults.iso = free_check_null(g_spread_sheet.defaults.iso);
|
|
|
|
g_spread_sheet.defaults.redox = free_check_null(g_spread_sheet.defaults.redox);
|
|
g_spread_sheet.defaults.units = free_check_null(g_spread_sheet.defaults.units);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
void add_row(struct spread_row *spread_row_ptr)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
g_spread_sheet.rows = (struct spread_row **) PHRQ_realloc(g_spread_sheet.rows, sizeof(struct spread_row*) * (g_spread_sheet.count_rows + 1));
|
|
if (g_spread_sheet.rows == NULL)
|
|
{
|
|
malloc_error();
|
|
}
|
|
else
|
|
{
|
|
g_spread_sheet.rows[g_spread_sheet.count_rows++] = copy_row(spread_row_ptr);
|
|
}
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
struct spread_row *copy_row(struct spread_row *spread_row_ptr)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
int i;
|
|
struct spread_row *new_spread_row_ptr;
|
|
/*
|
|
* Allocate space
|
|
*/
|
|
new_spread_row_ptr = (struct spread_row *) PHRQ_malloc((size_t) sizeof(struct spread_row));
|
|
if (new_spread_row_ptr == NULL) malloc_error();
|
|
new_spread_row_ptr->char_vector = (char **) PHRQ_malloc((size_t) spread_row_ptr->count * sizeof(char *));
|
|
if (new_spread_row_ptr->char_vector == NULL) malloc_error();
|
|
new_spread_row_ptr->d_vector = (LDBLE *) PHRQ_malloc((size_t) spread_row_ptr->count * sizeof(LDBLE));
|
|
if (new_spread_row_ptr->d_vector == NULL) malloc_error();
|
|
new_spread_row_ptr->type_vector = (int *) PHRQ_malloc((size_t) spread_row_ptr->count * sizeof(int));
|
|
if (new_spread_row_ptr->type_vector == NULL) malloc_error();
|
|
|
|
for (i = 0; i < spread_row_ptr->count; i++)
|
|
{
|
|
new_spread_row_ptr->char_vector[i] = string_duplicate(spread_row_ptr->char_vector[i]);
|
|
new_spread_row_ptr->d_vector[i] = spread_row_ptr->d_vector[i];
|
|
new_spread_row_ptr->type_vector[i] = spread_row_ptr->type_vector[i];
|
|
}
|
|
new_spread_row_ptr->count = spread_row_ptr->count;
|
|
new_spread_row_ptr->empty = spread_row_ptr->empty;
|
|
new_spread_row_ptr->number = spread_row_ptr->number;
|
|
new_spread_row_ptr->string = spread_row_ptr->string;
|
|
|
|
return new_spread_row_ptr;
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
void copy_defaults(struct defaults *dest_ptr, struct defaults *src_ptr)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
int i;
|
|
dest_ptr->count_iso = src_ptr->count_iso;
|
|
dest_ptr->density = src_ptr->density;
|
|
dest_ptr->iso = (struct iso*)PHRQ_malloc(sizeof(struct iso) * src_ptr->count_iso);
|
|
if (dest_ptr->iso == NULL)
|
|
{
|
|
malloc_error();
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < src_ptr->count_iso; i++)
|
|
{
|
|
dest_ptr->iso[i] = src_ptr->iso[i];
|
|
dest_ptr->iso[i].name = string_duplicate(src_ptr->iso[i].name);
|
|
}
|
|
}
|
|
|
|
dest_ptr->pe = src_ptr->pe;
|
|
dest_ptr->ph = src_ptr->ph;
|
|
dest_ptr->redox = string_duplicate(src_ptr->redox);
|
|
dest_ptr->temp = src_ptr->temp;
|
|
dest_ptr->units = string_duplicate(src_ptr->units);
|
|
dest_ptr->water = src_ptr->water;
|
|
}
|
|
|
|
#endif
|