1 /*
2 Copyright (c) 1990 Massachusetts Institute of Technology, Cambridge, MA.
3 All rights reserved.
4 
5 This Agreement gives you, the LICENSEE, certain rights and obligations.
6 By using the software, you indicate that you have read, understood, and
7 will comply with the terms.
8 
9 Permission to use, copy and modify for internal, noncommercial purposes
10 is hereby granted.  Any distribution of this program or any part thereof
11 is strictly prohibited without prior written consent of M.I.T.
12 
13 Title to copyright to this software and to any associated documentation
14 shall at all times remain with M.I.T. and LICENSEE agrees to preserve
15 same.  LICENSEE agrees not to make any copies except for LICENSEE'S
16 internal noncommercial use, or to use separately any portion of this
17 software without prior written consent of M.I.T.  LICENSEE agrees to
18 place the appropriate copyright notice on any such copies.
19 
20 Nothing in this Agreement shall be construed as conferring rights to use
21 in advertising, publicity or otherwise any trademark or the name of
22 "Massachusetts Institute of Technology" or "M.I.T."
23 
24 M.I.T. MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED.  By
25 way of example, but not limitation, M.I.T. MAKES NO REPRESENTATIONS OR
26 WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR
27 THAT THE USE OF THE LICENSED SOFTWARE COMPONENTS OR DOCUMENTATION WILL
28 NOT INFRINGE ANY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
29 M.I.T. shall not be held liable for any liability nor for any direct,
30 indirect or consequential damages with respect to any claim by LICENSEE
31 or any third party on account of or arising from this Agreement or use
32 of this software.
33 */
34 
35 #include "mulGlobal.h"
36 #include "zbufGlobal.h"
37 
disExtrasimpcube(pc)38 disExtrasimpcube(pc)
39 cube *pc;
40 {
41   printf("cubes[%d][%d][%d][%d]\n", pc->level, pc->j, pc->k, pc->l);
42 }
43 
disExParsimpcube(pc)44 disExParsimpcube(pc)
45 cube *pc;
46 {
47   cube *pa = pc->parent;
48   printf("cubes[%d][%d][%d][%d], ", pc->level, pc->j, pc->k, pc->l);
49   printf("parent = cubes[%d][%d][%d][%d]\n", pa->level, pa->j, pa->k, pa->l);
50 }
51 
dissimpcube(pc)52 dissimpcube(pc)
53 cube *pc;
54 {
55 int i;
56   printf("cube center: x=%g y=%g z=%g\n", pc->x, pc->y, pc->z);
57   printf("index=%d dindex=%d level=%d loc_exact=%d mul_exact=%d numkids=%d\n",
58 	 pc->index, pc->dindex, pc->level,
59 	 pc->loc_exact, pc->mul_exact, pc->numkids);
60   printf("numnbrs=%d upnumvects=%d directnumvects=%d downnumvects=%d\n",
61 	 pc->numnbrs, pc->upnumvects, pc->directnumvects, pc->downnumvects);
62 }
63 
discube(pc)64 discube(pc)
65 cube *pc;
66 {
67 int i;
68   printf("cube center: x=%g y=%g z=%g\n", pc->x, pc->y, pc->z);
69   printf("index=%d dindex=%d level=%d loc_exact=%d mul_exact=%d numkids=%d\n",
70 	 pc->index, pc->dindex, pc->level,
71 	 pc->loc_exact, pc->mul_exact, pc->numkids);
72   printf("numnbrs=%d upnumvects=%d directnumvects=%d downnumvects=%d\n",
73 	 pc->numnbrs, pc->upnumvects, pc->directnumvects, pc->downnumvects);
74   if(pc->directnumvects > 0) {
75     printf("num of elements in ");
76     for(i=0; i < pc->directnumvects; i++) {
77       printf("v%d = %d ", i, pc->directnumeles[i]);
78     }
79     printf("\nchgs\n");
80     for(i=0; i < pc->directnumeles[0]; i++) {
81       dischg(pc->chgs[i]);
82     }
83   }
84   if(pc->downnumvects > 0) {
85     printf("num of down elements in ");
86     for(i=0; i < pc->downnumvects; i++) {
87       printf("v%d = %d ", i, pc->downnumeles[i]);
88     }
89   }
90 }
91 
disupcube(pc)92 disupcube(pc)
93 cube *pc;
94 {
95 
96 
97 }
98 
disdirectcube(pc)99 disdirectcube(pc)
100 cube *pc;
101 {
102 int i;
103   for(i=0; i < pc->directnumvects; i++) {
104     printf("matrix %d\n", i);
105     dismat(pc->directmats[i], pc->directnumeles[0], pc->directnumeles[i]);
106     if(i==0) {
107       printf("lu factored matrix\n");
108       dismat(pc->directlu, pc->directnumeles[0], pc->directnumeles[i]);
109     }
110   }
111 }
112 
113 
dissys(sys)114 dissys(sys)
115 ssystem *sys;
116 {
117 int i, j, k, l, side;
118   printf("side=%d depth=%d order=%d\n",
119 	 sys->side, sys->depth, sys->order);
120   printf("Cube corner is x=%g y=%g z=%g\n", sys->minx, sys->miny, sys->minz);
121   printf("Cube side length= %g\n", sys->length);
122   printf("Printing all the cubes\n");
123   for(i = 0, side = 1; i <= sys->depth; i++, side *= 2) {
124     for(j=0; j < side; j++) {
125       for(k=0; k < side; k++) {
126 	for(l=0; l < side; l++) {
127 	  fprintf(stdout, "\ncubes[%d][%d][%d][%d]\n", i, j, k, l);
128 	  dissimpcube(&(sys->cubes[i][j][k][l]));
129 /*	  disdirectcube(&(sys->cubes[i][j][k][l])); */
130 	}
131       }
132     }
133   }
134 }
135 
136 
137 
dismat(mat,rows,cols)138 dismat(mat, rows, cols)
139 double **mat;
140 int rows, cols;
141 {
142 int i,j;
143   if(cols != 0) {
144     for(i=0; i < rows; i++) {
145       printf("\n i=%d\n", i);
146       for(j=0; j < cols; j++) {
147         printf("%d %g  ", j, mat[i][j]);
148         if(((j+1) % 5) == 0) printf("\n");
149       }
150     }
151     printf("\n");
152   }
153 }
154 
155 
disvect(v,size)156 disvect(v, size)
157 double *v;
158 int size;
159 {
160 int i;
161   for(i=0; i < size; i++) {
162     printf("i=%d %g ", i, v[i]);
163     if(((i+1) % 5) == 0) printf("\n");
164   }
165   printf("\n");
166 }
167 
dischg(pq)168 dischg(pq)
169 charge *pq;
170 {
171   printf("cond=%d index=%d\n", pq->cond, pq->index);
172 }
173 
disallchg(pq)174 disallchg(pq)
175 charge *pq;
176 {
177 charge *nq;
178   for(nq = pq; nq != NULL; nq = nq->next) disfchg(pq);
179 }
180 
disfchg(pq)181 disfchg(pq)
182 charge *pq;
183 {
184 /*
185   printf("Cond=%d Corners\n", pq->cond);
186   printf("x0=%g y0=%g z0=%g\n", pq->x0, pq->y0, pq->z0);
187   printf("x1=%g y1=%g z1=%g\n", pq->x1, pq->y1, pq->z1);
188   printf("x2=%g y2=%g z2=%g\n", pq->x2, pq->y2, pq->z2);
189   printf("x3=%g y3=%g z3=%g\n", pq->x3, pq->y3, pq->z3);
190   printf("Center\n");
191   printf("x=%g y=%g z=%g\n", pq->x, pq->y, pq->z);
192 */
193 }
194 
195 /*
196   dumps a rows x cols matrix of doubles; assumes indices from zero
197 */
dumpMat(mat,rows,cols)198 void dumpMat(mat, rows, cols)
199 int rows, cols;
200 double **mat;
201 {
202   int i, j;
203   for(i = 0; i < rows; i++) {
204     fprintf(stdout, "    row%d ", i);
205     for(j = 0; j < cols; j++) {
206       if(mat[i][j] < 0.0) fprintf(stdout, "%.5e ", mat[i][j]);
207       else fprintf(stdout, " %.5e ", mat[i][j]);
208     }
209     fprintf(stdout, "\n");
210   }
211 }
212 
213 /*
214   dumps a rows x cols matrix of doubles; assumes indices from zero
215 */
dumpCorners(fp,mat,rows,cols)216 void dumpCorners(fp, mat, rows, cols)
217 int rows, cols;
218 double **mat;
219 FILE *fp;
220 {
221   int i, j;
222   for(i = 0; i < rows; i++) {
223     fprintf(fp, "  corner%d ", i);
224     for(j = 0; j < cols; j++) {
225       if(mat[i][j] < 0.0) fprintf(fp, "%.5e ", mat[i][j]);
226       else fprintf(fp, " %.5e ", mat[i][j]);
227     }
228     fprintf(fp, "\n");
229   }
230 }
231 
232 /*
233   dumps a vector of itegers along side a vector of doubles, index from zero
234 */
dumpVecs(dblvec,intvec,size)235 void dumpVecs(dblvec, intvec, size)
236 double *dblvec;
237 int *intvec, size;
238 {
239   int i;
240 
241   for(i = 0; i < size; i++) {
242     fprintf(stdout, "%d %d %g\n", i, intvec[i], dblvec[i]);
243   }
244 }
245 
246 /*
247   dumps the relative coordinates of an array of charges or evaluation pnts
248 */
dumpChgs(chgs,numchgs,x,y,z)249 void dumpChgs(chgs, numchgs, x, y, z)
250 int numchgs;
251 double x, y, z;
252 charge **chgs;
253 {
254   int i;
255   double rho, cosA, beta;
256   for(i = 0; i < numchgs; i++) {
257     xyz2sphere(chgs[i]->x, chgs[i]->y, chgs[i]->z,
258 	       x, y, z, &rho, &cosA, &beta);
259     fprintf(stdout, "    %d %d ", chgs[i]->index, chgs[i]->cond);
260     if(rho < 0) fprintf(stdout, "(%.5e ", rho);
261     else fprintf(stdout, "( %.5e ", rho);
262     if(cosA < 0) fprintf(stdout, "%.5e ", cosA);
263     else fprintf(stdout, " %.5e ", cosA);
264     if(beta < 0) fprintf(stdout, "%.5e) ", beta);
265     else fprintf(stdout, " %.5e) ", beta);
266     if(x < 0) fprintf(stdout, "(%.5e ", chgs[i]->x);
267     else fprintf(stdout, "( %.5e ", chgs[i]->x);
268     if(y < 0) fprintf(stdout, "%.5e ", chgs[i]->y);
269     else fprintf(stdout, " %.5e ", chgs[i]->y);
270     if(z < 0) fprintf(stdout, "%.5e)\n", chgs[i]->z);
271     else fprintf(stdout, " %.5e)\n", chgs[i]->z);
272   }
273 }
274 
275 /*
276   dumps the relative coordinates of an array of charges or evaluation pnts
277   - also dumps dummy bit
278 */
dumpChgsWDummy(chgs,numchgs,is_dummy,x,y,z)279 void dumpChgsWDummy(chgs, numchgs, is_dummy, x, y, z)
280 int numchgs, *is_dummy;
281 double x, y, z;
282 charge **chgs;
283 {
284   int i;
285   double rho, cosA, beta;
286   for(i = 0; i < numchgs; i++) {
287     xyz2sphere(chgs[i]->x, chgs[i]->y, chgs[i]->z,
288 	       x, y, z, &rho, &cosA, &beta);
289     fprintf(stdout, "    %d %d(%d) %d ", chgs[i]->index, is_dummy[i],
290 	    chgs[i]->dummy, chgs[i]->cond);
291     if(rho < 0) fprintf(stdout, "(%.5e ", rho);
292     else fprintf(stdout, "( %.5e ", rho);
293     if(cosA < 0) fprintf(stdout, "%.5e ", cosA);
294     else fprintf(stdout, " %.5e ", cosA);
295     if(beta < 0) fprintf(stdout, "%.5e) ", beta);
296     else fprintf(stdout, " %.5e) ", beta);
297     if(x < 0) fprintf(stdout, "(%.5e ", chgs[i]->x);
298     else fprintf(stdout, "( %.5e ", chgs[i]->x);
299     if(y < 0) fprintf(stdout, "%.5e ", chgs[i]->y);
300     else fprintf(stdout, " %.5e ", chgs[i]->y);
301     if(z < 0) fprintf(stdout, "%.5e)\n", chgs[i]->z);
302     else fprintf(stdout, " %.5e)\n", chgs[i]->z);
303   }
304 }
305 
306 /*
307   display the matrix built for a given charge to multipole transformation
308 */
dispQ2M(mat,chgs,numchgs,x,y,z,order)309 void dispQ2M(mat, chgs, numchgs, x, y, z, order)
310 int numchgs, order;
311 double **mat, x, y, z;
312 charge **chgs;
313 {
314   fprintf(stdout, "\nQ2M MATRIX: cube at (%.5e %.5e %.5e)\n", x, y, z);
315   dumpMat(mat, multerms(order), numchgs);
316   fprintf(stdout,
317 	  "    CHARGES IN CUBE # cond (rho_i cos(alpha_i) beta_i) (x y z):\n");
318   dumpChgs(chgs, numchgs, x, y, z);
319 }
320 
321 /*
322   display the matrix built for a given multipole to local transformation
323 */
dispM2L(mat,x,y,z,xp,yp,zp,order)324 void dispM2L(mat, x, y, z, xp, yp, zp, order)
325 int order;
326 double **mat, x, y, z, xp, yp, zp;
327 {
328   fprintf(stdout,
329    "\nM2L MATRIX: multi at (%.5e %.5e %.5e) -> local at (%.5e %.5e %.5e)\n",
330 	  x, y, z, xp, yp, zp);
331   dumpMat(mat, multerms(order), multerms(order));
332 }
333 
334 /*
335   display the matrix built for a given charge to local transformation
336 */
dispQ2L(mat,chgs,numchgs,x,y,z,order)337 void dispQ2L(mat, chgs, numchgs, x, y, z, order)
338 int numchgs, order;
339 double **mat, x, y, z;
340 charge **chgs;
341 {
342   fprintf(stdout, "\nQ2L MATRIX: cube at (%.5e %.5e %.5e)\n", x, y, z);
343   dumpMat(mat, multerms(order), numchgs);
344   fprintf(stdout,
345 	  "    CHARGES IN CUBE # cond (rho_i cos(alpha_i) beta_i) (x y z):\n");
346   dumpChgs(chgs, numchgs, x, y, z);
347 }
348 
349 /*
350   display the matrix built for a given charge to potential transformation
351 */
dispQ2P(mat,chgs,numchgs,is_dummy,pchgs,numpchgs)352 void dispQ2P(mat, chgs, numchgs, is_dummy, pchgs, numpchgs)
353 int numchgs, numpchgs, *is_dummy;
354 double **mat;
355 charge **chgs, **pchgs;
356 {
357   fprintf(stdout, "\nQ2P MATRIX:\n");
358   dumpMat(mat, numpchgs, numchgs);
359   fprintf(stdout,
360 	  "    PANELS IN CUBE # dummy(real) cond (rho_i cos(alpha_i) beta_i) (x y z):\n");
361   dumpChgsWDummy(chgs, numchgs, is_dummy, 0.0, 0.0, 0.0);
362   fprintf(stdout,
363 	  "    EVALS IN CUBE # cond (rho_i cos(alpha_i) beta_i) (x y z):\n");
364   dumpChgs(pchgs, numpchgs, 0.0, 0.0, 0.0);
365 }
366 
367 /*
368   display the matrix built for a given charge to potential transformation
369 */
dispQ2PDiag(mat,chgs,numchgs,is_dummy)370 void dispQ2PDiag(mat, chgs, numchgs, is_dummy)
371 int numchgs, *is_dummy;
372 double **mat;
373 charge **chgs;
374 {
375   fprintf(stdout, "\nQ2PDiag MATRIX:\n");
376   dumpMat(mat, numchgs, numchgs);
377   fprintf(stdout,
378 	  "    PANELS IN CUBE # dummy(real) cond (rho_i cos(alpha_i) beta_i) (x y z):\n");
379   dumpChgsWDummy(chgs, numchgs, is_dummy, 0.0, 0.0, 0.0);
380 }
381 
382 /*
383   display the matrix built for a given multipole to multipole transformation
384 */
dispM2M(mat,x,y,z,xp,yp,zp,order)385 void dispM2M(mat, x, y, z, xp, yp, zp, order)
386 int order;
387 double **mat, x, y, z, xp, yp, zp;
388 {
389   fprintf(stdout,
390       "\nM2M MATRIX: cube at (%.5e %.5e %.5e) shifted to (%.5e %.5e %.5e)\n",
391 	  x, y, z, xp, yp, zp);
392   dumpMat(mat, multerms(order), multerms(order));
393 }
394 
395 /*
396   display the matrix built for a given local to local transformation
397 */
dispL2L(mat,x,y,z,xp,yp,zp,order)398 void dispL2L(mat, x, y, z, xp, yp, zp, order)
399 int order;
400 double **mat, x, y, z, xp, yp, zp;
401 {
402   fprintf(stdout,
403       "\nL2L MATRIX: cube at (%.5e %.5e %.5e) shifted to (%.5e %.5e %.5e)\n",
404 	  x, y, z, xp, yp, zp);
405   dumpMat(mat, multerms(order), multerms(order));
406 }
407 
408 /*
409   display the matrix built for a given multipole to potential transformation
410 */
dispM2P(mat,x,y,z,chgs,numchgs,order)411 void dispM2P(mat, x, y, z, chgs, numchgs, order)
412 int numchgs, order;
413 double **mat, x, y, z;
414 charge **chgs;
415 {
416   fprintf(stdout, "\nM2P MATRIX: cube at (%.5e %.5e %.5e)\n", x, y, z);
417   dumpMat(mat, numchgs, multerms(order));
418   fprintf(stdout,
419 	  "    EVAL PNTS IN CUBE # cond (rho_i, cos(alpha_i), beta_i):\n");
420   dumpChgs(chgs, numchgs, x, y, z);
421 }
422 
423 /*
424   display the matrix built for a given local to potential transformation
425 */
dispL2P(mat,x,y,z,chgs,numchgs,order)426 void dispL2P(mat, x, y, z, chgs, numchgs, order)
427 int numchgs, order;
428 double **mat, x, y, z;
429 charge **chgs;
430 {
431   fprintf(stdout, "\nL2P MATRIX: cube at (%.5e %.5e %.5e)\n", x, y, z);
432   dumpMat(mat, numchgs, multerms(order));
433   fprintf(stdout,
434 	  "    EVAL PNTS IN CUBE # cond (rho_i, cos(alpha_i), beta_i):\n");
435   dumpChgs(chgs, numchgs, x, y, z);
436 }
437 
438 /*
439   displays upward pass and moment vectors associated with a cube - debug only
440 */
dumpUpVecs(pc)441 void dumpUpVecs(pc)
442 cube *pc;
443 {
444   int i, j;
445   fprintf(stdout,
446     "\nUPWARD PASS/MOMENT VECTORS, LEVEL %d CUBE AT (%.5e %.5e %.5e):\n",
447 	  pc->level, pc->x, pc->y, pc->z);
448   for(i = 0; i < pc->upnumvects; i++) {
449     fprintf(stdout, "%d", i);
450     for(j = 0; j < pc->upnumeles[i]; j++) {
451       if(pc->upvects[i][j] < 0.0)
452 	  fprintf(stdout, " %.5e", pc->upvects[i][j]);
453       else fprintf(stdout, "  %.5e", pc->upvects[i][j]);
454     }
455     fprintf(stdout, "\n");
456   }
457   fprintf(stdout, "M");
458   for(j = 0; j < pc->multisize; j++) {
459     if(pc->multi[j] < 0.0) fprintf(stdout, " %.5e", pc->multi[j]);
460     else fprintf(stdout, "  %.5e", pc->multi[j]);
461   }
462   fprintf(stdout, "\n");
463 }
464 
465 /*
466   displays the upward pass vectors for the eight level 1 cubes - debug only
467 */
dumpLevOneUpVecs(sys)468 void dumpLevOneUpVecs(sys)
469 ssystem *sys;
470 {
471   int i, j, k;
472   cube *****cubes = sys->cubes;
473   for(i = 0; i < 2; i++) {
474     for(j = 0; j < 2; j++) {
475       for(k = 0; k < 2; k++) {
476 	if(cubes[1][i][j][k] != NULL) dumpUpVecs(cubes[1][i][j][k]);
477       }
478     }
479   }
480 }
481 
482 /*
483   checks a cube (direct, local or eval) list for bad cube structs - debug only
484   -- doesn't quite do this - always uses direct list for one thing
485 */
chkList(sys,listtype)486 void chkList(sys, listtype)
487 ssystem *sys;
488 int listtype;			/* DIRECT, LOCAL or EVAL */
489 {
490   int cnt[BUFSIZ];		/* # of cubes processed by level */
491   int depth = sys->depth;
492   int lev, nn;
493   int i, j, k;
494   cube *nc;
495   for(i = 0; i <= depth; i++) cnt[i] = 0;
496   nc = sys->directlist;
497   while(nc != NULL) {
498     /* check number and level of neighbors */
499     lev = nc->level;
500     nn = nc->numnbrs;
501     for(i = 0; i < nn; i++) {
502       if(lev != ((nc->nbrs)[i])->level) {
503 	fprintf(stderr, "chkList: level %d cube has a level %d nbr\n", lev,
504 		((nc->nbrs)[i])->level);
505 	fprintf(stderr, " ok cubes ");
506 	for(j = 0; j <= depth; j++) fprintf(stderr, "lev%d: %d ", j, cnt[j]);
507 	fprintf(stderr, "\n");
508 	exit(1);
509       }
510     }
511     /* check number of kids */
512     if(lev == depth && nc->numkids != 0) {
513       fprintf(stderr, "chkList: level %d cube has children\n", lev);
514       fprintf(stderr, " ok cubes ");
515       for(j = 0; j <= depth; j++) fprintf(stderr, "lev%d: %d ", j, cnt[j]);
516       fprintf(stderr, "\n");
517       exit(1);
518     }
519     /* if lowest level, check status of eval and direct vects */
520     if(lev == depth) {
521       if(nc->dindex == 0 || nc->directnumeles == NULL) {
522 	fprintf(stderr, "chkList: level %d cube has bad direct info\n", lev);
523 	fprintf(stderr, " ok cubes ");
524 	for(j = 0; j <= depth; j++) fprintf(stderr, "lev%d: %d ", j, cnt[j]);
525 	fprintf(stderr, "\n");
526 	exit(1);
527       }
528       if(nc->evalnumvects == 0 && listtype == EVAL) {
529 	fprintf(stderr, "chkList: level %d cube has no eval info\n", lev);
530 	fprintf(stderr, " ok cubes ");
531 	for(j = 0; j <= depth; j++) fprintf(stderr, "lev%d: %d ", j, cnt[j]);
532 	fprintf(stderr, "\n");
533 	exit(1);
534       }
535     }
536     cnt[lev]++;
537     if(listtype == DIRECT) nc = nc->dnext;
538     else if(listtype == LOCAL) nc = nc->lnext;
539     else if(listtype == EVAL) nc = nc->enext;
540     else {
541       fprintf(stderr, "chkList: bad flag\n");
542       exit(1);
543     }
544   }
545   if(listtype == DIRECT) fprintf(stdout, "\nDirect ");
546   else if(listtype == LOCAL) fprintf(stdout, "\nLocal ");
547   else fprintf(stdout, "\nEval ");
548   fprintf(stdout, "list ok: ");
549   for(j = 0; j <= depth; j++) fprintf(stdout, "lev%d: %d ", j, cnt[j]);
550   fprintf(stdout, "\n\n");
551 }
552 
553 /*
554   chks a cube for bad cube struct (direct, local or eval) entries - debug only
555 */
chkCube(sys,nc,listtype)556 void chkCube(sys, nc, listtype)
557 ssystem *sys;
558 cube *nc;
559 int listtype;			/* DIRECT, LOCAL or EVAL */
560 {
561   int depth = sys->depth;
562   int lev, nn;
563   int i, j, k;
564   if(nc != NULL) {
565     /* check number and level of neighbors */
566     lev = nc->level;
567     nn = nc->numnbrs;
568     for(i = 0; i < nn; i++) {
569       if(lev != ((nc->nbrs)[i])->level) {
570 	fprintf(stdout, "chkCube: level %d cube has a level %d nbr\n", lev,
571 		((nc->nbrs)[i])->level);
572 /*	exit(1);*/
573       }
574     }
575     /* check number of kids */
576     if(lev == depth && nc->numkids != 0) {
577       fprintf(stdout, "chkCube: level %d cube has children\n", lev);
578 /*      exit(1);*/
579     }
580     /* if lowest level, check status of eval and direct vects */
581     if(lev == depth) {
582       if(nc->dindex == 0) {
583 	fprintf(stdout, "chkCube: level %d cube has zero direct index\n", lev);
584 /*	exit(1);*/
585       }
586       if(nc->directnumeles == NULL) {
587 	fprintf(stdout,
588 		"chkCube: level %d cube has NULL directnumeles\n", lev);
589 /*	exit(1);*/
590       }
591       if(nc->evalnumvects == 0 && listtype == EVAL) {
592 	fprintf(stdout, "chkCube: level %d cube has no eval info\n", lev);
593 /*	exit(1);*/
594       }
595       if(nc->eval == NULL && listtype == EVAL) {
596 	fprintf(stdout, "chkCube: level %d cube has no eval pntr\n", lev);
597       }
598     }
599   }
600 }
601 
602 /*
603   checks the lowest level cubes for trouble using chkCube - debug only
604 */
chkLowLev(sys,listtype)605 void chkLowLev(sys, listtype)
606 ssystem *sys;
607 int listtype;			/* DIRECT, LOCAL or EVAL */
608 {
609   int i, j, k, l, side, depth = sys->depth, cnt = 0;
610   cube *nc, *****cubes = sys->cubes;
611   for(i = 1, side = 1; i <= depth; i++, side *= 2);
612   for(j=0; j < side; j++) {	/* loop through all cubes at level depth */
613     for(k=0; k < side; k++) {
614       for(l=0; l < side; l++) {
615 	nc = cubes[depth][j][k][l];
616 	if(nc != NULL) {
617 	  chkCube(sys, nc, listtype);
618 	  cnt++;
619 	}
620       }
621     }
622   }
623   fprintf(stdout,"Total lowest level (level %d) cubes checked = %d\n",
624 	  depth, cnt);
625 }
626 
627 /*
628   dump the contents of a face struct
629 */
dump_face(fp,fac)630 void dump_face(fp, fac)
631 face *fac;
632 FILE *fp;
633 {
634   int i, j;
635   face **behind = fac->behind;
636 
637   fprintf(fp, "Face %d, %d sides, depth %d, mark %d, greylev %d\n",
638 	  fac->index, fac->numsides, fac->depth, fac->mark, fac->greylev);
639   fprintf(fp, "  plane: n = (%g %g %g) rhs = %g\n",
640 	  fac->normal[0], fac->normal[1], fac->normal[2], fac->rhs);
641   fprintf(fp, "  behind [depth(index)]:");
642   for(i = 0; i < fac->numbehind; i++) {
643     fprintf(fp, " %d(%d)", behind[i]->depth, behind[i]->index);
644     if(i % 10 == 0 && i != 0) fprintf(fp, "\n");
645   }
646   i--;
647   if(!(i % 10 && i != 0)) fprintf(fp, "\n");
648   fprintf(fp, " Corners\n");
649   dumpCorners(fp, fac->c, fac->numsides, 3);
650 }
651 
652 /*
653   core display routine used below
654 */
dumpSynCore1(str,depth,fcnt,excnt,emcnt,tcnt)655 void dumpSynCore1(str, depth, fcnt, excnt, emcnt, tcnt)
656 int depth, *fcnt, *excnt, *emcnt, *tcnt;
657 char *str;
658 {
659   int i;
660   fprintf(stdout, "%-13s", str);
661   for(i = 0; i <= depth; i++) {
662     sprintf(str, "%d/%d/%d/%d ", fcnt[i], excnt[i], emcnt[i], tcnt[i]);
663     if(i < 2) fprintf(stdout, "%8s", str);
664     else if(i == 2) fprintf(stdout, "%12s", str);
665     else if(i == 3) fprintf(stdout, "%16s", str);
666     else if(i == 4) fprintf(stdout, "%20s", str);
667     else if(i == 5) fprintf(stdout, "%24s", str);
668     else fprintf(stdout, "%28s", str);
669   }
670   fprintf(stdout, "\n");
671 }
672 /*
673   core display rtn used below
674 */
dumpSynCore2(str,depth,cnt)675 dumpSynCore2(str, depth, cnt)
676 int depth, *cnt;
677 char *str;
678 {
679   int i;
680 
681   fprintf(stdout, "%-13s", str);
682   for(i = 0; i <= depth; i++) {
683     sprintf(str, "%d    ", cnt[i]);
684     if(i < 2) fprintf(stdout, "%8s", str);
685     else if(i == 2) fprintf(stdout, "%12s", str);
686     else if(i == 3) fprintf(stdout, "%16s", str);
687     else if(i == 4) fprintf(stdout, "%20s", str);
688     else if(i == 5) fprintf(stdout, "%24s", str);
689     else fprintf(stdout, "%28s", str);
690   }
691   fprintf(stdout, "\n");
692 }
693 
694 /*
695   displays number of exact, full, empty and total cubes per level in
696   all cubes, and eval, direct, multi and local lists
697 */
dumpSynop(sys)698 void dumpSynop(sys)
699 ssystem *sys;
700 {
701   int i, j, k, l, side, depth = sys->depth, lev;
702   int excnt[BUFSIZ], fcnt[BUFSIZ], emcnt[BUFSIZ], tcnt[BUFSIZ];
703   extern int *multicnt, *localcnt;
704   char str[BUFSIZ];
705   cube *****cubes = sys->cubes, *nc;
706 
707   for(i = 0; i <= depth; i++) excnt[i] = fcnt[i] = emcnt[i] = tcnt[i] = 0;
708 
709   fprintf(stdout,
710 	  "\nCUBE AND EXPANSION SYNOPSIS (full/mul_exact/empty/ttl):\n");
711   fprintf(stdout, "             ");
712   for(i = 0; i <= depth; i++) {
713     sprintf(str, "level%d ", i);
714     if(i < 2) fprintf(stdout, "%8s", str);
715     else if(i == 2) fprintf(stdout, "%12s", str);
716     else if(i == 3) fprintf(stdout, "%16s", str);
717     else if(i == 4) fprintf(stdout, "%20s", str);
718     else if(i == 5) fprintf(stdout, "%24s", str);
719     else fprintf(stdout, "%28s", str);
720   }
721   fprintf(stdout, "\n");
722   /* dump cube usage by level */
723   for(i = 0, side = 1; i <= depth; i++, side *= 2) {
724     for(j=0; j < side; j++) {	/* loop through all cubes at levels >= 0 */
725       for(k=0; k < side; k++) {
726 	for(l=0; l < side; l++) {
727 	  nc = cubes[i][j][k][l];
728 	  tcnt[i]++;
729 	  if(nc != NULL) {
730 	    lev = nc->level;
731 	    fcnt[i]++;
732 	    if(nc->mul_exact == TRUE) excnt[i]++;
733 	  }
734 	  else emcnt[i]++;
735 	}
736       }
737     }
738   }
739   sprintf(str, "All cubes");
740   dumpSynCore1(str, depth, fcnt, excnt, emcnt, tcnt);
741 
742   for(i = 0; i <= depth; i++) excnt[i] = fcnt[i] = emcnt[i] = tcnt[i] = 0;
743   /* dump cube direct list by level */
744   for(nc = sys->directlist; nc != NULL; nc = nc->dnext) {
745     lev = nc->level;
746     tcnt[lev]++;
747     if(nc->upnumvects > 0) fcnt[lev]++;
748     else emcnt[lev]++;
749     if(nc->mul_exact == TRUE) excnt[lev]++;
750   }
751   sprintf(str, "Direct list");
752   dumpSynCore1(str, depth, fcnt, excnt, emcnt, tcnt);
753 
754   for(i = 0; i <= depth; i++) excnt[i] = fcnt[i] = emcnt[i] = tcnt[i] = 0;
755   /* dump cube local list by level */
756   for(i = 0; i <= depth; i++) {
757     for(nc = sys->locallist[i]; nc != NULL; nc = nc->lnext) {
758       lev = nc->level;
759       tcnt[lev]++;
760       if(nc->upnumvects > 0) fcnt[lev]++;
761       else emcnt[lev]++;
762       if(nc->mul_exact == TRUE) excnt[lev]++;
763     }
764   }
765   sprintf(str, "Local list");
766   dumpSynCore1(str, depth, fcnt, excnt, emcnt, tcnt);
767 
768   for(i = 0; i <= depth; i++) excnt[i] = fcnt[i] = emcnt[i] = tcnt[i] = 0;
769   /* dump cube multipole list by level */
770   for(i = 0; i <= depth; i++) {
771     for(nc = sys->multilist[i]; nc != NULL; nc = nc->mnext) {
772       lev = nc->level;
773       tcnt[lev]++;
774       if(nc->upnumvects > 0) fcnt[lev]++;
775       else emcnt[lev]++;
776       if(nc->mul_exact == TRUE) excnt[lev]++;
777     }
778   }
779   sprintf(str, "Multi list");
780   dumpSynCore1(str, depth, fcnt, excnt, emcnt, tcnt);
781 
782 
783   sprintf(str, "Multis built");
784   dumpSynCore2(str, depth, multicnt);
785 
786   sprintf(str, "Locals built");
787   dumpSynCore2(str, depth, localcnt);
788 
789 }
790 
791 /*
792   dumps the Gaussian unit (statcoulombs/meter^2) charge densities on panels
793 */
dumpChgDen(fp,q,chglist)794 void dumpChgDen(fp, q, chglist)
795 double *q;
796 charge *chglist;
797 FILE *fp;
798 {
799   charge *panel;
800 
801   for(panel = chglist; panel != NULL; panel = panel->next) {
802     if(panel->dummy) continue;
803     fprintf(fp, "%d\tq/A = %.5e %g", panel->index,
804 	    q[panel->index]/panel->area, panel->area);
805     if(panel->surf->type == CONDTR) fprintf(fp, " CONDTR");
806     if(panel->surf->type == DIELEC) fprintf(fp, " DIELEC");
807     if(panel->surf->type == BOTH) fprintf(fp, " BOTH");
808     fprintf(fp, " (%.3g %.3g %.3g)", panel->x, panel->y, panel->z);
809     fprintf(fp, " cond = %d\n", panel->cond);
810   }
811   fflush(fp);
812 }
813 
814 /*
815   like dumpMat but different formating and row labels (for dumpMatBldCnts)
816 */
dumpMatCnts(mat,depth,type)817 void dumpMatCnts(mat, depth, type)
818 int **mat, depth;
819 char *type;
820 {
821   int i, j;
822   char str[BUFSIZ];
823 
824   fprintf(stdout,
825 	  "\n%s MATRIX BUILD TOTALS (row = from cube, col = to cube):\n",
826 	  type);
827 
828   for(i = 0; i <= depth; i++) {
829     sprintf(str, " to %d ", i);
830     if(i == 0) fprintf(stdout, "%13s", str);
831     else if(i < 10) fprintf(stdout, "%6s", str);
832     else fprintf(stdout, "%7s", str);
833   }
834   fprintf(stdout, "\n");
835 
836   for(i = 0; i <= depth; i++) {
837     sprintf(str, "from %d ", i);
838     fprintf(stdout, "%-7s", str); /* print row label */
839     for(j = 0; j <= depth; j++) {
840       sprintf(str, "%d ", mat[i][j]);
841       if(j < 10) fprintf(stdout, "%6s", str);
842       else fprintf(stdout, "%7s", str);
843     }
844     fprintf(stdout, "\n");
845   }
846 
847 }
848 
849 /*
850   display matrix build count totals
851 */
dumpMatBldCnts(sys)852 void dumpMatBldCnts(sys)
853 ssystem *sys;
854 {
855   int i;
856   char type[BUFSIZ];
857   extern int **Q2Mcnt, **Q2Lcnt, **Q2Pcnt, **L2Lcnt;
858   extern int **M2Mcnt, **M2Lcnt, **M2Pcnt, **L2Pcnt, **Q2PDcnt;
859 
860   sprintf(type, "Q2M");
861   dumpMatCnts(Q2Mcnt, sys->depth, type);
862 
863   sprintf(type, "Q2L");
864   dumpMatCnts(Q2Lcnt, sys->depth, type);
865 
866   sprintf(type, "Q2P");
867   dumpMatCnts(Q2Pcnt, sys->depth, type);
868 
869   sprintf(type, "M2M");
870   dumpMatCnts(M2Mcnt, sys->depth, type);
871 
872   sprintf(type, "M2L");
873   dumpMatCnts(M2Lcnt, sys->depth, type);
874 
875   sprintf(type, "M2P");
876   dumpMatCnts(M2Pcnt, sys->depth, type);
877 
878   sprintf(type, "L2L");
879   dumpMatCnts(L2Lcnt, sys->depth, type);
880 
881   sprintf(type, "L2P");
882   dumpMatCnts(L2Pcnt, sys->depth, type);
883 
884   sprintf(type, "Q2PDiag");
885   dumpMatCnts(Q2PDcnt, sys->depth, type);
886 
887 }
888 
889 /*
890   dumps state of important compile flags
891 */
dumpConfig(fp,name)892 void dumpConfig(fp, name)
893 char *name;
894 FILE *fp;
895 {
896   int size = -1;		/* for '#define MAXITER size' case */
897 
898   fprintf(fp, "\n%s CONFIGURATION FLAGS:\n", name);
899 
900   fprintf(fp, " DISCRETIZATION CONFIGURATION\n");
901 
902   fprintf(fp, "   WRMETH");
903   if(WRMETH == COLLOC)
904       fprintf(fp, " == COLLOC (point collocation)\n");
905   else if(WRMETH == SUBDOM)
906       fprintf(fp, " == SUBDOM (not implemented - do collocation)\n");
907   else if(WRMETH == GALKIN)
908       fprintf(fp, " == GALKIN (not implemented - do collocation)\n");
909   fprintf(fp, "   ELTYPE");
910   if(ELTYPE == CONST)
911       fprintf(fp, " == CONST (constant panel densities)\n");
912   else if(ELTYPE == AFFINE)
913       fprintf(fp, " == AFFINE (not implemented - use constant)\n");
914   else if(ELTYPE == QUADRA)
915       fprintf(fp, " == QUADRA (not implemented - use constant)\n");
916 
917   fprintf(fp, " MULTIPOLE CONFIGURATION\n");
918 
919   fprintf(fp, "   DNTYPE");
920   if(DNTYPE == NOLOCL)
921       fprintf(fp, " == NOLOCL (no locals in dwnwd pass)\n");
922   else if(DNTYPE == NOSHFT)
923       fprintf(fp, " == NOSHFT (no local2local shift dwnwd pass)\n");
924   else if(DNTYPE == GRENGD)
925       fprintf(fp, " == GRENGD (full Greengard dwnwd pass)\n");
926   fprintf(fp, "   MULTI");
927   if(MULTI == ON) fprintf(fp, " == ON (include multipole part of P*q)\n");
928   else fprintf(fp, " == OFF (don't use multipole part of P*q)\n");
929   fprintf(fp, "   RADINTER");
930   if(RADINTER == ON)
931       fprintf(fp," == ON (allow parent level interaction list entries)\n");
932   else
933    fprintf(fp," == OFF (use only cube level interaction list entries)\n");
934   fprintf(fp, "   NNBRS == %d (max distance to a nrst neighbor)\n", NNBRS);
935   fprintf(fp, "   ADAPT");
936   if(ADAPT == ON)
937       fprintf(fp, " == ON (adaptive - no expansions in exact cubes)\n");
938   else fprintf(fp, " == OFF (not adaptive - expansions in all cubes)\n");
939   fprintf(fp, "   OPCNT");
940   if(OPCNT == ON)
941       fprintf(fp, " == ON (count P*q ops - exit after mat build)\n");
942   else fprintf(fp, " == OFF (no P*q op count - iterate to convergence)\n");
943 
944   fprintf(fp, "   MAXDEP");
945   fprintf(fp,
946 	  " == %d (assume no more than %d partitioning levels are needed)\n",
947 	  MAXDEP, MAXDEP);
948 
949   fprintf(fp, "   NUMDPT");
950   fprintf(fp,
951 	  " == %d (do %d potential evaluations for each dielectric panel)\n",
952 	  NUMDPT, NUMDPT);
953 
954   fprintf(fp, " LINEAR SYSTEM SOLUTION CONFIGURATION\n");
955 
956   fprintf(fp, "   ITRTYP");
957   if(ITRTYP == GCR)
958       fprintf(fp, " == GCR (generalized conjugate residuals)\n");
959   else if(ITRTYP == GMRES)
960       fprintf(fp, " == GMRES (generalized minimum residuals)\n");
961   else fprintf(fp, " == %d (not implemented - use GCR)\n", ITRTYP);
962 
963   fprintf(fp, "   PRECOND");
964   if(PRECOND == BD) {
965     fprintf(fp,
966 	    " == BD (use block diagonal preconditioner)\n");
967   }
968   else if(PRECOND == OL) {
969     fprintf(fp,
970 	    " == OL (use overlap preconditioner)\n");
971   }
972   else if(PRECOND == NONE) {
973     fprintf(fp,
974 	    " == NONE (no preconditioner)\n");
975   }
976   else fprintf(fp, " == %d (not implemented - use BD, OL or NONE)\n", PRECOND);
977 
978   fprintf(fp, "   DIRSOL");
979   if(DIRSOL == ON)
980       fprintf(fp, " == ON (do the whole calculation directly)\n");
981   else fprintf(fp, " == OFF (do the calculation iteratively)\n");
982 
983   fprintf(fp, "   EXPGCR");
984   if(EXPGCR == ON)
985       fprintf(fp, " == ON (do all P*q's explicitly w/full matrix)\n");
986   else fprintf(fp, " == OFF (do P*q's with multipole)\n");
987 
988   fprintf(fp, "   MAXITER");
989   if(MAXITER < 0) {
990     fprintf(fp, " == size (for n panel system, do at most n iterations)\n");
991   }
992   else fprintf(fp, " == %d (stop after %d iterations if not converged)\n",
993 	  MAXITER, MAXITER);
994 
995   fprintf(fp, "   EXRTSH");
996   fprintf(fp,
997 	  " == %g (exact/ttl cubes > %g on lowest level => stop refinement)\n",
998 	  EXRTSH, EXRTSH);
999 }
1000 
1001 
1002 /*
1003   pads a string on the right up to a given length, truncates if too long
1004 */
padName(tostr,frstr,len)1005 char *padName(tostr, frstr, len)
1006 char *tostr, *frstr;
1007 int len;
1008 {
1009   int i;
1010 
1011   for(i = 0; frstr[i] != '\0'; i++) tostr[i] = frstr[i];
1012   if(i > len) tostr[len] = '\0';		/* truncate */
1013   else {			/* pad */
1014     for(; i < len; i++) tostr[i] = ' ';
1015     tostr[len] = '\0';
1016   }
1017   return(tostr);
1018 }
1019 
1020 /*
1021   returns a string of spaces (doesn't stdio have this somewhere?)
1022 */
spaces(str,num)1023 char *spaces(str, num)
1024 char *str;
1025 int num;
1026 {
1027   int i;
1028 
1029   for(i = 0; i < num; i++) str[i] = ' ';
1030   str[num] = '\0';
1031   return(str);
1032 }
1033 
1034 /*
1035   prints the capacitance matrix with symmetrized (averaged) off-diagonals
1036   - mks units (Farads) are used
1037   - some attempt to scale (eg pF, nF, uF etc) is made
1038   - also checks for M-matrix sign pattern, diag dominance
1039 */
mksCapDump(capmat,numconds,relperm,name_list)1040 void mksCapDump(capmat, numconds, relperm, name_list)
1041 double **capmat, relperm;
1042 int numconds;
1043 Name **name_list;
1044 {
1045   int i, j, toobig, toosmall, maxlen, sigfig, colwidth, i_killed, j_killed;
1046   int first_offd;
1047   double maxdiag = 0.0, minoffd, rowttl, rowdiag, scale = 1.0, **sym_mat;
1048   double mat_entry;
1049   char unit[BUFSIZ], name[BUFSIZ], *padName(), *spaces(), cond_name[BUFSIZ];
1050   char *getConductorName();
1051   extern NAME *start_name;	/* NAME structs giving conductor names */
1052   Name *cname;
1053   extern ITER *kill_num_list, *kinp_num_list;
1054   extern double iter_tol;
1055 
1056   first_offd = TRUE;
1057   minoffd = capmat[1][1];	/* this entry is always present */
1058 				/* - in the 1 cond case, assign is still ok */
1059 
1060   /* set up symetrized matrix storage */
1061   CALLOC(sym_mat, numconds+1, double*, ON, AMSC);
1062   for(i=1; i <= numconds; i++)  {
1063     CALLOC(sym_mat[i], numconds+1, double, ON, AMSC);
1064   }
1065 
1066   /* get the smallest and largest (absolute value) symmetrized elements */
1067   /* check for non-M-matrix symmetrized capacitance matrix */
1068   for(i = 1; i <= numconds; i++) {
1069 
1070     /* skip conductors removed from input */
1071     if(want_this_iter(kinp_num_list, i)) continue;
1072 
1073     i_killed = want_this_iter(kill_num_list, i);
1074 
1075     if(capmat[i][i] <= 0.0 && !i_killed) {
1076       fprintf(stderr, "\nmksCapDump: Warning - capacitance matrix has non-positive diagonal\n  row %d\n", i+1);
1077     }
1078     maxdiag = MAX(maxdiag, fabs(capmat[i][i]));
1079     rowttl = 0.0;
1080     for(j = 1; j <= numconds; j++) {
1081 
1082       /* skip conductors removed from input */
1083       if(want_this_iter(kinp_num_list, j)) continue;
1084 
1085       if(j == i) {
1086 	sym_mat[i][i] = capmat[i][i];
1087 	continue;
1088       }
1089 
1090       /* if this column was not calculated and neither was the column
1091          with the same number as the current row, then symetrized mat has
1092 	 no entry at [i][j], [j][i] */
1093       j_killed = want_this_iter(kill_num_list, j);
1094       if(i_killed && j_killed) continue;
1095 
1096       /* if this column was calculated but column with the same number
1097          as the current row wasnt, then symmetrized mat has unaveraged entry
1098 	 at [i][j], [j][i] */
1099       else if(i_killed && !j_killed) mat_entry = capmat[i][j];
1100 
1101       /* if this column was not calculated but column with the same number
1102          as the current row was, then symmetrized mat has unaveraged entry
1103 	 at [i][j], [j][i] */
1104       else if(!i_killed && j_killed) mat_entry = capmat[j][i];
1105 
1106       /* if this column was calculated and column with the same number
1107          as the current row was also, then symmetrized mat has averaged entry
1108 	 at [i][j], [j][i] */
1109       else mat_entry = (capmat[i][j] + capmat[j][i])/2.0;
1110 
1111       rowttl += mat_entry;
1112       if(mat_entry >= 0.0) {
1113 	fprintf(stderr, "\nmksCapDump: Warning - capacitance matrix has non-negative off-diagonals\n  row %d col %d\n", i, j);
1114       }
1115       if(fabs(mat_entry) != 0.0) {
1116 	if(first_offd) {
1117 	  minoffd = fabs(mat_entry);
1118 	  first_offd = FALSE;
1119 	}
1120 	else minoffd = MIN(minoffd, fabs(mat_entry));
1121       }
1122 
1123       sym_mat[i][j] = mat_entry;
1124     }
1125     if(rowttl + capmat[i][i] <= 0.0 && !i_killed) {
1126       fprintf(stderr, "\nmksCapDump: Warning - capacitance matrix is not strictly diagonally dominant\n  due to row %d\n", i);
1127     }
1128   }
1129 
1130   /* figure the units to use for the matrix entries
1131      - set up so smallest element is between 0.1 and 10 */
1132   if(minoffd*FPIEPS*relperm*scale > 10.0) toobig = TRUE;
1133   else toobig = FALSE;
1134   if(minoffd*FPIEPS*relperm*scale < 0.1) toosmall = TRUE;
1135   else toosmall = FALSE;
1136   while(toobig == TRUE || toosmall == TRUE) {
1137     if(toobig == TRUE) {
1138       scale *= 1e-3;
1139       if(minoffd*FPIEPS*relperm*scale <= 10.0) break;
1140     }
1141     if(toosmall == TRUE) {
1142       scale *= 1e+3;
1143       if(minoffd*FPIEPS*relperm*scale >= 0.1) break;
1144     }
1145   }
1146 
1147   /* get the appropriate unit string */
1148   if(scale == 1e-18) strcpy(unit, "exa");
1149   else if(scale == 1e-15) strcpy(unit, "peta");
1150   else if(scale == 1e-12) strcpy(unit, "tera");
1151   else if(scale == 1e-9) strcpy(unit, "giga");
1152   else if(scale == 1e-6) strcpy(unit, "mega");
1153   else if(scale == 1e-3) strcpy(unit, "kilo");
1154   else if(scale == 1.0) strcpy(unit, "");
1155   else if(scale == 1e+3) strcpy(unit, "milli");
1156   else if(scale == 1e+6) strcpy(unit, "micro");
1157   else if(scale == 1e+9) strcpy(unit, "nano");
1158   else if(scale == 1e+12) strcpy(unit, "pico");
1159   else if(scale == 1e+15) strcpy(unit, "femto");
1160   else if(scale == 1e+18) strcpy(unit, "atto");
1161   else sprintf(unit, "every unit is %g ", 1/scale);
1162 
1163   /* get the length of the longest name */
1164   maxlen = 0;
1165   for(i = 1; i <= numconds; i++) {
1166     maxlen = MAX(strlen(getConductorName(i, name_list)), maxlen);
1167   }
1168 
1169   /* print the matrix */
1170   sigfig = 2+log10(1.0/iter_tol);	/* get no. significant figs to prnt */
1171   colwidth = sigfig+6;		/* field width for cap mat columns */
1172   if(ITRDAT == OFF) fprintf(stdout, "\n");
1173   if(kill_num_list != NULL)
1174       fprintf(stdout, "\nPARTIAL CAPACITANCE MATRIX, %sfarads\n", unit);
1175   else fprintf(stdout, "\nCAPACITANCE MATRIX, %sfarads\n", unit);
1176   if(numconds < 10) fprintf(stdout, "%s", spaces(unit, maxlen+2));
1177   else if(numconds < 100) fprintf(stdout, "%s", spaces(unit, maxlen+3));
1178   else fprintf(stdout, "%s", spaces(unit, maxlen+4));
1179   for(j = 1; j <= numconds; j++) { /* column headings */
1180     if(want_this_iter(kinp_num_list, j)) continue;
1181     sprintf(name, "%d ", j);
1182     sprintf(unit, "%%%ds", colwidth+1);
1183     fprintf(stdout, unit, name);
1184   }
1185   fprintf(stdout, "\n");
1186   for(i = 1; i <= numconds; i++) { /* rows */
1187 
1188     /* skip conductors removed from input */
1189     if(want_this_iter(kinp_num_list, i)) continue;
1190 
1191     sprintf(unit, "%d", i);
1192 
1193     strcpy(cond_name, getConductorName(i, name_list));
1194 
1195     if(numconds < 10)
1196 	fprintf(stdout, "%s %1s", padName(name, cond_name, maxlen), unit);
1197     else if(numconds < 100)
1198 	fprintf(stdout, "%s %2s", padName(name, cond_name, maxlen), unit);
1199     else
1200 	fprintf(stdout, "%s %3s", padName(name, cond_name, maxlen), unit);
1201 
1202     for(j = 1; j <= numconds; j++) {
1203 
1204       /* skip conductors removed from input */
1205       if(want_this_iter(kinp_num_list, j)) continue;
1206 
1207       if(want_this_iter(kill_num_list, i)
1208 	 && want_this_iter(kill_num_list, j)) {
1209 	/* print a blank if capacitance was not calculated */
1210 	fprintf(stdout, "%s", spaces(unit, colwidth+1));
1211       }
1212       else {
1213 	sprintf(unit, " %%%d.%dg", colwidth, sigfig);
1214 	fprintf(stdout, unit, scale*FPIEPS*relperm*sym_mat[j][i]);
1215       }
1216     }
1217     fprintf(stdout, "\n");
1218   }
1219 }
1220 
1221 /*
1222   dumps brief information about multipole set up
1223 */
dumpMulSet(sy,numLev,order)1224 void dumpMulSet(sy, numLev, order)
1225 ssystem *sy;
1226 int numLev, order;
1227 {
1228   int numcubes, numsides, i, multerms();
1229 
1230   for(numcubes = 1, i = 0; i < numLev; numcubes *= 8, i++);
1231   for(numsides = 1, i = 0; i < numLev; numsides *= 2, i++);
1232 
1233   fprintf(stdout, "\nMULTIPOLE SETUP SUMMARY\n");
1234   fprintf(stdout, "Level 0 cube extremal coordinates\n");
1235   fprintf(stdout, "  x: %g to %g\n",
1236 	  sy->minx, sy->minx + numsides * (sy->length));
1237   fprintf(stdout, "  y: %g to %g\n",
1238 	  sy->miny, sy->miny + numsides * (sy->length));
1239   fprintf(stdout, "  z: %g to %g\n",
1240 	  sy->minz, sy->minz + numsides * (sy->length));
1241   fprintf(stdout, "Level %d (lowest level) cubes\n  %d total\n",
1242 	  numLev, numcubes);
1243   fprintf(stdout,
1244 	  "  side length = %g\n  maximum number of panels in each = %d\n",
1245 	  sy->length, sy->mul_maxlq);
1246   fprintf(stdout, "  maximum number of evaluation points in each = %d\n",
1247 	  sy->loc_maxlq);
1248   fprintf(stdout,
1249 	  "Maximum number of panels treated with a multipole expansion = %d\n",
1250 	  sy->max_panel);
1251   fprintf(stdout,
1252   "Maximum number of evaluation points treated with a local expansion = %d\n",
1253 	  sy->max_eval_pnt);
1254   fprintf(stdout,
1255 	  "Maximum number of panels treated exactly = %d (limit = %d)\n",
1256 	  sy->mul_maxq, multerms(order));
1257   fprintf(stdout,
1258    "Maximum number of evaluation points treated exactly = %d (limit = %d)\n",
1259 	  sy->loc_maxq, multerms(order));
1260 }
1261 
1262 /*
1263   dump all the preconditioner matrices in the direct list cubes as one
1264   big matrix for matlab read in "Ctil"
1265   - figures preconditioner by multiplying it by columns of the inverse
1266     and dumping results one column at a time
1267   - figures the unpreconditioned matrix (using calcp) and dumps it to "P"
1268   - type determines which of the matrices to dump
1269 */
dump_preconditioner(sys,chglist,type)1270 void dump_preconditioner(sys, chglist, type)
1271 charge *chglist;
1272 ssystem *sys;
1273 int type;			/* 1=>dump P and C; 2=>P only; 3=>C only */
1274 {
1275   int num_panels, i, j;
1276   charge *pp, *pi;
1277   cube *cp;
1278   double calcp();
1279   FILE *fp;
1280 
1281   /* find the number of panels */
1282   for(num_panels = 0, pp = chglist; pp != NULL; pp = pp->next, num_panels++);
1283 
1284   /* open the output file */
1285   if((fp = fopen("prec.mat","w")) == NULL) {
1286     fprintf(stderr, "dump_preconditioner: can't open `prec.mat'\n");
1287     exit(1);
1288   }
1289 
1290   if(type == 1 || type == 3) {
1291     fprintf(stdout, "\nDumping preconditioner to `prec.mat' as `Ctil'\n");
1292     /* dump the preconditioner one column at a time */
1293     /* - savemat arg "type" can be used to make rowwise dumps
1294          type = x0xx  =>  columnwise dumps
1295          type = x1xx  =>  rowwise dumps (see matlab manual) */
1296     for(j = 1; j < num_panels+1; j++) {
1297       /* load I col into q and zero p */
1298       for(i = 0; i < num_panels+1; i++) {
1299 	if(i == j) sys->q[i] = 1.0;
1300 	else sys->q[i] = 0.0;
1301       }
1302       /* figure the column of C in p (xfered to q after calculation) */
1303       mulPrecond(sys, PRECOND);
1304       /* dump the preconditioner column */
1305       if(j == 1) savemat_mod(fp, 1000, "Ctil", num_panels, num_panels, 0,
1306 			     &(sys->q[1]), (double *)NULL, 0, num_panels);
1307       else savemat_mod(fp, 1000, "Ctil", num_panels, num_panels, 0,
1308 		       &(sys->q[1]), (double *)NULL, 1, num_panels);
1309 
1310     }
1311   }
1312 
1313   if(type == 1 || type == 2) {
1314     fprintf(stdout, "\nDumping pot. coeff. mat. to `prec.mat' as `P'\n");
1315     /* dump the P matrix - DANGER: does n^2 calcp() calls,
1316        but storage is only n */
1317     /* are q indices from 1?? */
1318     for(j = 1; j < num_panels+1; j++) {
1319       /* find the panel with the current index (select column) */
1320       for(pp = chglist; pp != NULL; pp = pp->next) {
1321 	if(pp->index == j) break;
1322       }
1323       if(pp == NULL) {
1324 	fprintf(stderr, "dump_preconditioner: no charge with index %d\n", j);
1325 	exit(1);
1326       }
1327       for(i = 0; i < num_panels+1; i++) sys->p[i] = 0.0;
1328       /* find the column---influence of q_j on potentials at each q_i */
1329       for(i = 1, pi = chglist; pi != NULL; i++, pi = pi->next) {
1330 	sys->p[pi->index] = calcp(pp, pi->x, pi->y, pi->z, NULL);
1331       }
1332       /* dump the column */
1333       if(j == 1) savemat_mod(fp, 1000, "P", num_panels, num_panels, 0,
1334 			     &(sys->p[1]), (double *)NULL, 0, num_panels);
1335       else savemat_mod(fp, 1000, "P", num_panels, num_panels, 0,
1336 		       &(sys->p[1]), (double *)NULL, 1, num_panels);
1337 
1338     }
1339   }
1340 
1341   fclose(fp);
1342 }
1343 
1344 /*
1345   do an n^2/2 check to see if any panels have the same center points
1346   (debug only)
1347 */
has_duplicate_panels(fp,chglst)1348 int has_duplicate_panels(fp, chglst)
1349 charge *chglst;
1350 FILE *fp;
1351 {
1352   int no_duplicates;
1353   charge *cp, *cpinner;
1354 
1355   no_duplicates = TRUE;
1356   for(cp = chglst; cp != NULL; cp = cp->next) {
1357     for(cpinner = cp->next; cpinner != NULL; cpinner = cpinner->next) {
1358       if(cp->x == cpinner->x && cp->y == cpinner->y && cp->z == cpinner->z) {
1359 	no_duplicates = FALSE;
1360 
1361 	if(cp->surf->type == CONDTR) fprintf(fp, "Panels %d(CONDTR)",
1362 						cp->index);
1363 	if(cp->surf->type == DIELEC) fprintf(fp, "Panels %d(DIELEC)",
1364 						cp->index);
1365 	if(cp->surf->type == BOTH) fprintf(fp, "Panels %d(BOTH)",
1366 					      cp->index);
1367 
1368 	if(cpinner->surf->type == CONDTR) fprintf(fp, " and %d(CONDTR)",
1369 						cpinner->index);
1370 	if(cpinner->surf->type == DIELEC) fprintf(fp, " and %d(DIELEC)",
1371 						cpinner->index);
1372 	if(cpinner->surf->type == BOTH) fprintf(fp, " and %d(BOTH)",
1373 					      cpinner->index);
1374 
1375 	fprintf(fp, " both have center (%.3g %.3g %.3g)\n",
1376 		cp->x, cp->y, cp->z);
1377       }
1378     }
1379   }
1380 
1381   if(no_duplicates) return(FALSE);
1382   else return(TRUE);
1383 }
1384 
1385 #if DSQ2PD == ON
1386 /*
1387   dump the condensed matrix for matlab use
1388 */
dumpQ2PDiag(nextc)1389 void dumpQ2PDiag(nextc)
1390 cube *nextc;
1391 {
1392   int i, j, ind, pos_d, neg_d;
1393   double temp[BUFSIZ], temp_mat[100][100], **rmat;
1394   double pos_fact, neg_fact, panel_fact;
1395   FILE *fp, *fopen();
1396 
1397   /* dump the diag matrix to a matlab file along with its dummy vector */
1398   /*   must complie on sobolev with /usr/local/matlab/loadsave/savemat.o */
1399   if((fp = fopen("Q2PDiag.mat", "w")) == NULL) {
1400     fprintf(stderr, "dumpQ2PDiag: can't open `Q2PDiag.mat' to write\n");
1401     exit(1);
1402   }
1403   if(sizeof(temp) < nextc->upnumeles[0]*nextc->upnumeles[0]) {
1404     fprintf(stderr, "dumpQ2PDiag: temporary arrays not big enough\n");
1405     exit(1);
1406   }
1407 
1408   /* incorporate the electric field evaluation into the matrix */
1409   /* if a row corresponds to a flux density difference, alter it */
1410   rmat = nextc->directmats[0];
1411   for(i = 0; i < nextc->upnumeles[0]; i++) {
1412     if(nextc->chgs[i]->dummy) {
1413       for(j = 0; j < nextc->upnumeles[0]; j++) temp_mat[i][j] = 0.0;
1414       continue;
1415     }
1416 
1417     if(nextc->chgs[i]->surf->type == CONDTR) {
1418       for(j = 0; j < nextc->upnumeles[0]; j++) {
1419 	temp_mat[i][j] = rmat[i][j];
1420       }
1421     }
1422     else {
1423 
1424       pos_fact
1425 	  = nextc->chgs[i]->surf->outer_perm/nextc->chgs[i]->pos_dummy->area;
1426       pos_d = nextc->chgs[i]->pos_dummy->index - 1;
1427       neg_fact
1428 	  = nextc->chgs[i]->surf->inner_perm/nextc->chgs[i]->neg_dummy->area;
1429       neg_d = nextc->chgs[i]->neg_dummy->index - 1;
1430       panel_fact = pos_fact + neg_fact;
1431 
1432       for(j = 0; j < nextc->upnumeles[0]; j++) {
1433 	temp_mat[i][j] = pos_fact*rmat[pos_d][j] - panel_fact*rmat[i][j]
1434 	    + neg_fact*rmat[neg_d][j];
1435       }
1436     }
1437   }
1438 
1439   /* flatten the Q2PDiag matrix */
1440   for(j = ind = 0; j < nextc->upnumeles[0]; j++) {
1441     for(i = 0; i < nextc->upnumeles[0]; i++) {
1442       temp[ind++] = temp_mat[i][j];
1443     }
1444   }
1445   savemat(fp, 1000, "A", nextc->upnumeles[0], nextc->upnumeles[0],
1446 	  0, temp, (double *)NULL);
1447 
1448   /* make the is_dummy vector a vector of doubles */
1449   for(i = 0; i < nextc->upnumeles[0]; i++)
1450       temp[i] = (double)(nextc->nbr_is_dummy[0][i]);
1451   savemat(fp, 1000, "is_dummy", nextc->upnumeles[0], 1,
1452 	  0, temp, (double *)NULL);
1453 
1454   /* make a vector with 0 => CONDTR 1 => DIELEC 2 => BOTH -1 => dummy */
1455   for(i = 0; i < nextc->upnumeles[0]; i++) {
1456     if(nextc->chgs[i]->dummy) temp[i] = -1.0;
1457     else temp[i] = (double)(nextc->chgs[i]->surf->type);
1458   }
1459   savemat(fp, 1000, "surf_type", nextc->upnumeles[0], 1,
1460 	  0, temp, (double *)NULL);
1461 
1462   fclose(fp);
1463   fprintf(stdout, "Dumped Q2PDiag matrix to `Q2PDiag.mat'\n");
1464 }
1465 
1466 #endif
1467 
1468 #if 1 == 0
1469 /*
1470   for debug only on SPARC2 -- NaN trap error handler (see man matherr)
1471 */
matherr(exc)1472 int matherr(exc)
1473 struct exception *exc;
1474 {
1475   fprintf(stderr, "matherr: ");
1476 
1477   if(exc->type == DOMAIN) fprintf(stderr, "DOMAIN error in");
1478   else if(exc->type == SING) fprintf(stderr, "SING error in");
1479   else if(exc->type == OVERFLOW) fprintf(stderr, "OVERFLOW error in");
1480   else if(exc->type == UNDERFLOW) fprintf(stderr, "UNDERFLOW error in");
1481 
1482   fprintf(stderr, " %s\n", exc->name);
1483 
1484   fprintf(stderr, " args: %g %g returning: %g\n", exc->arg1, exc->arg2,
1485 	  exc->retval);
1486   exit(1);
1487 }
1488 #endif
1489 
1490 /*
1491   debug only - check a vector to make sure it has zeros in dummy entries
1492 */
chkDummy(vector,is_dummy,size)1493 int chkDummy(vector, is_dummy, size)
1494 double *vector;
1495 int *is_dummy;
1496 int size;
1497 {
1498   int i, first = TRUE;
1499 
1500   for(i = 0; i < size; i++) {
1501     if(is_dummy[i] && vector[i] != 0.0) {
1502       if(first) {
1503 	first = FALSE;
1504 	fprintf(stderr, "\nchkDummy: entries should be 0.0: %d", i);
1505       }
1506       else fprintf(stderr, " %d", i);
1507     }
1508   }
1509   if(!first) fprintf(stderr, "\n");
1510 }
1511 
1512 /*
1513   debug only - print message if dummy list doesn't match panel list
1514 */
chkDummyList(panels,is_dummy,n_chgs)1515 void chkDummyList(panels, is_dummy, n_chgs)
1516 charge **panels;
1517 int *is_dummy;
1518 int n_chgs;
1519 {
1520   int i;
1521   int first = TRUE;
1522 
1523   for(i = 0; i < n_chgs; i++) {
1524     if(is_dummy[i] && !panels[i]->dummy || !is_dummy[i] && panels[i]->dummy) {
1525       if(first) {
1526 	first = FALSE;
1527 	fprintf(stderr, "chkDummyList: inconsistent dummy list entries:\n");
1528       }
1529       fprintf(stderr, " %d is_dummy = %d, panel->dummy = %d\n", i,
1530 	      is_dummy[i], panels[i]->dummy);
1531     }
1532   }
1533 
1534 }
1535 
1536 /*
1537   print the conductor names to a file
1538 */
dumpCondNames(fp,name_list)1539 void dumpCondNames(fp, name_list)
1540 FILE *fp;
1541 Name *name_list;
1542 {
1543   int i;
1544   char *last_alias();
1545   Name *cur_name;
1546 
1547   fprintf(fp, "CONDUCTOR NAMES\n");
1548   for(cur_name = name_list, i = 0; cur_name != NULL;
1549       cur_name = cur_name->next, i++) {
1550     fprintf(fp, "  %d `%s'\n", i+1, last_alias(cur_name));
1551   }
1552 }
1553 
1554 /*
1555   debug only: dump state of internal conductor name list
1556 */
dumpNameList(name_list)1557 int dumpNameList(name_list)
1558 Name *name_list;
1559 {
1560   Name *cur_name, *cur_alias;
1561 
1562   for(cur_name = name_list; cur_name != NULL; cur_name = cur_name->next) {
1563     fprintf(stdout, "`%s'\n", cur_name->name);
1564     for(cur_alias = cur_name->alias_list; cur_alias != NULL;
1565 	cur_alias = cur_alias->next) {
1566       fprintf(stdout, "  `%s'\n", cur_alias->name);
1567     }
1568   }
1569   return(TRUE);
1570 }
1571 
1572