Command.cc 8.46 KB
Newer Older
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1
2
3
4
/*
  This file is part of CDO. CDO is a collection of Operators to
  manipulate and analyse Climate model Data.

Uwe Schulzweida's avatar
Uwe Schulzweida committed
5
  Copyright (C) 2003-2017 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
Uwe Schulzweida's avatar
Uwe Schulzweida committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  See COPYING file for copying and redistribution conditions.

  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; version 2 of the License.

  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.
*/

/*
   This module contains the following operators:
*/


Ralf Mueller's avatar
Ralf Mueller committed
23
#include <cdi.h>
Uwe Schulzweida's avatar
Uwe Schulzweida committed
24
25
#include "cdo.h"
#include "cdo_int.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
26
#include "counter.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
27

Uwe Schulzweida's avatar
Uwe Schulzweida committed
28
29
30
31

typedef struct
{
  int   param;
32
33
34
  char  name[CDI_MAX_NAME];
  char  longname[CDI_MAX_NAME];
  char  units[CDI_MAX_NAME];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
35
36
37
38
39
40
41
42
} vars_t;

vars_t *all_vars = NULL;

int gl_streamID = 0;
int gl_vlistID = 0;
int gl_varID = 0;
int gl_nvars = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
43
int levelID = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
44
45
46
int gl_tsID1 = 0;
int gl_tsID2 = 0;
double *gl_data = NULL;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
47
48
49
50
51

#define MAX_LINE 256

int Done = 0;

52
53
54
55
56
57
int com_help(const char *);
int com_list(const char *);
int com_quit(const char *);
int com_stat(const char *);
int com_set(const char *);
int com_vars(const char *);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
58
59
60
61
//int com_stat(char *);


typedef struct {
62
63
64
  const char  *name; /* User printable name of the function. */
  int  (*func)(const char *); /* Function to call to do the job. */
  const char  *doc; /* Documentation for this function. */
Uwe Schulzweida's avatar
Uwe Schulzweida committed
65
66
67
68
69
70
71
72
73
}
command_t;

command_t commands[] = {
  { "help", com_help, "Display this text" },
  { "?",    com_help, "Synonym for 'help'" },
  { "list", com_list, "List files in DIR" },
  { "quit", com_quit, "Quit using CDO" },
  { "stat", com_stat, "Statistic for selected field" },
Uwe Schulzweida's avatar
Uwe Schulzweida committed
74
  { "set",  com_set,  "set variables" },
Uwe Schulzweida's avatar
Uwe Schulzweida committed
75
76
77
78
79
80
81
82
83
84
85
86
87
  { "vars", com_vars, "list variables" },
  //  { "stat", com_stat, "Print out statistics on FILE" },
  { NULL, NULL, NULL }
};


/* Return non-zero if ARG is a valid argument for CALLER, else print
an error message and return zero. */
int valid_argument (char *caller, char *arg)
{
  if (!arg || !*arg)
    {
      fprintf (stderr, "%s: Argument required.\n", caller);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
88
      return 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
89
    }
90
  return 1;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
91
92
93
}

/* Print out help for ARG, or for all of the commands if ARG is not present. */
94
int com_help(const char *arg)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
95
96
97
{
  int printed = 0;

98
  for ( int i = 0; commands[i].name; i++ )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
99
100
101
102
103
104
105
106
107
108
    {
      if (!*arg || (strcmp (arg, commands[i].name) == 0))
	{
	  printf ("%s\t\t%s.\n", commands[i].name, commands[i].doc);
	  printed++;
	}
    }

  if ( !printed )
    {
Ralf Mueller's avatar
Ralf Mueller committed
109
      printf ("No commands match '%s'. Possibilties are:\n", arg);
110
      for ( int i = 0; commands[i].name; i++ )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
111
112
113
114
115
116
117
118
119
120
121
122
123
124
	{
	  /* Print in six columns. */
	  if ( printed == 6 )
	    {
	      printed = 0;
	      printf ("\n");
	    }
	  printf("%s\t", commands[i].name);
	  printed++;
	}

      if (printed) printf ("\n");
    }

Uwe Schulzweida's avatar
Uwe Schulzweida committed
125
  return 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
126
127
128
129
}


/* List the file(s) named in arg. */
130
int com_list(const char *arg)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
131
132
133
134
{
  if (!arg)
    arg = "";

Uwe Schulzweida's avatar
Uwe Schulzweida committed
135
  return 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
136
137
138
}

