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 <string.h>
36 #include "mulGlobal.h"
37 #include "zbufGlobal.h"
38 
39 #ifdef SOLARIS
40 #include <sys/systeminfo.h>
41 #endif
42 
43 /*
44   reads an input file list file (a list of dielectric i/f and conductor
45     surface files with permittivities)
46   returns linked list of file pointers and permittivities in surface structs
47   surface list file is specified on the command line with `-l<filename>'
48   each line in the list file specifies a surface filename and its permittivites
49   if a list file line has the filename string `stdin' then stdin will be
50     read (note that more than one `stdin' is not allowed)
51 
52   list file line formats
53   conductor surface:
54   C <filename> <outer rel permittivity> <tx> <ty> <tz> [+]
55 
56   dielectric surface:
57   D <file> <outer rel perm> <inner rel perm> <tx> <ty> <tz> <rx> <ry> <rz> [-]
58 
59   thin conductor on dielectric boundary (B => "both"):
60   B <file> <outer rel perm> <inner rel perm> <tx> <ty> <tz> <rx> <ry> <rz> [+-]
61 
62   group name specification line:
63   G <group name>
64 
65   comment line:
66   * <comment line>
67 
68   the <tx> <ty> <tz> are 3 components of a translation vector that is applied
69     to all the panels in the file
70   the <rx> <ry> <rz> specify a reference point on the outside of the
71     interface surface (all surface normals should point towards the point)
72     the optional `-' indicates that the reference point is inside
73     the surface (all surface normals should point away from the point)
74     the reference point is used to figure which permittivity is on which side
75     for type B surfaces, there must be no space between the `+' and `-' if
76       both are used - note that D surfaces must never have a `+'
77     since the reference point must be on one side, each file must contain
78       a convex surface (ie any surface must be broken into such subsurfaces)
79   the optional `+' indicates that the panels in the next conductor line file
80     should be grouped together for the purposes of renumbering
81     - if two files have two distinct conductors but both sets of panels
82       are numbered `1' inside the two files then use something like
83       C first_file 1.5 <tx> <ty> <tz>
84       C second_file 1.5 <tx> <ty> <tz>
85     - on the other hand, if parts of the same conductor are split into
86       two files (say because the second part borders a different dielectric)
87       then use something like
88       C first_file 1.5 <tx> <ty> <tz> +
89       C second_file 2.0 <tx> <ty> <tz>
90       in this case it is up to the user to make sure first_file's panels
91       and second_file's panels all have the same conductor number
92     - to disable the renumbering entirely, use the `+' on all the
93       conductor lines:
94       C first_file 3.0 <tx> <ty> <tz> +
95       C second_file 4.0 <tx> <ty> <tz> +
96       C last_file 3.0 <tx> <ty> <tz> +
97     - files grouped together with the + option have their conductor names
98       appended with the string ` (GROUP<number>)'
99       - for example, the conductor name `BIT_LINE' shows up as
100         `BIT_LINE (GROUP3)' if it is in the third group
101       - a string other than `GROUP<number>' may be specified for the
102         group name using G line `G <group name>' just before the group to
103 	be renamed; this is helpful when idenifying conductors to omit
104 	from capacitance calculations using the -k option
105 */
read_list_file(surf_list,num_surf,list_file,read_from_stdin)106 void read_list_file(surf_list, num_surf, list_file, read_from_stdin)
107 int *num_surf, read_from_stdin;
108 char *list_file;
109 surface **surf_list;
110 {
111   int linecnt, end_of_chain, ref_pnt_is_inside, group_cnt;
112   FILE *fp, *fopen();
113   char tline[BUFSIZ], file_name[BUFSIZ], plus[BUFSIZ], group_name[BUFSIZ];
114   double outer_perm, inner_perm, tx, ty, tz, rx, ry, rz;
115   surface *cur_surf;
116 
117   /* find the end of the current surface list */
118   if(*surf_list != NULL) {
119     for(cur_surf = *surf_list; cur_surf->next != NULL;
120 	cur_surf = cur_surf->next);
121   }
122 
123   /* attempt to open file list file */
124   if((fp = fopen(list_file, "r")) == NULL) {
125     fprintf(stderr, "read_list_file: can't open list file\n  `%s'\nto read\n",
126 	    list_file);
127     exit(0);
128   }
129 
130   /* read file names and permittivities, build linked list */
131   linecnt = 0;
132   group_cnt = read_from_stdin + 1;
133   sprintf(group_name, "GROUP%d", group_cnt);
134   while(fgets(tline, sizeof(tline), fp) != NULL) {
135     linecnt++;
136     if(tline[0] == 'C' || tline[0] == 'c') {
137       if(sscanf(&(tline[1]), "%s %lf %lf %lf %lf",
138 		file_name, &outer_perm, &tx, &ty, &tz) != 5) {
139 	fprintf(stderr,
140 	       "read_list_file: bad conductor surface format, tline %d:\n%s\n",
141 		linecnt, tline);
142 	exit(0);
143       }
144 
145       /* check if end of chain of surfaces with same conductor numbers */
146       end_of_chain = TRUE;
147       if(sscanf(&(tline[1]), "%s %lf %lf %lf %lf %s",
148 		file_name, &outer_perm, &tx, &ty, &tz, plus) == 6) {
149 	if(!strcmp(plus, "+")) end_of_chain = FALSE;
150       }
151 
152       /* allocate and load surface struct */
153       if(*surf_list == NULL) {
154 	CALLOC(*surf_list, 1, surface, ON, AMSC);
155 	cur_surf = *surf_list;
156       }
157       else {
158 	CALLOC(cur_surf->next, 1, surface, ON, AMSC);
159 	cur_surf->next->prev = cur_surf;
160 	cur_surf = cur_surf->next;
161       }
162 
163       cur_surf->type = CONDTR;
164       cur_surf->trans[0] = tx;
165       cur_surf->trans[1] = ty;
166       cur_surf->trans[2] = tz;
167       cur_surf->end_of_chain = end_of_chain;
168       CALLOC(cur_surf->name, strlen(file_name)+1, char, ON, AMSC);
169       strcpy(cur_surf->name, file_name);
170       cur_surf->outer_perm = outer_perm;
171 
172       /* set up group name */
173       CALLOC(cur_surf->group_name, strlen(group_name)+1, char, ON, AMSC);
174       strcpy(cur_surf->group_name, group_name);
175 
176       /* update group name if end of chain */
177       if(end_of_chain) {
178 	sprintf(group_name, "GROUP%d", ++group_cnt);
179       }
180 
181       (*num_surf)++;
182     }
183     else if(tline[0] == 'B' || tline[0] == 'b') {
184       if(sscanf(&(tline[1]), "%s %lf %lf %lf %lf %lf %lf %lf %lf",
185 		file_name, &outer_perm, &inner_perm, &tx, &ty, &tz,
186 		&rx, &ry, &rz) != 9) {
187 	fprintf(stderr,
188 		"read_list_file: bad thin conductor on dielectric interface surface format, line %d:\n%s\n",
189 		linecnt, tline);
190 	exit(0);
191       }
192 
193       /* check if end of chain of surfaces with same conductor numbers */
194       end_of_chain = TRUE;
195       ref_pnt_is_inside = FALSE;
196       if(sscanf(&(tline[1]), "%s %lf %lf %lf %lf %lf %lf %lf %lf %s",
197 		file_name, &outer_perm, &inner_perm, &tx, &ty, &tz,
198 		&rx, &ry, &rz, plus)
199 	 == 10) {
200 	if(!strcmp(plus, "+")) end_of_chain = FALSE;
201 	if(!strcmp(plus, "+-") || !strcmp(plus, "-+")) {
202 	  end_of_chain = FALSE;
203 	  ref_pnt_is_inside = TRUE;
204 	}
205 	if(!strcmp(plus, "-")) ref_pnt_is_inside = TRUE;
206       }
207 
208       /* allocate and load surface struct */
209       if(*surf_list == NULL) {
210 	CALLOC(*surf_list, 1, surface, ON, AMSC);
211 	cur_surf = *surf_list;
212       }
213       else {
214 	CALLOC(cur_surf->next, 1, surface, ON, AMSC);
215 	cur_surf->next->prev = cur_surf;
216 	cur_surf = cur_surf->next;
217       }
218 
219       cur_surf->type = BOTH;
220       cur_surf->trans[0] = tx;
221       cur_surf->trans[1] = ty;
222       cur_surf->trans[2] = tz;
223       cur_surf->ref[0] = rx;
224       cur_surf->ref[1] = ry;
225       cur_surf->ref[2] = rz;
226       cur_surf->ref_inside = ref_pnt_is_inside;
227       cur_surf->end_of_chain = end_of_chain;
228       CALLOC(cur_surf->name, strlen(file_name)+1, char, ON, AMSC);
229       strcpy(cur_surf->name, file_name);
230       cur_surf->outer_perm = outer_perm;
231       cur_surf->inner_perm = inner_perm;
232 
233       /* set up group name */
234       CALLOC(cur_surf->group_name, strlen(group_name)+1, char, ON, AMSC);
235       strcpy(cur_surf->group_name, group_name);
236 
237       /* update group name if end of chain */
238       if(end_of_chain) {
239 	sprintf(group_name, "GROUP%d", ++group_cnt);
240       }
241 
242       (*num_surf)++;
243     }
244     else if(tline[0] == 'D' || tline[0] == 'd') {
245       if(sscanf(&(tline[1]), "%s %lf %lf %lf %lf %lf %lf %lf %lf",
246 		file_name, &outer_perm, &inner_perm, &tx, &ty, &tz,
247 		&rx, &ry, &rz) != 9) {
248 	fprintf(stderr,
249 		"read_list_file: bad dielectric interface surface format, line %d:\n%s\n",
250 		linecnt, tline);
251 	exit(0);
252       }
253 
254       /* check to see if reference point is negative side of surface */
255       ref_pnt_is_inside = FALSE;
256       if(sscanf(&(tline[1]), "%s %lf %lf %lf %lf %lf %lf %lf %lf %s",
257 		file_name, &outer_perm, &inner_perm, &tx, &ty, &tz,
258 		&rx, &ry, &rz, plus)
259 	 == 10) {
260 	if(!strcmp(plus, "-")) ref_pnt_is_inside = TRUE;
261       }
262 
263       /* allocate and load surface struct */
264       if(*surf_list == NULL) {
265 	CALLOC(*surf_list, 1, surface, ON, AMSC);
266 	cur_surf = *surf_list;
267       }
268       else {
269 	CALLOC(cur_surf->next, 1, surface, ON, AMSC);
270 	cur_surf->next->prev = cur_surf;
271 	cur_surf = cur_surf->next;
272       }
273 
274       cur_surf->type = DIELEC;
275       cur_surf->trans[0] = tx;
276       cur_surf->trans[1] = ty;
277       cur_surf->trans[2] = tz;
278       cur_surf->ref[0] = rx;
279       cur_surf->ref[1] = ry;
280       cur_surf->ref[2] = rz;
281       cur_surf->ref_inside = ref_pnt_is_inside;
282       cur_surf->end_of_chain = TRUE;
283       CALLOC(cur_surf->name, strlen(file_name)+1, char, ON, AMSC);
284       strcpy(cur_surf->name, file_name);
285       cur_surf->outer_perm = outer_perm;
286       cur_surf->inner_perm = inner_perm;
287 
288       /* set up group name */
289       CALLOC(cur_surf->group_name, strlen(group_name)+1, char, ON, AMSC);
290       strcpy(cur_surf->group_name, group_name);
291 
292       /* update group name (DIELEC surface is always end of chain) */
293       sprintf(group_name, "GROUP%d", ++group_cnt);
294 
295       (*num_surf)++;
296     }
297     else if(tline[0] == 'G' || tline[0] == 'g') {
298       if(sscanf(&(tline[1]), "%s", group_name) != 1) {
299 	fprintf(stderr,"read_list_file: bad group name format, line %d:\n%s\n",
300 		linecnt, tline);
301 	exit(0);
302       }
303     }
304     else if(tline[0] == '%' || tline[0] == '*' ||
305 	    tline[0] == '#'); /* ignore comments */
306     else {
307       fprintf(stderr, "read_list_file: bad line format, line %d:\n%s\n",
308 		linecnt, tline);
309       exit(0);
310     }
311   }
312   fclose(fp);
313 
314 }
315 
316 #if 1 == 0			/* now done one panel at a time in initcalcp */
317 
318 /*
319   TEMPORARY: works best for closed surfaces in which case ref should
320     be a point inside with ref_inside = TRUE
321   can also be used with open surfaces: ref = point on - side, ref_inside = TRUE
322   will not work if the surface folds back on itself (and other ways too)
323 */
align_normals(panel_list,surf)324 void align_normals(panel_list, surf)
325 surface *surf;
326 charge *panel_list;
327 {
328   int i, flip_normal;
329   char *hack_path();
330   charge *nc;
331   double ctr_minus_n[3], ctr_plus_n[3], norm_minus, norm_plus, norm, norm_sq;
332   double x, y, z, *normal, *direction, *tempd;
333   int ref_inside = surf->ref_inside;
334   double *ref = surf->ref, temp;
335   char *surf_name = surf->name;
336 
337   for(nc = panel_list; nc != NULL; nc = nc->next) {
338 
339     /* get panel position (relative to reference point) and normal */
340     x = nc->x - ref[0]; y = nc->y - ref[1]; z = nc->z - ref[2];
341     norm_sq = x*x + y*y + z*z;
342     norm = sqrt(norm_sq);
343     normal = nc->Z;
344 
345     /* add the (scaled) normal and negative normal to the panel center */
346     /* negative normal result should be closer to ref point if(ref_inside) */
347     ctr_minus_n[0] = x - 0.1*norm*normal[0];
348     ctr_minus_n[1] = y - 0.1*norm*normal[1];
349     ctr_minus_n[2] = z - 0.1*norm*normal[2];
350     ctr_plus_n[0] = x + 0.1*norm*normal[0];
351     ctr_plus_n[1] = y + 0.1*norm*normal[1];
352     ctr_plus_n[2] = z + 0.1*norm*normal[2];
353 
354     /* get norms of test points, one inside (minus) other out (plus) */
355     norm_minus = ctr_minus_n[0]*ctr_minus_n[0];
356     norm_plus = ctr_plus_n[0]*ctr_plus_n[0];
357     for(i = 1; i < 3; i++) {
358       norm_minus += ctr_minus_n[i]*ctr_minus_n[i];
359       norm_plus += ctr_plus_n[i]*ctr_plus_n[i];
360     }
361 
362     flip_normal = FALSE;
363     if(norm_minus > norm_sq) {
364       if(norm_plus > norm_sq) {
365 	fprintf(stderr,
366 		"align_normals: both test points on non-reference side\n");
367 	fprintf(stderr, "  Surface: %s\n", hack_path(surf_name));
368 	fprintf(stderr, "  Translation: (%g %g %g)\n", surf->trans[0],
369 		surf->trans[1], surf->trans[2]);
370 	fprintf(stderr, "  Reference point: (%g %g %g)\n",
371 		ref[0], ref[1], ref[2]);
372 	fprintf(stderr, "  Panel cntr: (%g %g %g)\n",
373 		nc->x, nc->y, nc->z);
374 	fprintf(stderr, "  Normal: (%g %g %g)\n",
375 		normal[0], normal[1], normal[2]);
376 	exit(0);
377       }
378       if(ref_inside) flip_normal = TRUE;
379     }
380     else if(norm_plus < norm_sq) {
381       if(norm_minus < norm_sq) {
382 	fprintf(stderr,
383 		"align_normals: both test points on reference point side\n");
384 	fprintf(stderr, "  Surface: %s\n", hack_path(surf_name));
385 	fprintf(stderr, "  Translation: (%g %g %g)\n", surf->trans[0],
386 		surf->trans[1], surf->trans[2]);
387 	fprintf(stderr, "  Reference point: (%g %g %g)\n",
388 		ref[0], ref[1], ref[2]);
389 	fprintf(stderr, "  Panel cntr: (%g %g %g)\n",
390 		nc->x, nc->y, nc->z);
391 	fprintf(stderr, "  Normal: (%g %g %g)\n",
392 		normal[0], normal[1], normal[2]);
393 	exit(0);
394       }
395       if(!ref_inside) flip_normal = TRUE;
396     }
397 
398     if(flip_normal) {
399       for(i = 0; i < 3; i++) {
400 	normal[i] = -normal[i];	/* flip the normal */
401 	nc->X[i] = -(nc->X[i]);	/* flip the x direction */
402 	/* interchange points 0 and 2 so that corner order will be
403 	   consistent with X flip (note that this is OK for quads and tris) */
404 	temp = nc->corner[0][i];
405 	nc->corner[0][i] = nc->corner[2][i];
406 	nc->corner[2][i] = temp;
407       }
408     }
409   }
410 }
411 
412 #endif
413 
414 /*
415   add dummy panel structs to the panel list for electric field evaluation
416   - assumes its handed a list of DIELEC or BOTH type panels
417 */
add_dummy_panels(panel_list)418 void add_dummy_panels(panel_list)
419 charge *panel_list;
420 {
421   double h;
422   charge *dummy_list = NULL;
423   charge *cur_panel, *cur_dummy;
424 
425   for(cur_panel = panel_list; cur_panel != NULL; cur_panel = cur_panel->next) {
426     cur_panel->dummy = FALSE;
427 
428     /* make 2 dummy panels for evaluation points needed to do div difference */
429     /* make the first */
430     if(dummy_list == NULL) {
431       CALLOC(dummy_list, 1, charge, ON, AMSC);
432       cur_dummy = dummy_list;
433     }
434     else {
435       CALLOC(cur_dummy->next, 1, charge, ON, AMSC);
436       cur_dummy = cur_dummy->next;
437     }
438 
439     cur_dummy->dummy = TRUE;
440     h = HPOS;
441     cur_dummy->x = cur_panel->x + cur_panel->Z[0]*h;
442     cur_dummy->y = cur_panel->y + cur_panel->Z[1]*h;
443     cur_dummy->z = cur_panel->z + cur_panel->Z[2]*h;
444     /* note ABUSE OF area field - used to store div dif distance */
445     cur_dummy->area = h;
446 
447     cur_panel->pos_dummy = cur_dummy; /* link dummy to its real panel */
448 
449     /* make the second dummy struct */
450     CALLOC(cur_dummy->next, 1, charge, ON, AMSC);
451     cur_dummy = cur_dummy->next;
452 
453     cur_dummy->dummy = TRUE;
454     h = HNEG;
455     cur_dummy->x = cur_panel->x - cur_panel->Z[0]*h;
456     cur_dummy->y = cur_panel->y - cur_panel->Z[1]*h;
457     cur_dummy->z = cur_panel->z - cur_panel->Z[2]*h;
458     /* note ABUSE OF area field - used to store div dif distance */
459     cur_dummy->area = h;
460 
461     cur_panel->neg_dummy = cur_dummy; /* link dummy to its real panel */
462   }
463 
464   /* put the dummies in the list */
465   for(cur_panel = panel_list; cur_panel->next != NULL;
466       cur_panel = cur_panel->next);
467   cur_panel->next = dummy_list;
468 
469 }
470 
471 /* returns a pointer to a file name w/o the path (if present) */
hack_path(str)472 char *hack_path(str)
473 char *str;
474 {
475   int i;
476   int last_slash;
477 
478   for(i = last_slash = 0; str[i] != '\0'; i++) {
479     if(str[i] == '/') last_slash = i;
480   }
481 
482   if(str[last_slash] == '/') return(&(str[last_slash+1]));
483   else return(str);
484 }
485 
486 /*
487   reassigns conductor numbers to a list of panels so that they'll
488     be numbered contiguously from 1
489   - also changes conductor numbers associated with conductor name structs
490   - dummy panels are skipped
491   - dielectric panels, with conductor number 0, are also skipped
492 */
reassign_cond_numbers(panel_list,name_list,surf_name)493 void reassign_cond_numbers(panel_list, name_list, surf_name)
494 char *surf_name;
495 NAME *name_list;
496 charge *panel_list;
497 {
498   int i, j, cond_nums[MAXCON], num_cond, cond_num_found, temp;
499   char str[BUFSIZ], *hack_path();
500   charge *cur_panel;
501   NAME *cur_name;
502 
503   /* get the conductor numbers currently being used */
504   num_cond = 0;
505   for(cur_panel = panel_list; cur_panel != NULL; cur_panel = cur_panel->next) {
506     if(cur_panel->dummy || cur_panel->cond == 0) continue;
507 
508     cond_num_found = FALSE;
509     for(i = 0; i < num_cond; i++) {
510       if(cur_panel->cond == cond_nums[i]) {
511 	cond_num_found = TRUE;
512 	break;
513       }
514     }
515     if(!cond_num_found) cond_nums[num_cond++] = cur_panel->cond;
516   }
517 
518   /* rewrite all the conductor numbers to be their position in the array */
519   for(cur_panel = panel_list; cur_panel != NULL; cur_panel = cur_panel->next) {
520     if(cur_panel->dummy || cur_panel->cond == 0) continue;
521 
522     for(i = 0; i < num_cond && cur_panel->cond != cond_nums[i]; i++);
523     if(i == num_cond) {
524       fprintf(stderr,
525        "reassign_cond_numbers: cant find conductor number that must exist\n");
526       exit(0);
527     }
528     cur_panel->cond = i+1;
529   }
530 
531   /* do the same for the name structs */
532   for(cur_name = name_list; cur_name != NULL; cur_name = cur_name->next) {
533     for(i = 0;
534 	i < num_cond && cur_name->patch_list->conductor_ID != cond_nums[i];
535 	i++);
536     if(i == num_cond) {
537       fprintf(stderr,
538 	   "reassign_cond_numbers: cant find conductor number in name list\n");
539       exit(0);
540     }
541 #if 1 == 0
542     /* change the name given to this conductor if it was derived from the ID */
543     /* check the number */
544     if(sscanf(&(cur_name->name[9]), "%d", &temp) == 1) {
545       if(temp == cur_name->patch_list->conductor_ID) {
546 	strcpy(str, cur_name->name);
547 	str[9] = '\0';
548 	/* check the rest of the string, replace if necessary */
549 	if(!strcmp(str, "CONDUCTOR")) {
550 	  sprintf(str, "COND%d (%s)", i+1, hack_path(surf_name));
551 	  if(strlen(str) > strlen(cur_name->name))
552 	      CALLOC(cur_name->name, strlen(str)+1, char, ON, AMSC);
553 	  strcpy(cur_name->name, str);
554 	}
555       }
556     }
557     cur_name->patch_list->conductor_ID = i+1;
558 #endif
559   }
560 
561 
562 }
563 
564 /*
565   negates all the conductor numbers - used to make a panel list's conds unique
566     just before renumbering
567 */
negate_cond_numbers(panel_list,name_list)568 void negate_cond_numbers(panel_list, name_list)
569 NAME *name_list;
570 charge *panel_list;
571 {
572   charge *cur_panel;
573   NAME *cur_name;
574 
575   for(cur_panel = panel_list; cur_panel != NULL; cur_panel = cur_panel->next) {
576     if(cur_panel->dummy) continue;
577 
578     cur_panel->cond = -cur_panel->cond;
579   }
580 
581   for(cur_name = name_list; cur_name != NULL; cur_name = cur_name->next) {
582     cur_name->patch_list->conductor_ID = -cur_name->patch_list->conductor_ID;
583   }
584 }
585 
586 /*
587   for debug - dumps the iter list
588 */
dump_ilist()589 int dump_ilist()
590 {
591   ITER *cur_iter;
592   extern ITER *qpic_num_list;
593 
594   /* check the list for the iter number passed in */
595   fprintf(stdout, "Iter list:");
596   for(cur_iter = qpic_num_list; cur_iter != NULL; cur_iter = cur_iter->next) {
597     fprintf(stdout, "%d ", cur_iter->iter);
598   }
599   fprintf(stdout, "\n");
600   return(TRUE);
601 }
602 
603 #if 1 == 0
604 /*
605   adds an iteration number to the list that get shaded .ps file dumps
606   - list is built on global variable q_iter
607 */
add_iter(iter_num)608 void add_iter(iter_num)
609 int iter_num;
610 {
611   ITER *cur_iter, *tail_iter;
612   extern ITER *q_iter;
613 
614   /* check the list for the iter number passed in */
615   for(cur_iter = q_iter; cur_iter != NULL;
616       tail_iter = cur_iter, cur_iter = cur_iter->next) {
617     if(cur_iter->iter == iter_num) {
618       return;
619     }
620   }
621 
622   /* not in list; create a new iter struct to store the new iter number */
623   if(q_iter == NULL) {
624     CALLOC(q_iter, 1, ITER, ON, AMSC);
625     tail_iter = q_iter;
626   }
627   else {
628     CALLOC(tail_iter->next, 1, ITER, ON, AMSC);
629     tail_iter = tail_iter->next;
630   }
631   tail_iter->iter = iter_num;
632   tail_iter->next = NULL;
633 }
634 #endif
635 
636 /*
637   checks if a particular iter is in the list; returns TRUE if it is
638 */
want_this_iter(iter_list,iter_num)639 int want_this_iter(iter_list, iter_num)
640 ITER *iter_list;
641 int iter_num;
642 {
643   ITER *cur_iter;
644 
645   for(cur_iter = iter_list; cur_iter != NULL; cur_iter = cur_iter->next) {
646     if(cur_iter->iter == iter_num) {
647       return(TRUE);
648     }
649   }
650 
651   return(FALSE);
652 }
653 /*
654   sets up the ps file base string
655 */
get_ps_file_base(argv,argc)656 void get_ps_file_base(argv, argc)
657 char *argv[];
658 int argc;
659 {
660   int i, j;
661   char temp[BUFSIZ], *hack_path();
662   extern char *ps_file_base, *in_file_name;
663 
664   /* - if no list file, use input file; otherwise use list file */
665   /* - if neither present, use "stdin" */
666   /*   check for list file */
667   for(i = 1; i < argc; i++) {
668     if(argv[i][0] == '-' && argv[i][1] == 'l') {
669       strcpy(temp, &(argv[i][2]));
670       /* go to end of string, walk back to first period */
671       for(j = 0; temp[j] != '\0'; j++);
672       for(; temp[j] != '.' && j >= 0; j--);
673       if(temp[j] == '.') temp[j] = '\0';
674       /* save list file base */
675       CALLOC(ps_file_base, strlen(temp)+1, char, ON, AMSC);
676       strcpy(ps_file_base, hack_path(temp));
677       break;
678     }
679     else if(argv[i][0] != '-') { /* not an option, must be input file */
680       /* modified for fasthenry to allow ../../fname.inp */
681       strcpy(temp, argv[i]);
682       for(j = strlen(temp); j != -1 && temp[j] != '.' && temp[j] != '/'; j--);
683       if (j == -1 || temp[j] == '/')
684         j = strlen(temp) + 1;
685       temp[j] = '\0';
686       /* save list file base */
687       CALLOC(in_file_name, strlen(temp)+1, char, ON, AMSC);
688       strcpy(in_file_name, temp);
689       CALLOC(ps_file_base, strlen(temp)+1, char, ON, AMSC);
690       strcpy(ps_file_base, hack_path(temp));
691       break;
692     }
693   }
694 
695   if(ps_file_base == NULL) {	/* input must be stdin */
696     CALLOC(ps_file_base, strlen("stdin")+1, char, ON, AMSC);
697     strcpy(ps_file_base, "stdin");
698   }
699 }
700 
701 /*
702   open all the surface files and return a charge (panel) struct list
703   set up pointers from each panel to its corresponding surface struct
704   align the normals of all the panels in each surface so they point
705     towards the same side as where the ref point is (dielectric files only)
706 */
read_panels(surf_list,name_list,num_cond)707 charge *read_panels(surf_list, name_list, num_cond)
708 Name **name_list;
709 int *num_cond;
710 surface *surf_list;
711 {
712   int patran_file, num_panels, stdin_read, num_dummies, num_quads, num_tris;
713   charge *panel_list = NULL, *cur_panel, *patfront(), *panel_group, *c_panel;
714   surface *cur_surf;
715   extern NAME *start_name, *start_name_this_time;
716   extern char *title;
717   NAME *name_group;
718   FILE *fp, *fopen();
719   char surf_name[BUFSIZ], *hack_path();
720   int patran_file_read;
721 
722   /*title[0] = '\0';*/
723   stdin_read = FALSE;
724   for(cur_surf = surf_list; cur_surf != NULL; cur_surf = cur_surf->next) {
725     if(!strcmp(cur_surf->name, "stdin")) {
726       if(stdin_read) {
727 	fprintf(stderr, "read_panels: attempt to read stdin twice\n");
728 	exit(0);
729       }
730       else {
731 	stdin_read = TRUE;
732 	fp = stdin;
733       }
734     }
735     else if((fp = fopen(cur_surf->name, "r")) == NULL) {
736       fprintf(stderr, "read_panels: can't open\n  `%s'\nto read\n",
737 	      cur_surf->name);
738       exit(0);
739     }
740 
741     /* input the panel list */
742     if(panel_list == NULL) {
743       /* group names are set up in read_list_file() */
744       sprintf(surf_name, "%%%s", cur_surf->group_name);
745       panel_list = cur_panel
746 	  = patfront(fp, &patran_file, cur_surf->type, cur_surf->trans,
747 		     name_list, num_cond, surf_name);
748       patran_file_read = patran_file;
749       panel_group = cur_panel;
750       name_group = start_name;
751     }
752     else {
753       if(cur_surf->prev->end_of_chain) {
754 	sprintf(surf_name, "%%%s", cur_surf->group_name);
755 	patran_file_read = FALSE;
756       }
757       cur_panel->next
758 	  = patfront(fp, &patran_file, cur_surf->type, cur_surf->trans,
759 		     name_list, num_cond, surf_name);
760       if(!patran_file && patran_file_read) {
761 	fprintf(stderr, "read_panels: generic format file\n  `%s'\nread after neutral file(s) in same group---reorder list file entries\n", cur_surf->name);
762 	exit(0);
763       }
764       patran_file_read = patran_file;
765       cur_panel = cur_panel->next;
766       if(cur_surf->prev->end_of_chain) {
767 	/* if previous surface was the end of a chain, set up new group */
768 	panel_group = cur_panel;
769 	name_group = start_name_this_time; /* not really used anymore */
770       }
771     }
772     if(strcmp(cur_surf->name, "stdin") != 0) fclose(fp);
773 
774     cur_surf->panels = cur_panel;
775 
776     /* save the surface file's title */
777     CALLOC(cur_surf->title, strlen(title)+1, char, ON, AMSC);
778     strcpy(cur_surf->title, title);
779     title[0] = '\0';		/* not sure if needed */
780 
781     /* if the surface is a DIELEC, make sure all conductor numbers are zero */
782     /* - also link each panel to its surface */
783     for(c_panel = cur_panel; c_panel != NULL; c_panel = c_panel->next) {
784       if(cur_surf->type == DIELEC) c_panel->cond = 0;
785       c_panel->surf = cur_surf;
786     }
787 
788     /* align the normals and add dummy structs if dielec i/f */
789     initcalcp(cur_surf->panels);/* get normals, edges, perpendiculars */
790     if(cur_surf->type == DIELEC || cur_surf->type == BOTH) {
791       /* if(patran_file) align_normals(cur_surf->panels);
792       align_normals(cur_surf->panels, cur_surf); /* now done in calcp */
793       add_dummy_panels(cur_surf->panels); /* add dummy panels for field calc */
794     }
795 
796     /* make cur_panel = last panel in list, count panels */
797     num_panels = num_dummies = num_tris = num_quads = 0;
798     for(cur_panel = cur_surf->panels ; ; cur_panel = cur_panel->next) {
799       num_panels++;
800       if(cur_panel->dummy) num_dummies++;
801       else if(cur_panel->shape == 3) num_tris++;
802       else if(cur_panel->shape == 4) num_quads++;
803       else {
804 	fprintf(stderr, "read_panels: bad panel shape, %d\n",
805 		cur_panel->shape);
806 	exit(0);
807       }
808       if(cur_panel->next == NULL) break;
809     }
810 
811     /*fprintf(stdout, "Surface %s has %d quads and %d tris\n",
812 	    cur_surf->name, num_quads, num_tris);*/
813 
814     cur_surf->num_panels = num_panels;
815     cur_surf->num_dummies = num_dummies;
816 
817 #if 1 == 0			/* now done implicitly with suffix names */
818     if(cur_surf->type == CONDTR || cur_surf->type == BOTH) {
819       if(cur_surf->end_of_chain) {
820 	/* if the current surface is the end of a group to be #ed together, */
821 	/*   renumber the conductors in the newly input surface so numbering */
822 	/*   is unique and contiguous over the whole list */
823 	if(cur_surf != surf_list) { /* if this is not the first surface */
824 	  negate_cond_numbers(panel_group, name_group);
825 	  reassign_cond_numbers(panel_list, start_name, cur_surf->name);
826 	}
827 	else reassign_cond_numbers(panel_list, start_name, cur_surf->name);
828       }
829     }
830 #endif
831 
832   }
833   return(panel_list);
834 }
835 
836 /*
837   returns either conductor number or one of two error codes
838   NOTUNI => no group name given and name by itself is not unique
839   NOTFND => neither name by itself nor with group name is not in list
840   - any unique leading part of the name%group_name string may be specified
841 */
getUniqueCondNum(name,name_list)842 int getUniqueCondNum(name, name_list)
843 char *name;
844 Name *name_list;
845 {
846   int nlen, cond;
847   char name_frag[BUFSIZ], *last_alias(), *cur_alias;
848   Name *cur_name, *prev_name;
849   int i, j, alias_match_name(), times_in_list;
850 
851   nlen = strlen(name);
852   times_in_list = 0;
853 
854   /* fish through name list for name---check first nlen chars for match */
855   for(cur_name = name_list, i = 1; cur_name != NULL && times_in_list < 2;
856       cur_name = cur_name->next, i++) {
857     cur_alias = last_alias(cur_name);
858     for(j = 0; j < nlen; j++) name_frag[j] = cur_alias[j];
859     name_frag[j] = '\0';
860     if(!strcmp(name_frag, name)) {
861       times_in_list++;	/* increment times name in list count */
862       cond = i;
863     }
864     prev_name = cur_name;
865   }
866 
867   /* name can't be dealt with; return appropriate error code */
868   if(times_in_list > 2) return(NOTUNI);
869   else if(times_in_list == 1) return(cond);
870   else return(NOTFND);
871 }
872 
873 
874 /*
875   called after all conductor names have been resolved to get list
876     of conductor numbers that whose columns will not be calculated
877   parses the conductor kill list spec from command line arg saved before
878   (conds that get no solve); puts result in kill_num_list
879   list string format:
880   [<cond name>[%<group name>]],[<cond name>[%<group name>]]...
881   - no spaces; group name may be omitted if conductor name is unique
882     across all groups
883   - conductor names can't have any %'s
884   - redundant names are detected as errors
885 */
get_kill_num_list(name_list,kill_name_list)886 ITER *get_kill_num_list(name_list, kill_name_list)
887 char *kill_name_list;
888 Name *name_list;
889 {
890   int i, j, start_token, end_token, end_name, cond;
891   char name[BUFSIZ], group_name[BUFSIZ];
892   ITER *kill_num_list;
893   ITER *cur_cond;
894 
895   /* check for no name list given */
896   if(kill_name_list == NULL) return(NULL);
897 
898   start_token = 0;
899   kill_num_list = NULL;
900   while(kill_name_list[start_token] != '\0') {
901 
902     /* loop until next comma or end of list */
903     for(i = start_token; kill_name_list[i] != '\0' && kill_name_list[i] != ',';
904 	i++);
905     end_token = i;
906 
907     /* extract the name%group_name string */
908     /*   copy the name */
909     for(i = start_token, j = 0; i < end_token; i++, j++)
910 	name[j] = kill_name_list[i];
911     name[j] = '\0';
912 
913     /* attempt to get conductor number from name and group_name */
914     cond = getUniqueCondNum(name, name_list);
915     if(cond == NOTUNI) {
916       fprintf(stderr,
917    "get_kill_num_list: cannot find unique conductor name starting `%s'\n",
918 	      name);
919       exit(0);
920     }
921     else if(cond == NOTFND) {
922       fprintf(stderr,
923 	      "get_kill_num_list: cannot find conductor name starting `%s'\n",
924 	      name);
925       exit(0);
926     }
927 
928     /* add conductor name to list of conductors to omit */
929     if(kill_num_list == NULL) {
930       CALLOC(kill_num_list, 1, ITER, ON, AMSC);
931       cur_cond = kill_num_list;
932     }
933     else {
934       CALLOC(cur_cond->next, 1, ITER, ON, AMSC);
935       cur_cond = cur_cond->next;
936     }
937     cur_cond->iter = cond;
938 
939     if(kill_name_list[end_token] == ',') start_token = end_token+1;
940     else start_token = end_token;
941   }
942   return(kill_num_list);
943 }
944 
945 /*
946   command line parsing routine
947 */
parse_command_line(argv,argc,autmom,autlev,relperm,numMom,numLev,input_file,surf_list_file,read_from_stdin)948 void parse_command_line(argv, argc, autmom, autlev, relperm, numMom, numLev,
949 			input_file, surf_list_file, read_from_stdin)
950 int argc, *autmom, *autlev, *numMom, *numLev, *read_from_stdin;
951 double *relperm;
952 char *argv[], **input_file, **surf_list_file;
953 {
954   int cmderr, i;
955   char **chkp, *chk;
956   long strtol();
957   extern char *kill_name_list, *kinp_name_list;
958   extern ITER *kill_num_list, *kinp_num_list;
959   extern double iter_tol;
960 
961   extern int s_, n_, g_, c_, x_, k_, rc_, rd_, rb_, q_, rk_, m_, f_, dd_;
962   extern double view[], moffset[], rotation, distance, linewd, scale, axeslen;
963   extern double elevation, azimuth;
964   extern int up_axis;
965   extern char *line_file;
966   extern char *ps_file_base;
967   extern ITER *qpic_num_list;
968   extern char *qpic_name_list;
969   extern ITER *kq_num_list;
970   extern char *kq_name_list;
971   /* load default parameters */
972   azimuth = DEFAZM;             /* azimuth */
973   elevation = DEFELE;           /* elevation */
974   rotation = DEFROT;            /* rotation relative to image of z axis */
975   distance = DEFDST;            /* distance to view pnt = (1+distance)radius */
976   moffset[0] = OFFSETX;         /* puts the origin this dist from lower left */
977   moffset[1] = OFFSETY;
978   scale = DEFSCL;               /* master scaling - applied to 2d image */
979   linewd = DEFWID;              /* line width used in ps file */
980   axeslen = DEFAXE;             /* length of axes lines in 3d */
981   up_axis = DEFUAX;             /* upward-pointing axis in 2d image */
982   line_file = NULL;             /* file of lines/arrows in .fig format */
983   ps_file_base = NULL;		/* base used to form .ps file names */
984   qpic_num_list = NULL;		/* list of cond nums to get shaded plots for */
985   qpic_name_list = NULL;	/* list of cond names to get shaded plots */
986   kq_num_list = NULL;		/* list of cond nums in shaded plots */
987   kq_name_list = NULL;		/* list of cond names in shaded plots */
988   s_ = n_ = g_ = c_ = x_ = k_ = rc_ = rd_ = rb_ = q_ = rk_ = m_ = f_ = FALSE;
989   dd_ = FALSE;
990 
991   /* for fasthenry, all we ever do is visualization */
992   /* m_ = TRUE; */
993 
994   iter_tol = ABSTOL;
995   kill_num_list = kinp_num_list = NULL;
996   kill_name_list = kinp_name_list = NULL;
997   cmderr = FALSE;
998   chkp = &chk;			/* pointers for error checking */
999 
1000   for(i = 1; i < argc && cmderr == FALSE; i++) {
1001     if(argv[i][0] == '-') {
1002       if(argv[i][1] == 'd' && argv[i][2] == 'c') {
1003 	dd_ = TRUE;
1004       }
1005       else if(argv[i][1] == 'l') {
1006 	*surf_list_file = &(argv[i][2]);
1007       }
1008       else if(argv[i][1] == 'r' && argv[i][2] == 's') {
1009 	kill_name_list = &(argv[i][3]);
1010       }
1011       else if(argv[i][1] == 'r' && argv[i][2] == 'i') {
1012 	kinp_name_list = &(argv[i][3]);
1013       }
1014       else if(argv[i][1] == '\0') {
1015 	*read_from_stdin = TRUE;
1016       }
1017 /*#if CAPVEW == ON*/
1018       else if(argv[i][1] == 'f') {
1019 	f_ = TRUE;
1020       }
1021       else if(argv[i][1] == 'b') {
1022 	line_file = &(argv[i][2]);
1023       }
1024       else if(argv[i][1] == 'a') {
1025         if(sscanf(&(argv[i][2]), "%lf", &azimuth) != 1) {
1026 	  fprintf(stderr, "%s: bad view point azimuth angle '%s'\n",
1027 		  argv[0], &argv[i][2]);
1028 	  cmderr = TRUE;
1029 	  break;
1030 	}
1031       }
1032       else if(argv[i][1] == 'e') {
1033         if(sscanf(&(argv[i][2]), "%lf", &elevation) != 1) {
1034 	  fprintf(stderr, "%s: bad view point elevation angle '%s'\n",
1035 		  argv[0], &argv[i][2]);
1036 	  cmderr = TRUE;
1037 	  break;
1038 	}
1039       }
1040       else if(argv[i][1] == 'r' && argv[i][2] == 'c') {
1041 	kq_name_list = &(argv[i][3]);
1042 	rc_ = TRUE;
1043       }
1044       else if(!strcmp(&(argv[i][1]), "rd")) rd_ = TRUE;
1045       /*else if(!strcmp(&(argv[i][1]), "rb")) rb_ = TRUE;*/
1046       else if(!strcmp(&(argv[i][1]), "rk")) rk_ = TRUE;
1047       else if(argv[i][1] == 'r') {
1048         if(sscanf(&(argv[i][2]), "%lf", &rotation) != 1) {
1049 	  fprintf(stderr, "%s: bad image rotation angle '%s'\n",
1050 		  argv[0], &argv[i][2]);
1051 	  cmderr = TRUE;
1052 	  break;
1053 	}
1054       }
1055       else if(argv[i][1] == 'h') {
1056         if(sscanf(&(argv[i][2]), "%lf", &distance) != 1) cmderr = TRUE;
1057 	else if(distance <= 0.0) cmderr = TRUE;
1058 	if(cmderr) {
1059 	  fprintf(stderr, "%s: bad view point distance '%s'\n",
1060 		  argv[0], &argv[i][2]);
1061 	  break;
1062 	}
1063       }
1064       else if(argv[i][1] == 's') {
1065         if(sscanf(&(argv[i][2]), "%lf", &scale) != 1) cmderr = TRUE;
1066 	else if(scale <= 0.0) cmderr = TRUE;
1067 	if(cmderr) {
1068 	  fprintf(stderr, "%s: bad image scale factor '%s'\n",
1069 		  argv[0], &argv[i][2]);
1070 	  break;
1071 	}
1072       }
1073       else if(argv[i][1] == 'w') {
1074         if(sscanf(&(argv[i][2]), "%lf", &linewd) != 1) {
1075 				/* no check for < 0 so dash (-1) is pos. */
1076 	  fprintf(stderr, "%s: bad line width '%s'\n",
1077 		  argv[0], &argv[i][2]);
1078 	  cmderr = TRUE;
1079 	  break;
1080 	}
1081       }
1082       /* -x sets up axes of default length, -x<len> uses len as length */
1083       else if(argv[i][1] == 'x') {
1084 	if(argv[i][2] == '\0') x_ = TRUE;
1085 	else {
1086 	  if(sscanf(&(argv[i][2]), "%lf", &axeslen) != 1) {
1087 				/* no check for < 0 so axes can flip */
1088 	    fprintf(stderr, "%s: bad axes length '%s'\n",
1089 		    argv[0], &argv[i][2]);
1090 	    cmderr = TRUE;
1091 	    break;
1092 	  }
1093 	  else x_ = TRUE;
1094 	}
1095       }
1096       else if(argv[i][1] == 'v') s_ = TRUE;
1097       else if(argv[i][1] == 'n') n_ = TRUE;
1098       else if(argv[i][1] == 'g') g_ = TRUE;
1099       else if(argv[i][1] == 'c') c_ = TRUE;
1100       else if(argv[i][1] == 'm') m_ = TRUE;
1101       else if(argv[i][1] == 'q') {
1102 	get_ps_file_base(argv, argc); /* set up the output file base */
1103 	qpic_name_list = &(argv[i][2]);
1104 	q_ = TRUE;
1105       }
1106       else if(argv[i][1] == 'u') {
1107 	if(!strcmp(&(argv[i][2]), "x") || !strcmp(&(argv[i][2]), "X"))
1108 	    up_axis = XI;
1109 	else if(!strcmp(&(argv[i][2]), "y") || !strcmp(&(argv[i][2]), "Y"))
1110 	    up_axis = YI;
1111 	else if(!strcmp(&(argv[i][2]), "z") || !strcmp(&(argv[i][2]), "Z"))
1112 	    up_axis = ZI;
1113 	else {
1114 	  fprintf(stderr, "%s: bad up axis type `%s' -- use x, y or z\n",
1115               argv[0], &(argv[i][2]));
1116           cmderr = TRUE;
1117           break;
1118         }
1119       }
1120 /*#endif*/
1121       else {
1122 	fprintf(stderr, "%s: illegal option -- %s\n", argv[0], &(argv[i][1]));
1123 	cmderr = TRUE;
1124 	break;
1125       }
1126     }
1127     else {			/* isn't an option, must be the input file */
1128       *input_file = argv[i];
1129     }
1130   }
1131 
1132   if(cmderr == TRUE) {
1133 /*#if CAPVEW == ON*/
1134     fprintf(stderr,
1135 	    "Usage: '%s [<input file>]\n                [-rs<cond list>] [-ri<cond list>]\n                [-] [-l<list file>] [-a<azimuth>] [-e<elevation>]\n                [-r<rotation>] [-h<distance>] [-s<scale>] [-w<linewidth>]\n                [-u<upaxis>] [-q<cond list>] [-rc<cond list>] [-x<axeslength>]\n                [-b<.figfile>] [-m] [-rk] [-rd] [-dc] [-c] [-v] [-n] [-f] [-g]\n", argv[0]);
1136     fprintf(stderr, "DEFAULT VALUES:\n");
1137     fprintf(stderr, "  azimuth = %g\n  elevation = %g\n  rotation = %g\n",
1138 	    DEFAZM, DEFELE, DEFROT);
1139     fprintf(stderr,
1140 	    "  distance = %g (0 => 1 object radius away from center)\n",
1141 	    DEFDST);
1142     fprintf(stderr, "  scale = %g\n  linewidth = %g\n",
1143 	    DEFDST, DEFSCL, DEFWID);
1144     if(DEFUAX == XI) fprintf(stderr, "  upaxis = x\n");
1145     else if(DEFUAX == YI) fprintf(stderr, "  upaxis = y\n");
1146     else if(DEFUAX == ZI) fprintf(stderr, "  upaxis = z\n");
1147     fprintf(stderr, "  axeslength = %g\n", DEFAXE);
1148     fprintf(stderr, "OPTIONS:\n");
1149     fprintf(stderr, "  -   = force conductor surface file read from stdin\n");
1150     fprintf(stderr, "  -m  = DUMP in MATLAB FORMAT instead of postscript\n");
1151     fprintf(stderr, "  -rs = remove conductors from solve list\n");
1152     fprintf(stderr, "  -ri = remove conductors from input\n");
1153     fprintf(stderr,
1154      "  -q  = select conductors for at-1V charge distribution .ps pictures\n");
1155     fprintf(stderr,
1156      "  -rc = remove conductors from all charge distribution .ps pictures\n");
1157     fprintf(stderr,
1158 "  -b  = superimpose lines, arrows and dots in .figfile on all .ps pictures\n");
1159     fprintf(stderr,
1160       "  -rk = remove key in shaded .ps picture file (use with -q option)\n");
1161     fprintf(stderr,
1162       "  -rd = remove DIELEC type surfaces from all .ps picture files\n");
1163     fprintf(stderr,
1164 "  -dc = display total charges in shaded .ps picture file (use with -q option)\n");
1165     fprintf(stderr, "  -c  = print command line in .ps picture file\n");
1166     fprintf(stderr, "  -v  = suppress showpage in all .ps picture files\n");
1167     fprintf(stderr, "  -n  = number faces with input order numbers\n");
1168     fprintf(stderr, "  -f  = do not fill in faces (don't rmv hidden lines)\n");
1169     fprintf(stderr, "  -g  = dump depth graph and quit\n");
1170     fprintf(stderr, "  <cond list> = [<name>],[<name>],...,[<name>]\n");
1171     /*dumpConfig(stderr, argv[0]);*/
1172     exit(0);
1173   }
1174 }
1175 
1176 /*
1177   surface information input routine - panels are read by read_panels()
1178 */
read_all_surfaces(input_file,surf_list_file,read_from_stdin,infile,relperm)1179 surface *read_all_surfaces(input_file, surf_list_file, read_from_stdin, infile,
1180 			   relperm)
1181 int read_from_stdin;
1182 char *input_file, *surf_list_file, *infile;
1183 double relperm;
1184 {
1185   int num_surf, i;
1186   char group_name[BUFSIZ];
1187   surface *surf_list, *cur_surf;
1188 
1189   /* get the surfaces from stdin, the list file or the file on cmd line */
1190   /* the `- ' option always forces the first cond surf read from stdin */
1191   /* can also read from stdin if there's no list file and no cmd line file */
1192   infile[0] = '\0';
1193   num_surf = 0;
1194   surf_list = NULL;
1195   strcpy(group_name, "GROUP1");
1196   if(read_from_stdin || (input_file == NULL && surf_list_file == NULL)) {
1197     CALLOC(surf_list, 1, surface, ON, AMSC);
1198     surf_list->type = CONDTR;	/* only conductors can come in stdin */
1199     CALLOC(surf_list->name, strlen("stdin")+1, char, ON, AMSC);
1200     strcpy(surf_list->name, "stdin");
1201     surf_list->outer_perm = relperm;
1202     surf_list->end_of_chain = TRUE;
1203 
1204     /* set up group name */
1205     CALLOC(surf_list->group_name, strlen(group_name)+1, char, ON, AMSC);
1206     strcpy(surf_list->group_name, group_name);
1207     strcpy(group_name, "GROUP2");
1208 
1209     cur_surf = surf_list;
1210 
1211     strcpy(infile, "stdin");
1212     num_surf++;
1213   }
1214 
1215   /* set up to read from command line file, if necessary */
1216   if(input_file != NULL) {
1217     if(surf_list == NULL) {
1218       CALLOC(surf_list, 1, surface, ON, AMSC);
1219       cur_surf = surf_list;
1220     }
1221     else {
1222       CALLOC(cur_surf->next, 1, surface, ON, AMSC);
1223       cur_surf = cur_surf->next;
1224     }
1225     cur_surf->type = CONDTR;
1226     CALLOC(cur_surf->name, strlen(input_file)+1, char, ON, AMSC);
1227     strcpy(cur_surf->name, input_file);
1228     cur_surf->outer_perm = relperm;
1229     cur_surf->end_of_chain = TRUE;
1230 
1231     /* set up group name */
1232     CALLOC(cur_surf->group_name, strlen(group_name)+1, char, ON, AMSC);
1233     strcpy(cur_surf->group_name, group_name);
1234 
1235     for(i = 0; infile[i] != '\0'; i++);
1236     if(infile[0] != '\0') sprintf(&(infile[i]), ", %s", input_file);
1237     else sprintf(&(infile[i]), "%s", input_file);
1238     num_surf++;
1239     read_from_stdin++;
1240   }
1241 
1242   /* read list file if present */
1243   if(surf_list_file != NULL) {
1244     read_list_file(&surf_list, &num_surf, surf_list_file, read_from_stdin);
1245     for(i = 0; infile[i] != '\0'; i++);
1246     if(infile[0] != '\0') sprintf(&(infile[i]), ", %s", surf_list_file);
1247     else sprintf(&(infile[i]), "%s", surf_list_file);
1248   }
1249 
1250   return(surf_list);
1251 }
1252 
1253 /*
1254   surface input routine and command line parser
1255   - inputs surfaces (ie file names whose panels are read in read_panels)
1256   - sets parameters accordingly
1257 */
input_surfaces(argv,argc,autmom,autlev,relperm,numMom,numLev,infile)1258 surface *input_surfaces(argv, argc, autmom, autlev, relperm,
1259 			numMom, numLev, infile)
1260 int argc, *autmom, *autlev, *numMom, *numLev;
1261 double *relperm;
1262 char *argv[], *infile;
1263 {
1264   int read_from_stdin, num_surf;
1265   surface *read_all_surfaces();
1266   char *surf_list_file, *input_file;
1267 
1268   /* initialize defaults */
1269   surf_list_file = input_file = NULL;
1270   read_from_stdin = FALSE;
1271 
1272   parse_command_line(argv, argc, autmom, autlev, relperm, numMom, numLev,
1273 		     &input_file, &surf_list_file, &read_from_stdin);
1274 
1275   return(read_all_surfaces(input_file, surf_list_file,
1276 			   read_from_stdin, infile, *relperm));
1277 }
1278 
1279 /*
1280   dump the data associated with the input surfaces
1281 */
dumpSurfDat(surf_list)1282 void dumpSurfDat(surf_list)
1283 surface *surf_list;
1284 {
1285   surface *cur_surf;
1286   char *hack_path();
1287 
1288   fprintf(stdout, "  Input surfaces:\n");
1289   for(cur_surf = surf_list; cur_surf != NULL; cur_surf = cur_surf->next) {
1290 
1291     /* possibly write group name */
1292     if(cur_surf == surf_list) fprintf(stdout, "   %s\n", cur_surf->group_name);
1293     else if(cur_surf->prev->end_of_chain)
1294 	fprintf(stdout, "   %s\n", cur_surf->group_name);
1295 
1296     /* write file name */
1297     fprintf(stdout, "    %s", hack_path(cur_surf->name));
1298     if(cur_surf->type == CONDTR) {
1299       fprintf(stdout, ", conductor\n");
1300       fprintf(stdout, "      title: `%s'\n", cur_surf->title);
1301       fprintf(stdout, "      outer permittivity: %g\n",
1302 	      cur_surf->outer_perm);
1303     }
1304     else if(cur_surf->type == DIELEC) {
1305       fprintf(stdout, ", dielectric interface\n");
1306       fprintf(stdout, "      title: `%s'\n", cur_surf->title);
1307       fprintf(stdout, "      permittivities: %g (inner) %g (outer)\n",
1308 	      cur_surf->inner_perm, cur_surf->outer_perm);
1309     }
1310     else if(cur_surf->type == BOTH) {
1311       fprintf(stdout, ", thin conductor on dielectric interface\n");
1312       fprintf(stdout, "      title: `%s'\n", cur_surf->title);
1313       fprintf(stdout, "      permittivities: %g (inner) %g (outer)\n",
1314 	      cur_surf->inner_perm, cur_surf->outer_perm);
1315     }
1316     else {
1317       fprintf(stderr, "dumpSurfDat: bad surface type\n");
1318       exit(0);
1319     }
1320     fprintf(stdout,"      number of panels: %d\n",
1321 	    cur_surf->num_panels - cur_surf->num_dummies);
1322     fprintf(stdout,"      number of extra evaluation points: %d\n",
1323 	    cur_surf->num_dummies);
1324     fprintf(stdout,"      translation: (%g %g %g)\n",
1325 	    cur_surf->trans[0], cur_surf->trans[1], cur_surf->trans[2]);
1326 
1327   }
1328 }
1329 
1330 /*
1331   replaces name (and all aliases) corresponding to "num" with unique string
1332 */
remove_name(name_list,num)1333 void remove_name(name_list, num)
1334 int num;
1335 Name **name_list;
1336 {
1337   static char str[] = "%`_^#$REMOVED";
1338   Name *cur_name, *cur_alias;
1339   int i, slen;
1340 
1341   slen = strlen(str);
1342 
1343   for(i = 1, cur_name = *name_list; cur_name != NULL;
1344       cur_name = cur_name->next, i++) {
1345     if(i == num) {
1346 
1347       /* overwrite name */
1348       if(strlen(cur_name->name) < slen) {
1349 	CALLOC(cur_name->name, slen+1, char, ON, AMSC);
1350       }
1351       strcpy(cur_name->name, str);
1352 
1353       /* overwrite aliases */
1354       for(cur_alias = cur_name->alias_list; cur_alias != NULL;
1355 	  cur_alias = cur_alias->next) {
1356 	if(strlen(cur_alias->name) < slen) {
1357 	  CALLOC(cur_alias->name, slen+1, char, ON, AMSC);
1358 	}
1359 	strcpy(cur_alias->name, str);
1360       }
1361     }
1362   }
1363 
1364 }
1365 
1366 /*
1367   removes (unlinks from linked list) panels that are on conductors to delete
1368 */
remove_conds(panels,num_list,name_list)1369 void remove_conds(panels, num_list, name_list)
1370 charge **panels;
1371 ITER *num_list;
1372 Name **name_list;
1373 {
1374   ITER *cur_num;
1375   charge *cur_panel, *prev_panel;
1376 
1377   for(cur_panel = prev_panel = *panels; cur_panel != NULL;
1378       cur_panel = cur_panel->next) {
1379     if(cur_panel->dummy) continue;
1380     if(cur_panel->surf->type == CONDTR || cur_panel->surf->type == BOTH) {
1381       if(want_this_iter(num_list, cur_panel->cond)) {
1382 	/* panel's conductor is to be removed, so unlink the panel */
1383 	/* - if panel to be removed is first panel, rewrite head pointer */
1384 	if(cur_panel == *panels) *panels = cur_panel->next;
1385 	/* - otherwise bypass cur_panel with next pointers */
1386 	else prev_panel->next = cur_panel->next;
1387       }
1388       else prev_panel = cur_panel;
1389     }
1390   }
1391 
1392   /* remove all -ri'd conductor names from master name list
1393      - required to get rid of references in capsolve()
1394      - actually, name and all its aliases are replaced by ugly string
1395        (not the cleanest thing) */
1396   for(cur_num = num_list; cur_num != NULL; cur_num = cur_num->next) {
1397     remove_name(name_list, cur_num->iter);
1398   }
1399 }
1400 
1401 /*
1402   checks for kill lists with inconsistent demands
1403   -rs list: can't remove a conductor physically removed from computation w/-ri
1404   -q list: can't dump q plot for cond physically rmed or rmed from comp
1405   -rc list: no restrictions
1406   -ri/-rs: can't exhaust all conductors with combination of these lists
1407 */
resolve_kill_lists(rs_num_list,q_num_list,ri_num_list,num_cond)1408 void resolve_kill_lists(rs_num_list, q_num_list, ri_num_list, num_cond)
1409 ITER *rs_num_list, *q_num_list, *ri_num_list;
1410 int num_cond;
1411 {
1412   int i, lists_exhaustive;
1413   ITER *cur_num;
1414   extern int m_;
1415 
1416   /* check for anything in -rs list in -ri list */
1417   for(cur_num = ri_num_list; cur_num != NULL; cur_num = cur_num->next) {
1418     if(want_this_iter(rs_num_list, cur_num->iter)) {
1419       fprintf(stderr,
1420  "resolve_kill_lists: a conductor removed with -ri is in the -rs list\n");
1421       exit(0);
1422     }
1423   }
1424 
1425   /* check for anything in -q list in -ri or -rs list
1426      - recall that -q by itself means plot for all active,
1427        so null q_num_list always ok */
1428   for(cur_num = q_num_list; cur_num != NULL; cur_num = cur_num->next) {
1429     if(want_this_iter(rs_num_list, cur_num->iter)
1430        || want_this_iter(ri_num_list, cur_num->iter)) {
1431       fprintf(stderr,
1432 "resolve_kill_lists: a conductor removed with -ri or -rs is in the -q list\n");
1433       exit(0);
1434     }
1435   }
1436 
1437   /* check that -rs and -ri lists don't exhaust all conductors */
1438   lists_exhaustive = TRUE;
1439   for(i = 1; i <= num_cond; i++) {
1440     if(!want_this_iter(rs_num_list, i) && !want_this_iter(ri_num_list, i)) {
1441       lists_exhaustive = FALSE;
1442       break;
1443     }
1444   }
1445   if(lists_exhaustive && !m_) {
1446     fprintf(stderr,
1447 "resolve_kill_lists: all conductors either in -ri or -rs list\n");
1448     exit(0);
1449   }
1450 }
1451 
1452 /*
1453   main input routine, returns a list of panels in the problem
1454 */
input_problem(argv,argc,autmom,autlev,relperm,numMom,numLev,name_list,num_cond)1455 charge *input_problem(argv, argc, autmom, autlev, relperm,
1456 		      numMom, numLev, name_list, num_cond)
1457 int argc, *autmom, *autlev, *numMom, *numLev, *num_cond;
1458 double *relperm;
1459 char *argv[];
1460 Name **name_list;
1461 {
1462   surface *surf_list, *input_surfaces();
1463   char infile[BUFSIZ], *ctime(), hostname[BUFSIZ];
1464   charge *read_panels(), *chglist;
1465   time_t clock;
1466   extern ITER *kill_num_list, *qpic_num_list, *kinp_num_list, *kq_num_list;
1467   extern char *kill_name_list, *qpic_name_list, *kinp_name_list;
1468   extern char *kq_name_list;
1469 
1470   /* read the conductor and dielectric interface surface files, parse cmds */
1471   surf_list = input_surfaces(argv, argc, autmom, autlev, relperm,
1472 			     numMom, numLev, infile);
1473 
1474   if(*autmom == ON) *numMom = DEFORD;
1475 
1476 #if DIRSOL == ON || EXPGCR == ON
1477   /*fprintf(stderr, "DIRSOL and EXPGCR compile options not implemented\n");
1478   exit(0);*/
1479   *numLev = 0;	       	/* put all the charges in first cube */
1480   *autlev = OFF;
1481 #endif
1482 
1483   strcpy(hostname, "19Sep96");
1484   fprintf(stdout, "Running %s %.1f (%s)\n  Input: %s\n",
1485 	  argv[0], VERSION, hostname, infile);
1486 
1487   /* input the panels from the surface files */
1488   *num_cond = 0;		/* initialize conductor count */
1489   chglist = read_panels(surf_list, name_list, num_cond);
1490 
1491 #if 1 == 0
1492  removed for fasthenry: Not used for anything with visualization, hopefully
1493   /* set up the lists of conductors to remove from solve list */
1494   kill_num_list = get_kill_num_list(*name_list, kill_name_list);
1495 
1496   /* remove the panels on specified conductors from input list */
1497   kinp_num_list = get_kill_num_list(*name_list, kinp_name_list);
1498   remove_conds(&chglist, kinp_num_list, name_list);
1499 
1500   /* set up the lists of conductors to dump shaded plots for */
1501   qpic_num_list = get_kill_num_list(*name_list, qpic_name_list);
1502 
1503   /* set up the lists of conductors to eliminate from shaded plots */
1504   kq_num_list = get_kill_num_list(*name_list, kq_name_list);
1505 
1506   /* check for inconsistencies in kill lists */
1507   resolve_kill_lists(kill_num_list, qpic_num_list, kinp_num_list, *num_cond);
1508 #endif
1509 
1510 #if DISSRF == ON
1511   dumpSurfDat(surf_list);
1512 #endif
1513 
1514   time(&clock);
1515   fprintf(stdout, "  Date: %s", ctime(&clock));
1516 #ifndef NO_GETHOSTNAME
1517 #ifndef SOLARIS
1518   if(gethostname(hostname, BUFSIZ) != -1)
1519       fprintf(stdout, "  Host: %s\n", hostname);
1520   else fprintf(stdout, "  Host: ? (gethostname() failure)\n");
1521 #else
1522   if (sysinfo(SI_HOSTNAME,hostname,BUFSIZ) != -1)
1523       fprintf(stdout, "  Host: %s\n", hostname);
1524   else fprintf(stdout, "  Host: ? (sysinfo() failure)\n");
1525 #endif
1526 #endif
1527 
1528 #if CFGDAT == ON
1529   dumpConfig(stdout, argv[0]);
1530 #endif
1531 
1532   /* return the panels from the surface files */
1533   return(chglist);
1534 }
1535