00001
00053 #include "apbscfg.h"
00054 #include "apbs/apbs.h"
00055
00056 #define IJK(i,j,k) (((k)*(nx)*(ny))+((j)*(nx))+(i))
00057 #define ERRRC 13
00058 #define DXM_MAXOP 20
00059 #define DXM_ISGRID 0
00060 #define DXM_ISSCALAR 1
00061
00062 VEMBED(rcsid="$Id: dxmath.c 1552 2010-02-10 17:46:27Z yhuang01 $")
00063
00064 typedef enum Dxmath_Opcode {
00065 DXM_ADD,
00066 DXM_SUB,
00067 DXM_DIV,
00068 DXM_MUL,
00069 DXM_EQU
00070 } Dxmath_Opcode;
00071
00072 int main(int argc, char **argv) {
00073
00074
00075 char *input_path;
00076 char *MCwhiteChars = " \t\n";
00077 char *MCcommChars = "#%";
00078 char tok[VMAX_BUFSIZE];
00079 char gridPath[DXM_MAXOP+1][VMAX_BUFSIZE];
00080 double scalar[DXM_MAXOP+1];
00081 int obType[DXM_MAXOP+1];
00082 int iop, numop;
00083 int i, nx, ny, nz;
00084 Dxmath_Opcode op[DXM_MAXOP];
00085 Vio *sock = VNULL;
00086 Vgrid *grid1 = VNULL;
00087 Vgrid *grid2 = VNULL;
00088
00089 char *header = "\n\n\
00090 ----------------------------------------------------------------------\n\
00091 ----------------------------------------------------------------------\n\
00092 \n\n";
00093
00094 char *usage = "\n\n\
00095 ----------------------------------------------------------------------\n\
00096 This driver program (like its UHBD counterpart) does simple arithmetic\n\
00097 with Cartesian grid data. It is invoked as:\n\n\
00098 dx-math <path>\n\n\
00099 where <path> is the path is the path to a file with operations specified\n\
00100 in a stack-based (RPN) manner. For example, a command file which adds\n\
00101 grid1 and grid2, multiplies the result by 5.3, adds grid4, subtracts\n\
00102 99.3 from the whole thing, and writes the result on grid5 would have the\n\
00103 form:\n\n\
00104 grid1\n\
00105 grid2 +\n\
00106 5.3 *\n\
00107 grid4 +\n\
00108 99.3 -\n\
00109 grid5 =\n\n\
00110 where the file names, scalar values, and operations must be separated by\n\
00111 tabs, line breaks, or white space. Comments can be included between the\n\
00112 character # and a new line (in the usual shell script fashion).\n\
00113 ----------------------------------------------------------------------\n\n";
00114
00115
00116
00117 Vio_start();
00118 Vnm_print(1, "%s", header);
00119 if (argc != 2) {
00120 Vnm_print(2,"\n*** Syntax error: got %d arguments, expected 2.\n\n",
00121 argc);
00122 Vnm_print(2,"%s\n", usage);
00123 return ERRRC;
00124 }
00125 input_path = argv[1];
00126
00127
00128 sock = Vio_ctor("FILE", "ASC", VNULL, input_path, "r");
00129 if (sock == VNULL) {
00130 Vnm_print(2, "main: Null socket!\n");
00131 return ERRRC;
00132 }
00133 if (Vio_accept(sock, 0) < 0) {
00134 Vnm_print(2, "main: Problem reading from socket!\n");
00135 return 0;
00136 }
00137 Vio_setWhiteChars(sock, MCwhiteChars);
00138 Vio_setCommChars(sock, MCcommChars);
00139
00140
00141
00142
00143
00144 if (Vio_scanf(sock, "%s", tok) != 1) {
00145 Vnm_print(2, "main: Ran out of tokens when parsing initial input!\n");
00146 return ERRRC;
00147 }
00148 strncpy(gridPath[0], tok, VMAX_BUFSIZE);
00149 obType[0] = DXM_ISGRID;
00150 numop = 0;
00151 while (Vio_scanf(sock, "%s", tok) == 1) {
00152 if (sscanf(tok, "%lg", &scalar[numop+1]) == 1) {
00153 obType[numop+1] = DXM_ISSCALAR;
00154 } else {
00155 strncpy(gridPath[numop+1], tok, VMAX_BUFSIZE);
00156 obType[numop+1] = DXM_ISGRID;
00157 }
00158 if (Vio_scanf(sock, "%s", tok) != 1) {
00159 Vnm_print(2, "main: Ran out of tokens when parsing input!\n");
00160 Vnm_print(2, "main: Last token = %s.\n", tok);
00161 return ERRRC;
00162 }
00163 if (strcmp(tok, "*") == 0) op[numop] = DXM_MUL;
00164 else if (strcmp(tok, "+") == 0) op[numop] = DXM_ADD;
00165 else if (strcmp(tok, "-") == 0) op[numop] = DXM_SUB;
00166 else if (strcmp(tok, "/") == 0) op[numop] = DXM_DIV;
00167 else if (strcmp(tok, "=") == 0) {
00168 op[numop] = DXM_EQU;
00169 numop++;
00170 break;
00171 } else {
00172 Vnm_print(2, "main: Undefined operation '%s'!\n", tok);
00173 return ERRRC;
00174 }
00175 numop++;
00176 if (numop == DXM_MAXOP) {
00177 Vnm_print(2, "main: Exceed maximum number of operations (%d)!\n",
00178 DXM_MAXOP);
00179 return ERRRC;
00180 }
00181 }
00182 Vio_acceptFree(sock);
00183
00184
00185 Vnm_print(1, "main: Performing following operations:\n");
00186 Vnm_print(1, "main: %s \n", gridPath[0]);
00187 for (iop=0; iop<numop; iop++) {
00188 if (obType[iop+1] == DXM_ISGRID)
00189 Vnm_print(1, "main: %s (grid) ", gridPath[iop+1]);
00190 else
00191 Vnm_print(1, "main: %g (scalar) ", scalar[iop+1]);
00192 switch (op[iop]) {
00193 case DXM_MUL:
00194 Vnm_print(1, "*\n");
00195 break;
00196 case DXM_ADD:
00197 Vnm_print(1, "+\n");
00198 break;
00199 case DXM_SUB:
00200 Vnm_print(1, "-\n");
00201 break;
00202 case DXM_DIV:
00203 Vnm_print(1, "/\n");
00204 break;
00205 case DXM_EQU:
00206 Vnm_print(1, "=\n");
00207 break;
00208 default:
00209 Vnm_print(2, "\nmain: Unknown operation (%d)!", op[iop]);
00210 return ERRRC;
00211 }
00212 }
00213
00214
00215 Vnm_print(1, "main: Reading grid from %s...\n", gridPath[0]);
00216 grid1 = Vgrid_ctor(0, 0, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, VNULL);
00217 if (!Vgrid_readDX(grid1, "FILE", "ASC", VNULL, gridPath[0])) {
00218 Vnm_print(2, "main: Problem reading OpenDX-format grid from %s\n",
00219 gridPath[0]);
00220 return ERRRC;
00221 }
00222 nx = grid1->nx;
00223 ny = grid1->ny;
00224 nz = grid1->nz;
00225 for (iop=0; iop<numop-1; iop++) {
00226 if (obType[iop+1] == DXM_ISGRID) {
00227 Vnm_print(1, "main: Reading grid from %s...\n", gridPath[iop+1]);
00228 grid2 = Vgrid_ctor(0, 0, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, VNULL);
00229 if (!Vgrid_readDX(grid2, "FILE", "ASC", VNULL, gridPath[iop+1])) {
00230 Vnm_print(2, "main: Problem reading OpenDX-format grid from \
00231 %s\n", gridPath[0]);
00232 return ERRRC;
00233 }
00234 if ((grid2->nx != nx) || (grid2->ny != ny) || (grid2->nz != nz)) {
00235 Vnm_print(2, "main: Grid dimension mis-match!\n");
00236 Vnm_print(2, "main: Grid 1 is %d x %d x %d\n", nx, ny, nz);
00237 Vnm_print(2, "main: Grid 2 is %d x %d x %d\n",
00238 grid2->nx, grid2->ny, grid2->nz);
00239 return ERRRC;
00240 }
00241 switch (op[iop]) {
00242 case DXM_ADD:
00243 Vnm_print(1, "main: Adding...\n");
00244 for (i=0; i<nx*ny*nz; i++)
00245 grid1->data[i] = grid1->data[i] + grid2->data[i];
00246 break;
00247 case DXM_MUL:
00248 Vnm_print(1, "main: Multiplying...\n");
00249 for (i=0; i<nx*ny*nz; i++)
00250 grid1->data[i] = grid1->data[i] * grid2->data[i];
00251 break;
00252 case DXM_SUB:
00253 Vnm_print(1, "main: Subtracting...\n");
00254 for (i=0; i<nx*ny*nz; i++)
00255 grid1->data[i] = grid1->data[i] - grid2->data[i];
00256 break;
00257 case DXM_DIV:
00258 Vnm_print(1, "main: Dividing...\n");
00259 for (i=0; i<nx*ny*nz; i++)
00260 grid1->data[i] = grid1->data[i] / grid2->data[i];
00261 break;
00262 default:
00263 Vnm_print(2, "main: Unexpected operation (%d)!\n",
00264 op[iop]);
00265 break;
00266 }
00267 Vgrid_dtor(&grid2);
00268 } else {
00269 Vnm_print(1, "main: Loading scalar %g...\n", scalar[iop+1]);
00270 switch (op[iop]) {
00271 case DXM_ADD:
00272 Vnm_print(1, "main: Adding...\n");
00273 for (i=0; i<nx*ny*nz; i++)
00274 grid1->data[i] = grid1->data[i] + scalar[iop+1];
00275 break;
00276 case DXM_MUL:
00277 Vnm_print(1, "main: Multiplying...\n");
00278 for (i=0; i<nx*ny*nz; i++)
00279 grid1->data[i] = grid1->data[i] * scalar[iop+1];
00280 break;
00281 case DXM_SUB:
00282 Vnm_print(1, "main: Subtracting...\n");
00283 for (i=0; i<nx*ny*nz; i++)
00284 grid1->data[i] = grid1->data[i] - scalar[iop+1];
00285 break;
00286 case DXM_DIV:
00287 Vnm_print(1, "main: Dividing...\n");
00288 for (i=0; i<nx*ny*nz; i++)
00289 grid1->data[i] = grid1->data[i] / scalar[iop+1];
00290 break;
00291 default:
00292 Vnm_print(2, "main: Unexpected operation (%d)!\n",
00293 op[iop]);
00294 break;
00295 }
00296 }
00297 }
00298
00299
00300 Vnm_print(1, "main: Writing results to %s...\n", gridPath[numop]);
00301 Vgrid_writeDX(grid1, "FILE", "ASC", VNULL, gridPath[numop],
00302 "DXMATH RESULTS", VNULL);
00303
00304 Vnm_print(1, "main: All done -- exiting.\n");
00305 return 0;
00306 }