/* The user wishes to quit using this program. Just set DONE non-zero. */
139
int com_quit(const char *arg)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
140
{
141
142
  UNUSED(arg);

Uwe Schulzweida's avatar
Uwe Schulzweida committed
143
144
  Done = 1;

Uwe Schulzweida's avatar
Uwe Schulzweida committed
145
  return 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
146
147
148
}


149
int com_stat(const char *arg)
150
{ 
151
  UNUSED(arg);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
152

Uwe Schulzweida's avatar
Uwe Schulzweida committed
153
154
  fprintf(stdout, "name=%s\n", all_vars[gl_varID].name);

155
  for ( int tsID = gl_tsID1; tsID <= gl_tsID2; ++tsID )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
156
    {
157
      int nrecs = streamInqTimestep(gl_streamID, tsID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
158
      if ( nrecs == 0 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
159
	{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
160
161
162
163
164
165
	  fprintf(stderr, "Timestep %d out of range!\n", tsID+1);
	  break;
	}
      else
	{
	  int i;
166
	  size_t nmiss;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
167
168
169
170
171
	  int gridsize;
	  double fmin = 1.e50 , fmax = -1.e50, fmean = 0;
	  counter_t counter;
	  
	  counter_start(&counter);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
172
173
	  streamReadVarSlice(gl_streamID, gl_varID, levelID, gl_data, &nmiss);
	  gridsize = gridInqSize(vlistInqVarGrid(gl_vlistID, gl_varID));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
174
175
	  for ( i = 0; i < gridsize; ++i )
	    {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
176
177
178
	      if ( gl_data[i] < fmin ) fmin = gl_data[i];
	      if ( gl_data[i] > fmax ) fmax = gl_data[i];
	      fmean += gl_data[i];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
179
180
181
182
	    }
	  fmean /= gridsize;
	  counter_stop(&counter);
	  
Uwe Schulzweida's avatar
Uwe Schulzweida committed
183
184
	  fprintf(stdout, "timestep=%d %g %g %g (%gs)\n",
		  tsID+1, fmin, fmean, fmax,
Uwe Schulzweida's avatar
Uwe Schulzweida committed
185
		  counter_cputime(counter));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
186
187
	}
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
188

Uwe Schulzweida's avatar
Uwe Schulzweida committed
189
  return 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
190
191
192
}


193
int com_set(const char *arg)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
194
195
196
{
  printf("com_set: %s\n", arg);

Uwe Schulzweida's avatar
Uwe Schulzweida committed
197
  return 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
198
199
200
}


201
int com_vars(const char *arg)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
202
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
203
  char paramstr[32];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
204

Uwe Schulzweida's avatar
Uwe Schulzweida committed
205
206
  if ( !arg ) arg = "";
  printf("com_vars: %s %d\n", arg, gl_nvars);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
207

208
  for ( int varID = 0; varID < gl_nvars; ++varID )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
209
    {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
210
211
      cdiParamToString(all_vars[varID].param, paramstr, sizeof(paramstr));

212
      fprintf(stdout,"varID=%3d, param=%s, name=%s, longname=\"%s\", units=\"%s\"\n",
Uwe Schulzweida's avatar
Uwe Schulzweida committed
213
	      varID+1, paramstr, all_vars[varID].name, all_vars[varID].longname, all_vars[varID].units);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
214
215
    }

Uwe Schulzweida's avatar
Uwe Schulzweida committed
216
  return 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
217
218
219
}

/* Look up NAME as the name of a command, and return a pointer to that
Uwe Schulzweida's avatar
Uwe Schulzweida committed
220
   command. Return a NULL pointer if NAME isn't a command name. */
Uwe Schulzweida's avatar
Uwe Schulzweida committed
221
222
command_t *find_command(char *name)
{
223
  for ( int i = 0; commands[i].name; i++ )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
224
    if ( strcmp(name, commands[i].name) == 0)
225
      return &commands[i];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
226

227
  return (command_t *)NULL;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
228
229
}

230
// Execute a command line.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
231
232
int execute_line(char *line)
{
233
234
  // Isolate the command word.
  int i = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
235
  while ( line[i] && isspace(line[i]) )  i++;
236
  char *word = line + i;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
237
  while ( line[i] && !isspace(line[i]) ) i++;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
238
239
240

  if ( line[i] ) line[i++] = '\0';

241
  command_t *command = find_command(word);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
242
243
244
  if ( !command )
    {
      fprintf (stderr, "%s: No such command!\n", word);
245
      return -1;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
246
    }
247
  // Get argument to command, if any.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
248
249
250
  while ( isspace(line[i]) ) i++;

  word = line + i;
251
  // Call the function.
252
  return (*(command->func)) (word);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
253
254
}

255
// Strip isspace from the start and end of STRING. Return a pointer into STRING.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
256
257
char *stripwhite(char *string)
{
258
  char *s;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
259
260
261
  for (s = string; isspace(*s); s++)
    ;
  if (*s == 0)
262
    return s;
263
  char *t = s + strlen (s) - 1;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
264
265
266
267
268
269
270
  while (t > s && isspace(*t))
    t--;
  *++t = '\0';

  return s;
}

271
272
273
extern "C" {
size_t getPeakRSS( );
}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
274
275
276
277

void readcmd(const char *prompt, char *line, int size)
{
  fputs(prompt, stdout);
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
  if ( cdoVerbose )
    {
      char memstring[32] = { "" };
      size_t memmax = getPeakRSS();
      if (memmax)
        {
          size_t muindex = 0;
          const char *mu[] = { "B", "KB", "MB", "GB", "TB", "PB" };
          const size_t nmu = sizeof(mu)/sizeof(char*);
          while (memmax > 9999 && muindex < nmu-1) { memmax /= 1024; muindex++; }
          snprintf(memstring, sizeof(memstring), "%zu%s", memmax, mu[muindex]);
        }
      fputs(" [", stdout);
      fputs(memstring, stdout);
      fputs("]", stdout);
    }
  fputs("> ", stdout);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
295
296
297
298
299
  fflush(stdout);

  *line = '\0';
  if ( fgets(line, size, stdin) )
    {
300
      char *newline = strchr(line, '\n'); // check for trailing '\n'
Uwe Schulzweida's avatar
Uwe Schulzweida committed
301
      if ( newline )
302
	*newline = '\0'; // overwrite the '\n' with a terminating null
Uwe Schulzweida's avatar
Uwe Schulzweida committed
303
304
305
306
    }
}


Uwe Schulzweida's avatar
Uwe Schulzweida committed
307
308
309
void command_init()
{
  gl_vlistID = streamInqVlist(gl_streamID);
310
  int taxisID = vlistInqTaxis(gl_vlistID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
311

312
313
  UNUSED(taxisID);

314
  int gridsize = vlistGridsizeMax(gl_vlistID);
315
  gl_data = (double*) Malloc(gridsize*sizeof(double));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
316
317

  gl_nvars = vlistNvars(gl_vlistID);
318
  all_vars = (vars_t*) Malloc(gl_nvars*sizeof(vars_t));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
319

320
  for ( int varID = 0; varID < gl_nvars; ++varID )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
321
    {
322
      all_vars[varID].param = vlistInqVarParam(gl_vlistID, varID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
323
324
325
326
327
328
      vlistInqVarName(gl_vlistID, varID, all_vars[varID].name);
      vlistInqVarLongname(gl_vlistID, varID, all_vars[varID].longname);
      vlistInqVarUnits(gl_vlistID, varID, all_vars[varID].units);
    }
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
329
330
331

void *Command(void *argument)
{
332
  // int recID, varID, levelID;
333
  // size_t nmiss;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
334
335
336
337
338
339
340
341
342
  double s_utime, s_stime;
  double e_utime, e_stime;
  double c_cputime = 0, c_usertime = 0, c_systime = 0;
  char line[MAX_LINE];
 
  cdoInitialize(argument);

  processStartTime(&s_utime, &s_stime);

343
  gl_streamID = streamOpenRead(cdoStreamName(0)->args);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
344

Uwe Schulzweida's avatar
Uwe Schulzweida committed
345
346
  command_init();
  
347
  // Loop reading and executing lines until the user quits.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
348
349
  while ( !Done )
    {
350
      readcmd("cdo cmd", line, MAX_LINE);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
351
352
353
354

      /* Remove leading and trailing whitespace from the line.
	 Then, if there is anything left, add it to the history list
	 and execute it. */
355
356
      char *s = stripwhite(line);
      if (*s) execute_line(s);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
357
    }
358
 
Uwe Schulzweida's avatar
Uwe Schulzweida committed
359
  streamClose(gl_streamID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
360

361
362
  if ( gl_data ) Free(gl_data);
  if ( all_vars ) Free(all_vars);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
363
364
365
366
367
368
369
370
371
372
373
374
375
376
  
  cdoProcessTime(&e_utime, &e_stime);

  c_usertime = e_utime - s_utime;
  c_systime  = e_stime - s_stime;
  c_cputime  = c_usertime + c_systime;

  s_utime = e_utime;
  s_stime = e_stime;

  cdoPrint("%.2fs %.2fs %.2fs", c_usertime, c_systime, c_cputime);

  cdoFinish();

Uwe Schulzweida's avatar
Uwe Schulzweida committed
377
  return 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
378
}