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