2000-05-06 16:12:51 +02:00
|
|
|
/* The 'compose' command. This is a more powerful and convenient form
|
|
|
|
|
* of the 'let' command. */
|
2011-12-11 19:05:00 +01:00
|
|
|
#include "ngspice/ngspice.h"
|
|
|
|
|
#include "ngspice/complex.h"
|
|
|
|
|
#include "ngspice/dvec.h"
|
|
|
|
|
#include "ngspice/bool.h"
|
|
|
|
|
#include "ngspice/sim.h"
|
|
|
|
|
#include "ngspice/pnode.h"
|
|
|
|
|
#include "ngspice/fteext.h"
|
|
|
|
|
#include "ngspice/cpextern.h"
|
2019-07-20 17:33:58 +02:00
|
|
|
#include "ngspice/randnumb.h"
|
2000-04-27 22:03:57 +02:00
|
|
|
|
* frontend/Makefile.am: Updates for new files.
* frontend/breakp2.c, frontend/newcoms.c, frontend/postcoms.c,
frontend/resource.c, frontend/terminal.h, frontend/variable.c,
frontend/variable.h, frontend/com_compose.c,
frontend/com_display.c, frontend/com_setscale.c,
frontend/com_strcmp.c: Include files update.
* parser/var2.c, parser/var2.h: Empty files, removed.
* parser/Makefile.am: Updates for removed files.
* parser/lexical.c: Small adjustments
* parser/input.c, parser/input.h: Input, output and error streams
handled in the frontend. Moved to the frontend directory.
* frontend/streams.c: Its new home.
2000-07-07 16:09:06 +02:00
|
|
|
#include "quote.h"
|
2000-05-06 16:12:51 +02:00
|
|
|
#include "com_compose.h"
|
|
|
|
|
#include "completion.h"
|
|
|
|
|
|
2019-07-20 17:33:58 +02:00
|
|
|
#include <math.h> /* log10 */
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2000-05-06 16:12:51 +02:00
|
|
|
/* Copy the data from a vector into a buffer with larger dimensions. */
|
|
|
|
|
static void
|
|
|
|
|
dimxpand(struct dvec *v, int *newdims, double *data)
|
|
|
|
|
{
|
2010-10-24 14:45:05 +02:00
|
|
|
ngcomplex_t *cdata = (ngcomplex_t *) data;
|
2000-05-06 16:12:51 +02:00
|
|
|
bool realflag = isreal(v);
|
|
|
|
|
int i, j, o, n, t, u;
|
|
|
|
|
int ncount[MAXDIMS], ocount[MAXDIMS];
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < MAXDIMS; i++)
|
|
|
|
|
ncount[i] = ocount[i] = 0;
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2000-05-06 16:12:51 +02:00
|
|
|
for (;;) {
|
|
|
|
|
for (o = n = i = 0; i < v->v_numdims; i++) {
|
|
|
|
|
for (j = i, t = u = 1; j < v->v_numdims; j++) {
|
|
|
|
|
t *= v->v_dims[j];
|
|
|
|
|
u *= newdims[j];
|
|
|
|
|
}
|
|
|
|
|
o += ocount[i] * t;
|
|
|
|
|
n += ncount[i] * u;
|
|
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2000-05-06 16:12:51 +02:00
|
|
|
if (realflag) {
|
|
|
|
|
data[n] = v->v_realdata[o];
|
|
|
|
|
} else {
|
2015-12-29 18:15:06 +01:00
|
|
|
cdata[n] = v->v_compdata[o];
|
2000-05-06 16:12:51 +02:00
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2000-05-06 16:12:51 +02:00
|
|
|
/* Now find the nextstrchr element... */
|
2012-09-20 20:30:53 +02:00
|
|
|
for (i = v->v_numdims - 1; i >= 0; i--)
|
|
|
|
|
if ((ocount[i] < v->v_dims[i] - 1) && (ncount[i] < newdims[i] - 1)) {
|
2000-05-06 16:12:51 +02:00
|
|
|
ocount[i]++;
|
|
|
|
|
ncount[i]++;
|
|
|
|
|
break;
|
2012-09-20 20:30:53 +02:00
|
|
|
} else {
|
2000-05-06 16:12:51 +02:00
|
|
|
ocount[i] = ncount[i] = 0;
|
2012-09-20 20:30:53 +02:00
|
|
|
}
|
|
|
|
|
|
2000-05-06 16:12:51 +02:00
|
|
|
if (i < 0)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/* The general syntax is 'compose name parm = val ...'
|
|
|
|
|
* The possible parms are:
|
|
|
|
|
* start The value at which the vector should start.
|
|
|
|
|
* stop The value at which the vector should end.
|
2019-07-20 17:33:58 +02:00
|
|
|
* step The difference between successive elements.
|
2010-03-20 16:28:54 +01:00
|
|
|
* lin The number of points, linearly spaced.
|
|
|
|
|
* log The number of points, logarithmically spaced.
|
|
|
|
|
* dec The number of points per decade, logarithmically spaced.
|
2019-07-20 17:33:58 +02:00
|
|
|
* oct The number of points per octave, logarithmically spaced.
|
2000-04-27 22:03:57 +02:00
|
|
|
* center Where to center the range of points.
|
|
|
|
|
* span The size of the range of points.
|
|
|
|
|
* gauss The number of points in the gaussian distribution.
|
2019-07-20 17:33:58 +02:00
|
|
|
* mean The mean value for the gaussian or uniform distributions.
|
|
|
|
|
* sd The standard deviation for the gaussian distribution.
|
|
|
|
|
* unif The number of points in the uniform distribution.
|
2000-04-27 22:03:57 +02:00
|
|
|
*
|
|
|
|
|
* The case 'compose name values val val ...' takes the values and creates a
|
2019-07-20 17:33:58 +02:00
|
|
|
* new vector -- the vals may be arbitrary expressions. Negative vals have to
|
|
|
|
|
* be put into brackets, like (-1.6).
|
2000-04-27 22:03:57 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
com_compose(wordlist *wl)
|
|
|
|
|
{
|
2000-05-06 16:12:51 +02:00
|
|
|
double start = 0.0;
|
|
|
|
|
double stop = 0.0;
|
|
|
|
|
double step = 0.0;
|
|
|
|
|
double lin = 0.0;
|
2019-07-20 17:33:58 +02:00
|
|
|
double center = 0.0;
|
|
|
|
|
double span = 0.0;
|
|
|
|
|
double mean = 0.0;
|
|
|
|
|
double sd = 0.0;
|
2000-04-27 22:03:57 +02:00
|
|
|
bool startgiven = FALSE, stopgiven = FALSE, stepgiven = FALSE;
|
|
|
|
|
bool lingiven = FALSE;
|
2019-07-20 17:33:58 +02:00
|
|
|
bool loggiven = FALSE, decgiven = FALSE, octgiven = FALSE, gaussgiven = FALSE;
|
|
|
|
|
bool unifgiven = FALSE;
|
2000-04-27 22:03:57 +02:00
|
|
|
bool spangiven = FALSE;
|
|
|
|
|
bool centergiven = FALSE;
|
|
|
|
|
bool meangiven = FALSE;
|
|
|
|
|
bool sdgiven = FALSE;
|
2019-07-20 17:33:58 +02:00
|
|
|
int log = 0, dec = 0, oct = 0, gauss = 0, unif = 0;
|
2000-04-27 22:03:57 +02:00
|
|
|
int i;
|
|
|
|
|
|
2012-10-01 18:31:02 +02:00
|
|
|
char *s, *var, *val;
|
2000-04-27 22:03:57 +02:00
|
|
|
double *td, tt;
|
2000-05-06 16:12:51 +02:00
|
|
|
double *data = NULL;
|
2010-10-24 14:45:05 +02:00
|
|
|
ngcomplex_t *cdata = NULL;
|
2000-05-06 16:12:51 +02:00
|
|
|
int length = 0;
|
|
|
|
|
int dim, type = SV_NOTYPE, blocksize;
|
2000-04-27 22:03:57 +02:00
|
|
|
bool realflag = TRUE;
|
|
|
|
|
int dims[MAXDIMS];
|
|
|
|
|
struct dvec *result, *vecs = NULL, *v, *lv = NULL;
|
2012-09-30 22:36:12 +02:00
|
|
|
struct pnode *pn, *names = NULL;
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2012-10-01 18:31:02 +02:00
|
|
|
char *resname = cp_unquote(wl->wl_word);
|
|
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
vec_remove(resname);
|
|
|
|
|
wl = wl->wl_next;
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
if (eq(wl->wl_word, "values")) {
|
|
|
|
|
/* Build up the vector from the rest of the line... */
|
|
|
|
|
wl = wl->wl_next;
|
2012-09-30 22:50:23 +02:00
|
|
|
|
|
|
|
|
names = ft_getpnames(wl, TRUE);
|
|
|
|
|
if (!names)
|
2012-10-01 18:31:02 +02:00
|
|
|
goto done;
|
2012-09-30 22:50:23 +02:00
|
|
|
|
|
|
|
|
for (pn = names; pn; pn = pn->pn_next) {
|
2010-11-19 19:54:40 +01:00
|
|
|
if ((v = ft_evaluate(pn)) == NULL)
|
2012-10-01 18:31:02 +02:00
|
|
|
goto done;
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
if (!vecs)
|
|
|
|
|
vecs = lv = v;
|
|
|
|
|
else
|
|
|
|
|
lv->v_link2 = v;
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
for (lv = v; lv->v_link2; lv = lv->v_link2)
|
|
|
|
|
;
|
|
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
/* Now make sure these are all of the same dimensionality. We
|
|
|
|
|
* can coerce the sizes...
|
|
|
|
|
*/
|
|
|
|
|
dim = vecs->v_numdims;
|
|
|
|
|
if (dim < 2)
|
|
|
|
|
dim = (vecs->v_length > 1) ? 1 : 0;
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
if (dim == MAXDIMS) {
|
2019-07-20 17:33:58 +02:00
|
|
|
fprintf(cp_err, "Error: compose -> max dimensionality is %d\n",
|
2000-04-27 22:03:57 +02:00
|
|
|
MAXDIMS);
|
2012-10-01 18:31:02 +02:00
|
|
|
goto done;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
for (v = vecs; v; v = v->v_link2)
|
|
|
|
|
if (v->v_numdims < 2)
|
|
|
|
|
v->v_dims[0] = v->v_length;
|
|
|
|
|
|
2019-05-01 11:57:16 +02:00
|
|
|
/* Init real flag according to type of first element */
|
|
|
|
|
realflag = !iscomplex(vecs);
|
|
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
for (v = vecs->v_link2, length = 1; v; v = v->v_link2) {
|
|
|
|
|
i = v->v_numdims;
|
|
|
|
|
if (i < 2)
|
|
|
|
|
i = (v->v_length > 1) ? 1 : 0;
|
|
|
|
|
if (i != dim) {
|
|
|
|
|
fprintf(cp_err,
|
2019-07-20 17:33:58 +02:00
|
|
|
"Error: compose -> all vectors must be of the same dimensionality\n");
|
2012-10-01 18:31:02 +02:00
|
|
|
goto done;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
length++;
|
|
|
|
|
if (iscomplex(v))
|
|
|
|
|
realflag = FALSE;
|
|
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
for (i = 0; i < dim; i++) {
|
|
|
|
|
dims[i] = vecs->v_dims[i];
|
|
|
|
|
for (v = vecs->v_link2; v; v = v->v_link2)
|
|
|
|
|
if (v->v_dims[i] > dims[i])
|
|
|
|
|
dims[i] = v->v_dims[i];
|
|
|
|
|
}
|
|
|
|
|
dim++;
|
|
|
|
|
dims[dim - 1] = length;
|
|
|
|
|
for (i = 0, blocksize = 1; i < dim - 1; i++)
|
|
|
|
|
blocksize *= dims[i];
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
if (realflag)
|
2010-10-28 21:32:34 +02:00
|
|
|
data = TMALLOC(double, length * blocksize);
|
2000-04-27 22:03:57 +02:00
|
|
|
else
|
2010-10-28 21:32:34 +02:00
|
|
|
cdata = TMALLOC(ngcomplex_t, length * blocksize);
|
2000-04-27 22:03:57 +02:00
|
|
|
|
|
|
|
|
/* Now copy all the data over... If the sizes are too small
|
|
|
|
|
* then the extra elements are left as 0.
|
|
|
|
|
*/
|
|
|
|
|
for (v = vecs, i = 0; v; v = v->v_link2) {
|
|
|
|
|
if (dim == 1) {
|
2019-05-01 12:43:51 +02:00
|
|
|
/* 3 possibilities
|
|
|
|
|
* 1) Composed vector is real (and current value is real)
|
|
|
|
|
* 2) Composed vector is complex
|
|
|
|
|
* a) and current value is real
|
|
|
|
|
* b) and current value is complex
|
|
|
|
|
* It is not possible for the composed vector to be real and
|
|
|
|
|
* the current value to be complex because it would have
|
|
|
|
|
* caused the composed vector to be complex. */
|
|
|
|
|
if (realflag) { /* composed vector is real */
|
2000-04-27 22:03:57 +02:00
|
|
|
data[i] = v->v_realdata[0];
|
|
|
|
|
}
|
2019-05-01 12:43:51 +02:00
|
|
|
else { /* complex composed vector */
|
|
|
|
|
ngcomplex_t *cdata_cur = cdata + i;
|
|
|
|
|
if (isreal(v)) {
|
|
|
|
|
/* Current value is real, so build complex value from it
|
|
|
|
|
* and no imaginary part */
|
|
|
|
|
realpart(*cdata_cur) = *v->v_realdata;
|
|
|
|
|
imagpart(*cdata_cur) = 0.0;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
*cdata_cur = *v->v_compdata;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
i++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
dimxpand(v, dims, (realflag ? (data + i * blocksize) :
|
|
|
|
|
(double *) (cdata + i * blocksize)));
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
length *= blocksize;
|
|
|
|
|
} else {
|
|
|
|
|
/* Parse the line... */
|
|
|
|
|
while (wl) {
|
2010-11-19 19:52:44 +01:00
|
|
|
if ((s = strchr(wl->wl_word, '=')) != NULL && s[1]) {
|
2000-04-27 22:03:57 +02:00
|
|
|
/* This is var=val. */
|
|
|
|
|
*s = '\0';
|
|
|
|
|
var = wl->wl_word;
|
|
|
|
|
val = s + 1;
|
|
|
|
|
wl = wl->wl_next;
|
2012-02-06 18:46:33 +01:00
|
|
|
} else if (strchr(wl->wl_word, '=')) {
|
2000-04-27 22:03:57 +02:00
|
|
|
/* This is var= val. */
|
|
|
|
|
*s = '\0';
|
|
|
|
|
var = wl->wl_word;
|
|
|
|
|
wl = wl->wl_next;
|
|
|
|
|
if (wl) {
|
|
|
|
|
val = wl->wl_word;
|
|
|
|
|
wl = wl->wl_next;
|
|
|
|
|
} else {
|
2019-07-20 17:33:58 +02:00
|
|
|
fprintf(cp_err, "Error: compose -> bad syntax\n");
|
2012-10-01 18:31:02 +02:00
|
|
|
goto done;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
/* This is var =val or var = val. */
|
|
|
|
|
var = wl->wl_word;
|
|
|
|
|
wl = wl->wl_next;
|
|
|
|
|
if (wl) {
|
|
|
|
|
val = wl->wl_word;
|
|
|
|
|
if (*val != '=') {
|
|
|
|
|
fprintf(cp_err,
|
2019-07-20 17:33:58 +02:00
|
|
|
"Error: compose -> bad syntax\n");
|
2012-10-01 18:31:02 +02:00
|
|
|
goto done;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
val++;
|
|
|
|
|
if (!*val) {
|
|
|
|
|
wl = wl->wl_next;
|
|
|
|
|
if (wl) {
|
|
|
|
|
val = wl->wl_word;
|
|
|
|
|
} else {
|
|
|
|
|
fprintf(cp_err,
|
2019-07-20 17:33:58 +02:00
|
|
|
"Error: compose -> bad syntax\n");
|
2012-10-01 18:31:02 +02:00
|
|
|
goto done;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
wl = wl->wl_next;
|
|
|
|
|
} else {
|
2019-07-20 17:33:58 +02:00
|
|
|
fprintf(cp_err, "Error: compose -> bad syntax\n");
|
2012-10-01 18:31:02 +02:00
|
|
|
goto done;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (cieq(var, "start")) {
|
|
|
|
|
startgiven = TRUE;
|
2010-11-19 19:54:40 +01:00
|
|
|
if ((td = ft_numparse(&val, FALSE)) == NULL) {
|
2000-04-27 22:03:57 +02:00
|
|
|
fprintf(cp_err,
|
2019-07-20 17:33:58 +02:00
|
|
|
"Error: compose -> bad parm %s = %s\n", var, val);
|
2012-10-01 18:31:02 +02:00
|
|
|
goto done;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
start = *td;
|
|
|
|
|
} else if (cieq(var, "stop")) {
|
|
|
|
|
stopgiven = TRUE;
|
2010-11-19 19:54:40 +01:00
|
|
|
if ((td = ft_numparse(&val, FALSE)) == NULL) {
|
2000-04-27 22:03:57 +02:00
|
|
|
fprintf(cp_err,
|
2019-07-20 17:33:58 +02:00
|
|
|
"Error: compose -> bad parm %s = %s\n", var, val);
|
2012-10-01 18:31:02 +02:00
|
|
|
goto done;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
stop = *td;
|
|
|
|
|
} else if (cieq(var, "step")) {
|
|
|
|
|
stepgiven = TRUE;
|
2010-11-19 19:54:40 +01:00
|
|
|
if ((td = ft_numparse(&val, FALSE)) == NULL) {
|
2000-04-27 22:03:57 +02:00
|
|
|
fprintf(cp_err,
|
2019-07-20 17:33:58 +02:00
|
|
|
"Error: compose -> bad parm %s = %s\n", var, val);
|
2012-10-01 18:31:02 +02:00
|
|
|
goto done;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
step = *td;
|
|
|
|
|
} else if (cieq(var, "center")) {
|
|
|
|
|
centergiven = TRUE;
|
2010-11-19 19:54:40 +01:00
|
|
|
if ((td = ft_numparse(&val, FALSE)) == NULL) {
|
2000-04-27 22:03:57 +02:00
|
|
|
fprintf(cp_err,
|
2019-07-20 17:33:58 +02:00
|
|
|
"Error: compose -> bad parm %s = %s\n", var, val);
|
2012-10-01 18:31:02 +02:00
|
|
|
goto done;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
center = *td;
|
|
|
|
|
} else if (cieq(var, "span")) {
|
|
|
|
|
spangiven = TRUE;
|
2010-11-19 19:54:40 +01:00
|
|
|
if ((td = ft_numparse(&val, FALSE)) == NULL) {
|
2000-04-27 22:03:57 +02:00
|
|
|
fprintf(cp_err,
|
2019-07-20 17:33:58 +02:00
|
|
|
"Error: compose -> bad parm %s = %s\n", var, val);
|
2012-10-01 18:31:02 +02:00
|
|
|
goto done;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
span = *td;
|
|
|
|
|
} else if (cieq(var, "mean")) {
|
|
|
|
|
meangiven = TRUE;
|
2010-11-19 19:54:40 +01:00
|
|
|
if ((td = ft_numparse(&val, FALSE)) == NULL) {
|
2000-04-27 22:03:57 +02:00
|
|
|
fprintf(cp_err,
|
2019-07-20 17:33:58 +02:00
|
|
|
"Error: compose -> bad parm %s = %s\n", var, val);
|
2012-10-01 18:31:02 +02:00
|
|
|
goto done;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
mean = *td;
|
|
|
|
|
} else if (cieq(var, "sd")) {
|
|
|
|
|
sdgiven = TRUE;
|
2010-11-19 19:54:40 +01:00
|
|
|
if ((td = ft_numparse(&val, FALSE)) == NULL) {
|
2000-04-27 22:03:57 +02:00
|
|
|
fprintf(cp_err,
|
2019-07-20 17:33:58 +02:00
|
|
|
"Error: compose -> bad parm %s = %s\n", var, val);
|
2012-10-01 18:31:02 +02:00
|
|
|
goto done;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
sd = *td;
|
|
|
|
|
} else if (cieq(var, "lin")) {
|
|
|
|
|
lingiven = TRUE;
|
2010-11-19 19:54:40 +01:00
|
|
|
if ((td = ft_numparse(&val, FALSE)) == NULL) {
|
2000-04-27 22:03:57 +02:00
|
|
|
fprintf(cp_err,
|
2019-07-20 17:33:58 +02:00
|
|
|
"Error: compose -> bad parm %s = %s\n", var, val);
|
2012-10-01 18:31:02 +02:00
|
|
|
goto done;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
lin = *td;
|
|
|
|
|
} else if (cieq(var, "log")) {
|
|
|
|
|
loggiven = TRUE;
|
2010-11-19 19:54:40 +01:00
|
|
|
if ((td = ft_numparse(&val, FALSE)) == NULL) {
|
2000-04-27 22:03:57 +02:00
|
|
|
fprintf(cp_err,
|
2019-07-20 17:33:58 +02:00
|
|
|
"Error: compose -> bad parm %s = %s\n", var, val);
|
2012-10-01 18:31:02 +02:00
|
|
|
goto done;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
2011-06-11 19:07:38 +02:00
|
|
|
log = (int)(*td);
|
2000-04-27 22:03:57 +02:00
|
|
|
} else if (cieq(var, "dec")) {
|
|
|
|
|
decgiven = TRUE;
|
2010-11-19 19:54:40 +01:00
|
|
|
if ((td = ft_numparse(&val, FALSE)) == NULL) {
|
2000-04-27 22:03:57 +02:00
|
|
|
fprintf(cp_err,
|
2019-07-20 17:33:58 +02:00
|
|
|
"Error: compose -> bad parm %s = %s\n", var, val);
|
2012-10-01 18:31:02 +02:00
|
|
|
goto done;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
2011-06-11 19:07:38 +02:00
|
|
|
dec = (int)(*td);
|
2019-07-20 17:33:58 +02:00
|
|
|
} else if (cieq(var, "oct")) {
|
|
|
|
|
octgiven = TRUE;
|
|
|
|
|
if ((td = ft_numparse(&val, FALSE)) == NULL) {
|
|
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Error: compose -> bad parm %s = %s\n", var, val);
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
oct = (int)(*td);
|
2000-04-27 22:03:57 +02:00
|
|
|
} else if (cieq(var, "gauss")) {
|
|
|
|
|
gaussgiven = TRUE;
|
2010-11-19 19:54:40 +01:00
|
|
|
if ((td = ft_numparse(&val, FALSE)) == NULL) {
|
2000-04-27 22:03:57 +02:00
|
|
|
fprintf(cp_err,
|
2019-07-20 17:33:58 +02:00
|
|
|
"Error: compose -> bad parm %s = %s\n", var, val);
|
2012-10-01 18:31:02 +02:00
|
|
|
goto done;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
2011-06-11 19:07:38 +02:00
|
|
|
gauss = (int)(*td);
|
2019-07-20 17:33:58 +02:00
|
|
|
} else if (cieq(var, "unif")) {
|
|
|
|
|
unifgiven = TRUE;
|
2010-11-19 19:54:40 +01:00
|
|
|
if ((td = ft_numparse(&val, FALSE)) == NULL) {
|
2000-04-27 22:03:57 +02:00
|
|
|
fprintf(cp_err,
|
2019-07-20 17:33:58 +02:00
|
|
|
"Error: compose -> bad parm %s = %s\n", var, val);
|
2012-10-01 18:31:02 +02:00
|
|
|
goto done;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
2019-07-20 17:33:58 +02:00
|
|
|
unif = (int)(*td);
|
|
|
|
|
} else {
|
|
|
|
|
fprintf(cp_err, "Error: compose -> bad parm %s\n", var);
|
|
|
|
|
goto done;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now see what we have... start and stop are pretty much
|
2019-07-20 17:33:58 +02:00
|
|
|
* compatible with everything (except gauss)...
|
2000-04-27 22:03:57 +02:00
|
|
|
*/
|
2019-07-20 17:33:58 +02:00
|
|
|
if (centergiven && spangiven && !startgiven && !stopgiven) {
|
|
|
|
|
start = center - span/2.0;
|
|
|
|
|
stop = center + span/2.0;
|
|
|
|
|
startgiven = TRUE;
|
|
|
|
|
stopgiven = TRUE;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2019-07-20 17:33:58 +02:00
|
|
|
if (stepgiven && (step == 0.0)) {
|
|
|
|
|
fprintf(cp_err, "Error: compose -> step cannot = 0.0\n");
|
|
|
|
|
goto done;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2019-07-20 17:33:58 +02:00
|
|
|
if (lingiven + loggiven + decgiven + octgiven + unifgiven + gaussgiven > 1) {
|
2000-04-27 22:03:57 +02:00
|
|
|
fprintf(cp_err,
|
2019-07-20 17:33:58 +02:00
|
|
|
"Error: compose -> can have at most one of (lin, log, dec, oct, unif, gauss)\n");
|
2012-10-01 18:31:02 +02:00
|
|
|
goto done;
|
2019-07-20 17:33:58 +02:00
|
|
|
} else if (lingiven + loggiven + decgiven + octgiven + unifgiven + gaussgiven == 0) {
|
2000-04-27 22:03:57 +02:00
|
|
|
/* Hmm, if we have a start, stop, and step we're ok. */
|
|
|
|
|
if (startgiven && stopgiven && stepgiven) {
|
|
|
|
|
lingiven = TRUE;
|
2019-07-20 17:33:58 +02:00
|
|
|
/* Ensure that step has the right sign */
|
|
|
|
|
if ((stop - start > 0) != (step > 0)) {
|
|
|
|
|
step = -step;
|
|
|
|
|
}
|
|
|
|
|
lin = (stop - start) / step + 1.;
|
2000-04-27 22:03:57 +02:00
|
|
|
stepgiven = FALSE; /* Problems below... */
|
|
|
|
|
} else {
|
|
|
|
|
fprintf(cp_err,
|
2019-07-20 17:33:58 +02:00
|
|
|
"Error: compose -> either one of (lin, log, dec, oct, unif, gauss) must be given, or all\n");
|
2000-04-27 22:03:57 +02:00
|
|
|
fprintf(cp_err,
|
2012-09-20 20:30:53 +02:00
|
|
|
"\tof (start, stop, and step) must be given.\n");
|
2012-10-01 18:31:02 +02:00
|
|
|
goto done;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
if (lingiven) {
|
|
|
|
|
/* Create a linear sweep... */
|
2019-07-20 17:33:58 +02:00
|
|
|
if (lin <= 0) {
|
|
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Error: compose -> The number of linearly spaced points, lin, must be positive.\n");
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
2018-08-28 18:45:19 +02:00
|
|
|
length = (int)lin;
|
|
|
|
|
data = TMALLOC(double, length);
|
2000-04-27 22:03:57 +02:00
|
|
|
if (stepgiven && startgiven && stopgiven) {
|
2019-07-20 17:33:58 +02:00
|
|
|
if (step != (stop - start) / (lin - 1.0)) {
|
2012-09-20 20:30:53 +02:00
|
|
|
fprintf(cp_err,
|
2019-07-20 17:33:58 +02:00
|
|
|
"Warning: compose -> bad step -- should be %g. ",
|
|
|
|
|
(stop - start) / (lin - 1.0));
|
|
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Specify only three out of start, stop, step, lin.\n");
|
2000-04-27 22:03:57 +02:00
|
|
|
stepgiven = FALSE;
|
|
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
if (!startgiven) {
|
2012-09-20 20:30:53 +02:00
|
|
|
if (stopgiven && stepgiven)
|
2019-07-20 17:33:58 +02:00
|
|
|
start = stop - step * (lin - 1.0);
|
2012-09-20 20:30:53 +02:00
|
|
|
else if (stopgiven)
|
2019-07-20 17:33:58 +02:00
|
|
|
start = stop - lin + 1.0;
|
2012-09-20 20:30:53 +02:00
|
|
|
else
|
2000-04-27 22:03:57 +02:00
|
|
|
start = 0;
|
|
|
|
|
startgiven = TRUE;
|
|
|
|
|
}
|
|
|
|
|
if (!stopgiven) {
|
|
|
|
|
if (stepgiven)
|
2019-07-20 17:33:58 +02:00
|
|
|
stop = start + step * (lin - 1.0);
|
2000-04-27 22:03:57 +02:00
|
|
|
else
|
2019-07-20 17:33:58 +02:00
|
|
|
stop = start + lin - 1.;
|
2000-04-27 22:03:57 +02:00
|
|
|
stopgiven = TRUE;
|
2012-09-20 20:30:53 +02:00
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
if (!stepgiven) {
|
2019-07-20 17:33:58 +02:00
|
|
|
step = (stop - start) / (lin - 1.0);
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
2018-08-28 18:45:19 +02:00
|
|
|
|
2019-07-20 17:33:58 +02:00
|
|
|
for (i = 0, tt = start; i < length; i++, tt += step)
|
|
|
|
|
data[i] = tt;
|
2018-08-28 18:45:19 +02:00
|
|
|
|
2019-07-20 17:33:58 +02:00
|
|
|
} else if (loggiven || decgiven || octgiven) {
|
2000-04-27 22:03:57 +02:00
|
|
|
/* Create a log sweep... */
|
2019-07-20 17:33:58 +02:00
|
|
|
if (centergiven && spangiven) {
|
|
|
|
|
if (center <= span/2.0) {
|
|
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Error: compose -> center must be greater than span/2\n");
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
if ((center <= 0) || (span <= 0)) {
|
|
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Error: compose -> center and span must be greater than 0\n");
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (startgiven && stopgiven) {
|
|
|
|
|
if ((start <= 0) || (stop <= 0)) {
|
|
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Error: compose -> start and stop must be greater than 0\n");
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Error: compose -> start and stop or center and span needed in case of log, dec or oct\n");
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
if (decgiven) {
|
|
|
|
|
log = (int)round(dec * log10(stop / start)) + 1;
|
|
|
|
|
} else if (octgiven) {
|
|
|
|
|
log = (int)round(oct * log10(stop / start) / log10(2)) + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
length = log;
|
|
|
|
|
data = TMALLOC(double, length);
|
|
|
|
|
|
|
|
|
|
data[0] = start;
|
|
|
|
|
for (i = 0; i < length; i++)
|
|
|
|
|
data[i] = start * pow(stop/start, (double)i/(log-1.0));
|
|
|
|
|
|
|
|
|
|
} else if (unifgiven) {
|
|
|
|
|
/* Create a set of uniform distributed values... */
|
|
|
|
|
if (startgiven || stopgiven) {
|
|
|
|
|
if (!startgiven || !stopgiven) {
|
|
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Error: compose -> For uniform distribution (start, stop) can be only given as bundle.\n");
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
if (meangiven || spangiven) {
|
|
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Error: compose -> For uniform distribution (start, stop) can't be mixed with mean or span.\n");
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
mean = (start + stop) / 2.0;
|
|
|
|
|
span = fabs(stop - start);
|
|
|
|
|
meangiven = TRUE;
|
|
|
|
|
spangiven = TRUE;
|
|
|
|
|
}
|
|
|
|
|
if (unif <= 0) {
|
|
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Error: compose -> The number of uniformly distributed points, unif, must be positive.\n");
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
if (!meangiven) {
|
|
|
|
|
/* Use mean default value 0.5 */
|
|
|
|
|
mean = 0.5;
|
|
|
|
|
}
|
|
|
|
|
if (!spangiven) {
|
|
|
|
|
/* Use span default value 1.0 */
|
|
|
|
|
span = 1.0;
|
|
|
|
|
}
|
|
|
|
|
length = unif;
|
|
|
|
|
data = TMALLOC(double, length);
|
|
|
|
|
for (i = 0; i < length; i++)
|
|
|
|
|
data[i] = mean + span * 0.5 * drand();
|
|
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
} else if (gaussgiven) {
|
|
|
|
|
/* Create a gaussian distribution... */
|
2019-07-20 17:33:58 +02:00
|
|
|
if (gauss <= 0) {
|
|
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Error: compose -> The number of Gaussian distributed points, gauss, must be positive.\n");
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
if (!meangiven) {
|
|
|
|
|
/* Use mean default value 0 */
|
|
|
|
|
mean = 0;
|
|
|
|
|
}
|
|
|
|
|
if (!sdgiven) {
|
|
|
|
|
/* Use sd default value 1.0 */
|
|
|
|
|
sd = 1.0;
|
|
|
|
|
}
|
|
|
|
|
length = gauss;
|
|
|
|
|
data = TMALLOC(double, length);
|
|
|
|
|
for (i = 0; i < length; i++)
|
|
|
|
|
data[i] = mean + sd * gauss1();
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2019-05-01 11:57:16 +02:00
|
|
|
/* Create a vector with the data that was processed */
|
2010-11-04 20:28:00 +01:00
|
|
|
if (realflag) {
|
2015-12-28 20:26:58 +01:00
|
|
|
result = dvec_alloc(resname,
|
|
|
|
|
type,
|
|
|
|
|
VF_REAL | VF_PERMANENT,
|
|
|
|
|
length, data);
|
2010-11-04 20:28:00 +01:00
|
|
|
} else {
|
2015-12-28 20:26:58 +01:00
|
|
|
result = dvec_alloc(resname,
|
|
|
|
|
type,
|
|
|
|
|
VF_COMPLEX | VF_PERMANENT,
|
|
|
|
|
length, cdata);
|
2010-11-04 20:28:00 +01:00
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2019-05-01 11:57:16 +02:00
|
|
|
/* The allocation for resname has been assigned to the result vector, so
|
|
|
|
|
* set to NULL so that it is not freed */
|
|
|
|
|
resname = NULL;
|
2015-12-28 20:24:11 +01:00
|
|
|
|
2019-05-01 11:57:16 +02:00
|
|
|
/* Set dimension info */
|
2000-04-27 22:03:57 +02:00
|
|
|
result->v_numdims = 1;
|
|
|
|
|
result->v_dims[0] = length;
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
vec_new(result);
|
|
|
|
|
cp_addkword(CT_VECTOR, result->v_name);
|
2012-10-01 18:31:02 +02:00
|
|
|
|
|
|
|
|
done:
|
2012-09-30 22:36:12 +02:00
|
|
|
free_pnode(names);
|
2012-10-01 18:31:02 +02:00
|
|
|
tfree(resname);
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|