1 /* this is the new fillM    10/92 */
2 
3 #include <string.h>
4 #include "induct.h"
5 
6 /* this fills the kircoff's voltage law matrix (Mesh matrix) */
7 /* it maps a matrix of mesh currents to branch currents */
8 /* it might actually be what some think of as the transpose of M */
9 /* Here, M*Im = Ib  where Im are the mesh currents, and Ib the branch */
10 /* 6/92 I added Mlist which is a vector of linked lists to meshes.
11    This replaces M.  But I keep M around for checking things in matlab. */
12 
13 /* much of what is commented out is obsolete stuff from an old idea
14    for a preconditioner that never worked */
fillM(indsys)15 void fillM(indsys)
16 SYS *indsys;
17 {
18 
19   GROUNDPLANE *plane;                           /* CMS 6/2/92 */
20 
21   int mesh, k, minimeshes;
22   MELEMENT **Mlist, *mend;
23   Minfo *m_info;
24   TREE *atree;
25   PATHLIST *aplist;
26   SPATH *apath;
27   SEGMENT *seg;
28   PSEUDO_SEG *pseg;
29 
30   Mlist = indsys->Mlist;
31   m_info = indsys->m_info;
32   mesh = 0;
33 
34   /* do all the loops due circuits in the graph */
35   for(atree = indsys->trees; atree != NULL; atree = atree->next)
36     for(aplist = atree->loops; aplist != NULL; aplist = aplist->next) {
37 
38       Mlist[mesh] = make_mesh_from_path(aplist->path, mesh, indsys);
39       if (Mlist[mesh] != NULL)
40 	/* it's possible that coincident gp nodes cause no path at all */
41 	mesh++;
42 
43      /* unimplemented junk
44       make_unconstrained(&(m_info[mesh]), mesh);
45       mesh += make_many_meshes_from_path(aplist->path, Mlist, m_info, mesh,
46 					 indsys);
47      */
48     }
49 
50   if (mesh > indsys->extra_meshes) {
51     fprintf(stderr, "Internal Error: Bad estimate for extra_meshes\n");
52     fprintf(stderr, "   One solution is to change FILS_PER_MESH to 1\n");
53     exit(1);
54   }
55 
56   minimeshes = mesh;
57 
58   /* this does all the meshes due to filaments within each segment */
59   for(seg = indsys->segment; seg != NULL; seg = seg->next) {
60     for(k = 1; k < seg->num_fils; k++, mesh++) {
61 
62         Mlist[mesh] = make_melement(seg->filaments[k-1].filnumber,
63 				    &seg->filaments[k-1], 1);
64 
65 	Mlist[mesh] = insert_in_list(make_melement(seg->filaments[k].filnumber,
66 						   &seg->filaments[k], -1),
67 				     Mlist[mesh]);
68        /* unimplemented junk
69 	make_unconstrained(&(m_info[mesh]),mesh);
70        */
71       }
72   }
73 
74   /* add all the lists to the groundplane */
75   for(plane = indsys->planes; plane != NULL; plane = plane->next) {
76     if (!is_nonuni_gp(plane))
77       mesh += makeMlist(plane, &(Mlist[mesh]), &(m_info[mesh]),mesh);
78     else
79       mesh += make_nonuni_Mlist(plane, &(Mlist[mesh]));
80   }
81 
82 
83   /* For each tree mesh, pick one mini-mesh to be unconstrained and make it
84      unique (unimplemented)*/
85   /*pick_unconstrained(Mlist, m_info, mesh, indsys->tree_meshes, minimeshes);*/
86 
87 
88   if (mesh <= indsys->num_mesh)
89     indsys->num_mesh = mesh;
90   else {
91     fprintf(stderr, "uh oh, mesh > num_mesh\n");
92     exit(1);
93   }
94 }
95 
96 /* this takes a linked list of segments (path) and makes a row of the */
97 /* mesh matrix out of the filament[0]'s of each segment.  */
make_mesh_from_path(path,mesh,indsys)98 MELEMENT *make_mesh_from_path(path, mesh, indsys)
99 SPATH *path;
100 int mesh;
101 SYS *indsys;
102 {
103   SPATH *selem, *temppath, *telem;
104   MELEMENT *m1, *m2, *m3, *mlist;
105   NODES *plusnode, *node, *plus2, *node0, *node1, *actualnode;
106   int i, sign, sign2;
107   SEGMENT *seg;
108   PSEUDO_SEG *pseg, *pseg2;
109 
110   mlist = NULL;
111   plusnode = find_first_node(path);  /* which node starts the loop */
112   for(selem = path, i = 0; selem != NULL; selem = selem->next, i++) {
113     node0 = getnode(0, selem->seg);  /* get original (not real) nodes */
114     node1 = getnode(1, selem->seg);
115     if (getrealnode(plusnode) == getrealnode(node0))
116       sign = 1;
117     else if (getrealnode(plusnode) == getrealnode(node1))
118       sign = -1;
119     else {
120       fprintf(stderr, "make_mesh_from_path: segments don't connect at node %s\n", plusnode->name);
121       exit(1);
122     }
123 
124     if (selem->seg.type == NORMAL) {
125       seg = (SEGMENT *)selem->seg.segp;
126 
127       m1 = make_melement(seg->filaments[0].filnumber, &seg->filaments[0],
128 			 sign);
129       mlist = insert_in_list(m1, mlist);
130     }
131     else if (selem->seg.type == PSEUDO) {
132       pseg = (PSEUDO_SEG *)selem->seg.segp;
133 
134       if (pseg->type == EXTERNTYPE)
135 	add_to_external(pseg, mesh, sign, indsys);
136       else if (pseg->type == GPTYPE) {
137 	while( is_next_seg_in_gp(selem, plusnode) == TRUE) {
138 	  /* this is an ugly addition to make gp meshes smaller if two segs */
139 	  /* come from the same gp.  It was commented out because of a bug  */
140           /* which hopefully i've fixed, 3/96 */
141 	  selem = selem->next;
142 	  if (sign == 1) {
143 	    plusnode = node1;
144 	    node1 = getothernode(node1, selem->seg);
145 	  }
146 	  else {
147 	    plusnode = node0;
148 	    node0 = getothernode(node0, selem->seg);
149 	  }
150 	  if (indsys->opts->debug == ON)
151 	    printf("Fixing extra long gp mesh in gp %s, mesh %d.\n",
152 		   node0->gp->name, mesh);
153 	}
154 	if (sign == 1) {
155 	  temppath = path_through_gp(node0, node1, node0->gp);
156 	  plus2 = node0;
157 	}
158 	else {
159 	  temppath = path_through_gp(node1, node0, node0->gp);
160 	  plus2 = node1;
161 	}
162 	while(temppath != NULL) {
163 	  telem = temppath;
164 	  seg = (SEGMENT *)telem->seg.segp;
165 	  if (is_nonuni_gp(node0->gp)) {
166 	    /* must compare cell nodes, not actual seg nodes */
167 	    if (plus2->gp_node == seg->node[0]->gp_node) {
168 	      sign2 = 1;
169 	      actualnode = seg->node[0];
170 	    }
171 	    else if (plus2->gp_node == seg->node[1]->gp_node) {
172 	      sign2 = -1;
173 	      actualnode = seg->node[1];
174 	    }
175 	    else {
176 	     fprintf(stderr, "Hey, path_through_gp made nonconnected path!\n");
177 	     exit(1);
178 	    }
179 	  }
180 	  else {
181 	    if (plus2 == seg->node[0])
182 	      sign2 = 1;
183 	    else if (plus2 == seg->node[1])
184 	      sign2 = -1;
185 	    else {
186 	     fprintf(stderr, "Hey, path_through_gp made nonconnected path!\n");
187 	     exit(1);
188 	   }
189 	    actualnode = plus2;
190 	  }
191 	  m1 = make_melement(seg->filaments[0].filnumber, &seg->filaments[0],
192 			     sign2);
193 	  mlist = insert_in_list(m1, mlist);
194 	  plus2 = getothernode(actualnode, telem->seg);
195 	  temppath = temppath->next;
196 /*	  free(telem); */
197 	}
198       }
199       else {
200 	fprintf(stderr, "make_mesh_from_path: unknown pseudo_seg %d\n",
201 		pseg->type);
202 	exit(1);
203       }
204     }
205     else {
206       bad_seg_type("make_mesh_from_path", selem->seg);
207     }
208     plusnode = getothernode(plusnode, selem->seg);
209   }
210 
211   if (mlist == NULL) {
212     fprintf(stderr,
213             "make_mesh_from_path: Possible loop of .external statements which is not allowed!\n");
214     fprintf(stderr,
215             " .external's (possibly equiv'ed nodes) which may make a loop:\n");
216     for(selem = path, i = 0; selem != NULL; selem = selem->next, i++) {
217       node0 = getnode(0, selem->seg);  /* get original (not real) nodes */
218       node1 = getnode(1, selem->seg);
219       fprintf(stderr, "  %s  %s\n",node0->name, node1->name);
220       /* the above could be made more useful by searching through
221 	 the master pseudo_nodes list for pseudo_nodes thatpoint to these */
222     }
223   }
224 
225   return mlist;
226 }
227 
228 /* Check to see if the next segment is also from the same groundplane */
is_next_seg_in_gp(selem,plusnode)229 is_next_seg_in_gp(selem,plusnode)
230 SPATH *selem;
231 NODES *plusnode;
232 {
233   PSEUDO_SEG *pseg2, *pseg1;
234   NODES *othernode;
235 
236   if (selem->next != NULL && selem->next->seg.type == PSEUDO) {
237     pseg1 = (PSEUDO_SEG *)selem->seg.segp;
238     pseg2 = (PSEUDO_SEG *)selem->next->seg.segp;
239     if (pseg2->type == GPTYPE
240 	&& pseg1->node[0]->gp == pseg2->node[0]->gp) {
241       othernode = getothernode(plusnode, selem->seg);
242       if (othernode == pseg2->node[0] || othernode == pseg2->node[1])
243 	return TRUE;
244       else if (plusnode == pseg2->node[0] || plusnode == pseg2->node[1])
245         /* segs could be reversed in the path list.  added 3/96 */
246         return TRUE;
247     }
248 /*
249     else
250       printf("Not an error: Two adjacent gp segs not in same gp %s, %s.\n",
251 	     pseg1->node[0]->gp->name, pseg2->node[0]->gp->name);
252 */
253   }
254   return FALSE;
255 }
256 
257 /* this inserts melem into the linked list beginning with bigmhead. */
258 /* It inserts it to preserve increasing filindex order. */
insert_in_list(melem,bigmhead)259 MELEMENT *insert_in_list(melem, bigmhead)
260 MELEMENT *melem, *bigmhead;
261 {
262   MELEMENT *melem2;
263 
264   if (bigmhead == NULL)
265     return melem;
266   else {
267     /* find where in the list to put melem */
268     melem2 = bigmhead;
269     if (melem2->filindex > melem->filindex) {  /* put at beginning */
270       melem->mnext = melem2;
271       bigmhead = melem;
272     }
273     else {  /* find its place in the middle of the list */
274       while(melem2->mnext != NULL
275 	    && melem2->mnext->filindex < melem->filindex)
276 	melem2 = melem2->mnext;
277       /* insert it in the middle */
278       melem->mnext = melem2->mnext;
279       melem2->mnext = melem;
280     }
281 
282     return bigmhead;
283   }
284 }
285 
getnode(number,seg)286 NODES *getnode(number, seg)
287 int number;
288 seg_ptr seg;
289 {
290   if (seg.type == NORMAL)
291     return ((SEGMENT *)seg.segp)->node[number];
292   else if (seg.type == PSEUDO)
293     return ((PSEUDO_SEG *)seg.segp)->node[number];
294   else
295     bad_seg_type("getnode", seg);
296 }
297 
bad_seg_type(name,seg)298 bad_seg_type(name, seg)
299 char *name;
300 seg_ptr seg;
301 {
302   fprintf(stderr, "%s: bad seg type: %d\n",name, seg.type);
303   exit(1);
304 }
305 
make_melement(filindex,fil,sign)306 MELEMENT *make_melement(filindex, fil, sign)
307 int filindex, sign;
308 FILAMENT *fil;
309 {
310   MELEMENT *melem;
311 
312   melem = (MELEMENT *)MattAlloc(1, sizeof(MELEMENT));
313   melem->filindex = filindex;
314   melem->fil = fil;
315   melem->sign = sign;
316   melem->mnext = NULL;
317 
318   return melem;
319 }
320 
321 /* this keeps track of the meshes which contain the nodes of the */
322 /* .external statement.  This will have a voltage source in them */
323 /* and will need a 1 placed in the RHS corresponding to mesh number 'mesh' */
add_to_external(pseg,mesh,sign,indsys)324 add_to_external(pseg, mesh, sign, indsys)
325 PSEUDO_SEG *pseg;
326 int mesh, sign;
327 SYS *indsys;
328 {
329   EXTERNAL *port;
330   int realsign;
331 
332   port = indsys->externals;
333   while(port != NULL && port->source != pseg)
334     port = port->next;
335 
336   if (port == NULL) {
337     fprintf(stderr, "Hey, supposed external segment isn't in list\n");
338     exit(1);
339   }
340 
341   realsign = -1 * sign;  /* since this will be moved to RHS, change its sign */
342 
343   port->indices = add_to_int_list(make_int_list(mesh, realsign),
344 				  port->indices);
345 
346 }
347 
make_int_list(mesh,sign)348 int_list *make_int_list(mesh, sign)
349 int mesh, sign;
350 {
351   int_list *elem;
352 
353   elem = (int_list *)Gmalloc(sizeof(int_list));
354   elem->index = mesh;
355   elem->sign = sign;
356   elem->next = NULL;
357 
358   return elem;
359 }
360 
add_to_int_list(int_elem,list)361 int_list *add_to_int_list(int_elem, list)
362 int_list *int_elem, *list;
363 {
364   int_elem->next = list;
365   return int_elem;
366 }
367 
368 /* makes the Mlist for the groundplane given a plane and parameters defining */
369 /* the current location of the overall Mlist.                                */
makeMlist(plane,pMlist,pm_info,mstart)370 makeMlist(plane, pMlist, pm_info, mstart)
371 GROUNDPLANE *plane;
372 MELEMENT **pMlist;
373 Minfo *pm_info;
374 int mstart;
375 {
376   MELEMENT *melem;
377   SEGMENT *seg;
378   int counter, i, j, k;
379   int signofelem;
380   int a_hole;
381   SEGMENT ***segs1 = plane->segs1;
382   SEGMENT ***segs2 = plane->segs2;
383 
384   counter = 0;
385 
386   for(i = 0; i < plane->seg2; i++){
387     for(j = 0; j < plane->seg1; j++){
388 
389       if (segs1[j][i] != NULL && segs2[j + 1][i] != NULL
390 	  && segs1[j][i + 1] != NULL && segs2[j][i]!= NULL) {
391 	pMlist[counter] = NULL;
392 
393 	for(k = 0; k < 4; k++){
394 	  switch (k) {
395 	  case 0:
396 	    seg = plane->segs1[j][i];
397 	    signofelem = -1.0;
398 	    break;
399 	  case 1:
400 	    seg = plane->segs2[j + 1][i];
401 	    signofelem = -1.0;
402 	    break;
403 	  case 2:
404 	    seg = plane->segs1[j][i + 1];
405 	    signofelem = 1.0;
406 	    break;
407 	  case 3:
408 	    seg = plane->segs2[j][i];
409 	    signofelem = 1.0;
410 	    break;
411 	  }
412 
413 	  melem = make_melement(seg->filaments[0].filnumber, &seg->filaments[0],
414 				signofelem);
415 	  pMlist[counter] = insert_in_list(melem, pMlist[counter]);
416 
417 	}
418       /* unimplemented junk
419 	make_unconstrained(&(pm_info[counter]), mstart+counter);
420       */
421 	counter++;
422       }
423     }
424   }
425 
426   if(counter > plane->numesh){
427     printf("something wrong with meshes, numesh != counter \n");
428     exit(1);
429   }
430 
431   return counter;
432 
433 }
434 
fill_b(ext,b)435 fill_b(ext, b)
436 EXTERNAL *ext;
437 CX *b;
438 {
439   int_list *elem;
440 
441   for(elem = ext->indices; elem != NULL; elem = elem->next)
442     b[elem->index].real = elem->sign;
443 }
444 
extractYcol(mat,x0,extcol,ext_list)445 extractYcol(mat, x0, extcol, ext_list)
446 CX **mat, *x0;
447 EXTERNAL *extcol, *ext_list;
448 {
449   EXTERNAL *ext;
450   int_list *elem;
451 
452   CX sum, tmp;
453 
454   for(ext = ext_list; ext != NULL; ext = ext->next) {
455     sum = CXZERO;
456     /* for each mesh that contains this voltage source */
457     for(elem = ext->indices; elem != NULL; elem = elem->next) {
458       cx_scalar_mult(tmp, elem->sign, x0[elem->index]);
459       cx_add(sum, sum, tmp);
460     }
461     mat[ext->Yindex][extcol->col_Yindex] = sum;
462   }
463 
464 }
465 
get_a_name(pseg)466 char *get_a_name(pseg)
467 PSEUDO_SEG *pseg;
468 {
469   return pseg->node[0]->name;
470 }
471 
472 /* we wish to find the first node in a path which is the node of
473    the first segment which is not connected to the second segment */
find_first_node(path)474 NODES *find_first_node(path)
475 SPATH *path;
476 {
477   NODES *node0, *node1;
478   int node1_in_middle;
479   int node0_in_middle;
480 
481   node0 = getnode(0, path->seg);
482   node1 = getnode(1, path->seg);
483   if (path->next == NULL)  /* there is no other segment */
484     return node0;
485 
486 #if 1==0
487   the old way
488 
489  replaced for the sake of fixing extra long gp meshes, we must
490  handle a two segment loop more carefully /*
491 
492   if (getrealnode(node0) == getrealnode(getnode(0, path->next->seg))
493       || getrealnode(node0) == getrealnode(getnode(1, path->next->seg)) )
494     /* node0 is connected to the next segment, so start with node 1 */
495     return node1;
496   else if (getrealnode(node1) == getrealnode(getnode(0, path->next->seg))
497       || getrealnode(node1) == getrealnode(getnode(1, path->next->seg)) )
498     /* node0 is connected to the next segment, so start with node 1 */
499     return node0;
500   else {
501     fprintf(stderr, "find_first_node: first seg not connected to second\n");
502     exit(1);
503   }
504 #endif
505 
506   /* is node0 connected to the next segment? */
507   node0_in_middle =
508     (getrealnode(node0) == getrealnode(getnode(0, path->next->seg))
509       || getrealnode(node0) == getrealnode(getnode(1, path->next->seg)) );
510 
511   node1_in_middle =
512     (getrealnode(node1) == getrealnode(getnode(0, path->next->seg))
513       || getrealnode(node1) == getrealnode(getnode(1, path->next->seg)) );
514 
515   /* return the node that isn't connecting the first and second segs */
516   if (node1_in_middle && !node0_in_middle)
517     return node0;
518   else if (node0_in_middle && !node1_in_middle)
519     return node1;
520   else if (node0_in_middle && node1_in_middle) {
521     /* this is a two segment loop, so it doesn't matter which
522        we return.  But if these are two groundplane segments, perhaps
523        this needs to be shortened to one segment and in order to do so
524        we must determine the connectivity based on original, not real, node
525        name */
526     if (node0 == getnode(0, path->next->seg)
527         || node0 == getnode(1, path->next->seg))
528       return node1;
529     else if (node1 == getnode(0, path->next->seg)
530         || node1 == getnode(1, path->next->seg))
531       return node0;
532     else
533       /* it doesn't matter, both are equiv'd */
534       return node0;
535   }
536   else {
537     fprintf(stderr, "find_first_node: first seg not connected to second\n");
538     exit(1);
539   }
540 
541 }
542 
makegrids(indsys,Im,column,freq_num)543 makegrids(indsys, Im, column, freq_num)
544 SYS *indsys;
545 CX *Im;
546 int column;
547 {
548   static CX *Ib = NULL, current;
549   int fils, meshes;
550   static CX **out1 = NULL;
551   static CX **out2 = NULL;
552   static maxdir1 = 0, maxdir2 = 0;
553   int dir1, dir2, num, i, j;
554   MELEMENT *mtemp;
555   GROUNDPLANE *p;
556   FILE *fp, *fpreal, *fpimag, *fpmag;
557   static char *fname, *tempstr;
558   SEGMENT *seg;
559   FILAMENT *fil;
560   double xv, yv, zv,x,y,z, magcur;
561 
562   fils = indsys->num_fils;
563   meshes = indsys->num_mesh;
564 
565   if (Ib == NULL) {
566      Ib = (CX *)MattAlloc(fils, sizeof(CX));
567      fname = malloc(100*sizeof(char));
568      tempstr = malloc(100*sizeof(char));
569    }
570 
571   /* do  Ib = Mtrans*Im */
572   for(i = 0; i < fils; i++) {
573     Ib[i] = CXZERO;
574     for(mtemp = indsys->Mtrans[i]; mtemp != NULL; mtemp = mtemp->mnext) {
575       if (mtemp->sign == 1)
576 	cx_add(Ib[i], Ib[i], Im[mtemp->filindex]);
577       else
578 	cx_sub(Ib[i], Ib[i], Im[mtemp->filindex]);
579     }
580   }
581 
582   printf("saving to Jreal%s.mat, Jimag%s.mat, Jmag%s.mat\n",
583 	 indsys->opts->suffix,
584 	 indsys->opts->suffix,
585 	 indsys->opts->suffix);
586 
587   sprintf(fname, "Jreal%s.mat",indsys->opts->suffix);
588   /* SRW -- this is ascii data */
589   fpreal = fopen(fname,"w");
590   if(fpreal == NULL){
591     printf("couldn't open file %s\n",fname);
592     exit(1);
593   }
594 /*  fprintf(fpreal, "$ DATA=VECTOR\n");*/
595 
596   sprintf(fname, "Jimag%s.mat",indsys->opts->suffix);
597   /* SRW -- this is ascii data */
598   fpimag = fopen(fname,"w");
599   if(fpimag == NULL){
600     printf("couldn't open file %s\n",fname);
601     exit(1);
602   }
603 /*  fprintf(fpimag, "$ DATA=VECTOR\n");*/
604 
605   sprintf(fname, "Jmag%s.mat",indsys->opts->suffix);
606   /* SRW -- this is ascii data */
607   fpmag = fopen(fname,"w");
608   if(fpmag == NULL){
609     printf("couldn't open file %s\n",fname);
610     exit(1);
611   }
612 /*  fprintf(fpmag, "$ DATA=VECTOR\n");*/
613 
614   for(seg = indsys->segment; seg != NULL; seg = seg->next)
615     for(i = 0; i < seg->num_fils; i++) {
616       fil = &(seg->filaments[i]);
617       current = Ib[fil->filnumber];
618       magcur = cx_abs(current);
619       xv = fil->lenvect[XX]/fil->length/fil->area;
620       yv = fil->lenvect[YY]/fil->length/fil->area;
621       zv = fil->lenvect[ZZ]/fil->length/fil->area;
622       x = fil->x[0];
623       y = fil->y[0];
624       z = fil->z[0];
625       fprintf(fpreal, "%lg %lg %lg  %lg %lg %lg\n",x,y,z,
626 	      xv*current.real, yv*current.real, zv*current.real);
627       fprintf(fpimag, "%lg %lg %lg  %lg %lg %lg\n",x,y,z,
628 	      xv*current.imag, yv*current.imag, zv*current.imag);
629       fprintf(fpmag, "%lg %lg %lg  %lg %lg %lg\n",x,y,z,
630 	      xv*magcur, yv*magcur, zv*magcur);
631     }
632 
633   fclose(fpreal);
634   fclose(fpimag);
635   fclose(fpmag);
636 
637   if (indsys->num_planes == 0)
638     return 0;
639 
640   printf("saving to file Grid%s%d_%d...\n",indsys->opts->suffix,
641 	 column+1,freq_num);
642   sprintf(fname, "Grid%s%d_%d.mat",indsys->opts->suffix,column+1,freq_num);
643 
644   /* SRW -- this is binary data */
645   fp = fopen(fname,"wb");
646   if(fp == NULL){
647     printf("couldn't open file %s\n",fname);
648     exit(1);
649   }
650 
651   for(num = 0, p = indsys->planes; p != NULL; p = p->next, num++){
652     if (is_nonuni_gp(p))
653       dump_nonuni_plane_currents(p->nonuni, Ib, fp);
654     else {
655       dir1 = p->seg1 + 1;
656       dir2 = p->seg2 + 1;
657 
658       if (dir1 > maxdir1 || dir2 > maxdir2) {
659 	out1 = (CX **)MatrixAlloc(dir2 + 10, dir1 + 10, sizeof(CX));
660 	out2 = (CX **)MatrixAlloc(dir2 + 10, dir1 + 10, sizeof(CX));
661 	maxdir1 = dir1 + 10;
662 	maxdir2 = dir2 + 10;
663       }
664 
665       for(i = 0; i < dir2; i++)
666 	for(j = 0; j < dir1; j++) {
667 	  /* do direction 1 */
668 	  if(j != dir1 - 1 && p->segs1[j][i] != NULL) {
669 	    out1[i][j] = Ib[p->segs1[j][i]->filaments[0].filnumber];
670 	    if (p->segs1[j][i]->node[0] != p->pnodes[j][i]) {
671 	      printf("You goofed 1\n");
672 	    }
673 	  }
674 	  else
675 	    out1[i][j] = CXZERO;
676 
677 	  /* do direction 2 */
678 	  if (i != dir2 - 1 && p->segs2[j][i] != NULL) {
679 	    out2[i][j] = Ib[p->segs2[j][i]->filaments[0].filnumber];
680 	    if (p->segs2[j][i]->node[0] != p->pnodes[j][i]) {
681 	      printf("You goofed 2\n");
682 	    }
683 	  }
684 	  else
685 	    out2[i][j] = CXZERO;
686 	}
687 
688       printf("saving grid1%s...\n",p->name);
689       strcpy(fname, "grid1");
690       sprintf(tempstr, "%s",p->name);
691       strcat(fname, tempstr);
692 
693       savecmplx(fp, fname, out1, dir2, dir1);
694 
695       printf("saving grid2%s...\n",p->name);
696       strcpy(fname, "grid2");
697       sprintf(tempstr, "%s",p->name);
698       strcat(fname,tempstr);
699 
700       savecmplx(fp, fname, out2, dir2, dir1);
701     }
702   }
703   fclose(fp);
704 }
705   /*------------------------------------------------------------------------*/
706 
707 
708 
709 #if 1==0
710 
711 The following is code that was not implemented and never used and is now
712   obsolete.
713 
714 /* this takes a linked list of segments (path) and makes many rows of the */
715 /* mesh matrix out of the filament[0]'s of each segment.  */
make_many_meshes_from_path(path,Mlist,m_info,mstart,indsys)716 make_many_meshes_from_path(path, Mlist, m_info, mstart, indsys)
717 SPATH *path;
718 MELEMENT **Mlist;
719 Minfo *m_info;
720 int mstart;  /* the mesh index at which to start creating meshes. */
721 SYS *indsys;
722 {
723   SPATH *selem, *temppath, *telem, *minipath;
724   MELEMENT *m1, *m2, *m3, *mlist;
725   NODES *plusnode, *node, *plus2, *node0, *node1;
726   int i, sign, sign2;
727   SEGMENT *seg;
728   PSEUDO_SEG *pseg, *pseg2;
729   int mesh, seg_count;
730   int physically_connected;
731   PSEUDO_SEG *extern_seg;
732   int extern_count, extern_sign;
733 
734   mlist = NULL;
735   mesh = 0;
736   minipath = NULL;
737   seg_count = 0;
738   extern_count = 0;
739 
740   plusnode = find_first_node(path);  /* which node starts the loop */
741   for(selem = path, i = 0; selem != NULL; selem = selem->next, i++) {
742     node0 = getnode(0, selem->seg);
743     node1 = getnode(1, selem->seg);
744     if (getrealnode(plusnode) == getrealnode(node0))
745       sign = 1;
746     else if (getrealnode(plusnode) == getrealnode(node1))
747       sign = -1;
748     else {
749       fprintf(stderr, "make_mesh_from_path: segments don't connect at node %s\n", plusnode->name);
750       exit(1);
751     }
752 
753     if (selem->seg.type == NORMAL) {
754       physically_connected = seg_count != 0 && (sign==1 && plusnode == node0
755 	                     || sign==-1 && plusnode==node1);
756       if (physically_connected) {
757 	minipath = add_seg_to_list(selem->seg, minipath);
758 	seg_count++;
759       }
760       if (!physically_connected || seg_count == FILS_PER_MESH) {
761 	Mlist[mstart + mesh] = make_mesh_from_path(minipath, mstart+mesh,
762 						   indsys);
763 	mesh++;
764 	reset_vars(&seg_count, &minipath);
765       }
766     }
767     else if (selem->seg.type == PSEUDO) {
768       pseg = (PSEUDO_SEG *)selem->seg.segp;
769 
770       if (pseg->type == EXTERNTYPE) {
771 	extern_count++;
772 	extern_seg = pseg;
773 	extern_sign = sign;
774 /*	add_to_external(pseg, mesh, sign, indsys); */
775       }
776       else if (pseg->type == GPTYPE) {
777 	/* flush any mesh which isn't finished yet */
778 	if (seg_count != 0) {
779 	  Mlist[mstart + mesh] = make_mesh_from_path(minipath, mstart+mesh,
780 						     indsys);
781 	  mesh++;
782 	  reset_vars(&seg_count, &minipath);
783 	}
784 	while( is_next_seg_in_gp(selem) == TRUE && 1==0) {
785 	  /* this is an ugly addition to make gp meshes smaller if two segs */
786 	  /* come from the same gp */
787 	  selem = selem->next;
788 	  if (sign == 1) {
789 	    plusnode = node1;
790 	    node1 = getothernode(node1, selem->seg);
791 	  }
792 	  else {
793 	    plusnode = node0;
794 	    node0 = getothernode(node0, selem->seg);
795 	  }
796 	  if (indsys->opts->debug == ON)
797 	    printf("Fixing extra long gp mesh in gp %s, mesh %d.\n",
798 		   node0->gp->name, mesh);
799 	}
800 	if (sign == 1) {
801 	  temppath = path_through_gp(node0, node1, node0->gp);
802 	  plus2 = node0;
803 	}
804 	else {
805 	  temppath = path_through_gp(node1, node0, node0->gp);
806 	  plus2 = node1;
807 	}
808 	while(temppath != NULL) {
809 	  telem = temppath;
810 	  seg = (SEGMENT *)telem->seg.segp;
811 	  if (plus2 == seg->node[0])
812 	    sign2 = 1;
813 	  else if (plus2 == seg->node[1])
814 	    sign2 = -1;
815 	  else {
816 	    fprintf(stderr, "Hey, path_through_gp made nonconnected path!\n");
817 	    exit(1);
818 	  }
819 	  minipath = add_seg_to_list(selem->seg, minipath);
820 	  seg_count++;
821 	  if (seg_count == FILS_PER_MESH) {
822 	    Mlist[mstart + mesh] = make_mesh_from_path(minipath, mstart+mesh,
823 						       indsys);
824 	    mesh++;
825 	    reset_vars(&seg_count, &minipath);
826 	  }
827 
828 	  plus2 = getothernode(plus2, telem->seg);
829 	  temppath = temppath->next;
830 	}
831       }
832       else {
833 	fprintf(stderr, "make_mesh_from_path: unknown pseudo_seg %d\n",
834 		pseg->type);
835 	exit(1);
836       }
837     }
838     else {
839       bad_seg_type("make_mesh_from_path", selem->seg);
840     }
841     plusnode = getothernode(plusnode, selem->seg);
842   }
843 
844   if (seg_count == FILS_PER_MESH) {
845     Mlist[mstart + mesh] = make_mesh_from_path(minipath, mstart+mesh,
846 					       indsys);
847     mesh++;
848     reset_vars(&seg_count, &minipath);
849   }
850 
851   if (extern_count > 0) {
852     if (extern_count == 1)
853       add_to_external(extern_seg, mstart, extern_sign, indsys);
854     else {
855       fprintf(stderr,"Internal Err: More than one voltage source in a mesh\n");
856       exit(1);
857     }
858   }
859 
860 #if 1==0
861   /* only the first mini mesh is unconstrained */
862   make_m_info(&(m_info[0]), UNCONSTRAINED, mstart, mstart, mstart, mesh);
863 
864   /* make the second one constrained to the first */
865   if (mesh > 1) {
866     make_m_info(&(m_info[1]), CONSTRAINED, mstart+1, mstart, mstart, mesh);
867   }
868 
869   /* The first constrained mesh above will have a current for these */
870   /* i.e., they are constrained to mstart+1 */
871 #endif
872 
873   for(i = 0; i < mesh; i++) {
874     make_m_info(&(m_info[i]), CONSTRAINED, mstart+i, -1, mstart,mesh, 0);
875   }
876 
877   if (mesh == 0) {
878     fprintf(stderr, "make_many_meshes: No meshes made!\n");
879     exit(1);
880   }
881 
882   return mesh;
883 }
884 
reset_vars(seg_count,minipath)885 reset_vars(seg_count, minipath)
886 int *seg_count;
887 SPATH **minipath;
888 {
889   *seg_count = 0;
890   free_spath(*minipath);
891   *minipath = NULL;
892 }
893 
make_unconstrained(pm_info,mesh)894 make_unconstrained(pm_info, mesh)
895 Minfo *pm_info;
896 int mesh;
897 {
898   make_m_info(pm_info, UNCONSTRAINED, mesh, -1, -1, -1, -1);
899 }
900 
make_m_info(pm_info,type,mesh_num,constr_mesh,first,num_meshes,other_mesh)901 make_m_info(pm_info, type, mesh_num, constr_mesh, first, num_meshes,
902 	    other_mesh)
903 Minfo *pm_info;
904 int type, mesh_num, constr_mesh, first, num_meshes, other_mesh;
905 {
906   pm_info->type = type;
907   pm_info->mesh_num = mesh_num;
908   pm_info->constraining_mesh = constr_mesh;
909   pm_info->first = first;
910   pm_info->num_meshes = num_meshes;
911   pm_info->other_mesh = other_mesh;
912 }
913 
pick_unconstrained(Mlist,m_info,total_meshes,big_meshes,num_meshes)914 pick_unconstrained(Mlist, m_info, total_meshes, big_meshes, num_meshes)
915 MELEMENT **Mlist;
916 Minfo *m_info;
917 int num_meshes;
918 int big_meshes;
919 int total_meshes;
920 {
921   Minfo **m_undone, *m_one;
922   int i, j, quit;
923   int counter;
924   int last_undone, undone;
925   int first /*, num_meshes*/;
926 
927   counter = 0;
928   m_undone = (Minfo **)Gmalloc(big_meshes*sizeof(Minfo *));
929 
930   /* This goes through all the big meshes and picks one representative mesh*/
931   for(i = 0; i < num_mesh; i++) {
932     m_undone[counter++] = &(m_info[i]);
933     i += m_info[i].num_meshes;
934   }
935 
936   if (counter != big_meshes) {
937     fprintf(stderr, "Error getting representative meshes\n");
938     exit(1);
939   }
940 
941   undone = big_meshes;
942   last_undone = undone + 1;
943 
944   while(undone < last_undone) {
945     last_undone = undone;
946 
947     /* counts duplicates and saves them in m_undone[i]->other_mesh */
948     count_duplicates(m_undone, undone, Mlist, m_info);
949 
950     for(i = 0; i < undone; i++) {
951       first = m_undone[i]->first;
952       num_meshes = m_undone[i]->num_meshes;
953       quit = FALSE;
954       for(j = first; j < first + num_meshes && quit == FALSE; j++) {
955 	if (!is_duplicated(m_info[j])) {
956 	  /* This mesh is unique among minimeshes*/
957 	  if (is_globally_unique(m_info[j], num_mesh, Mlist, total_meshes)) {
958 	    quit = TRUE;
959 
960 	    choose_this_mesh(m_undone[i], j, m_info);
961 	  }
962 	}
963       }
964     }
965 
966     undone = get_undone(m_undone, undone);
967   }
968 
969   /* sort in order of increasing number of minimeshes */
970   /* This is a rock sort.  Biggest element falls to the bottom */
971   for(i = 0; i < undone - 1; i++)
972     for(j = 1; j < undone - i; j++)
973       if (m_undone[j-1]->num_meshes > m_undone[j]->num_meshes) {
974 	m_one = m_undone[j-1];
975 	m_undone[j-1] = m_undone[j];
976 	m_undone[j] = m_one;
977       }
978 
979   /* Go through all the undone meshes and pick the first available mesh */
980   for(i = 0; i < undone; i++) {
981     first = m_undone[i]->first;
982     num_meshes = m_undone[i]->num_meshes;
983     quit = FALSE;
984     for(j = first; j < first + num_meshes && quit == FALSE; j++) {
985       if (is_locally_unique(m_undone, j, Mlist)) {
986 	/* This mesh is unique among other selected */
987 	if (is_globally_unique(m_info[j], &(Mlist[num_mesh]),
988 			       total_meshes - num_mesh)) {
989 	  quit = TRUE;
990 
991 	  choose_this_mesh(m_undone[i], j, m_info);
992 	}
993       }
994     }
995     if (quit == FALSE) {
996       fprintf(stderr, "screwed up!\n");
997       exit(1);
998     }
999   }
1000 
1001 }
1002 
count_duplicates(m_undone,undone,Mlist,m_info)1003 count_duplicates(m_undone, undone, Mlist, m_info)
1004 Minfo **m_undone, *m_undone;
1005 int undone;
1006 MELEMENT **Mlist;
1007 {
1008   int i,j,k,m;
1009   Minfo *m_one;
1010   int first_s, num_meshes_s, first_t, num_meshes_t;
1011 
1012   for(i = 0; i < undone; i++) {
1013     first_s = m_undone[i]->first;
1014     num_meshes_s = m_undone[i]->num_meshes;
1015     for(j = first_s; j < first_s + num_meshes_s; j++) {
1016       for(k = 0; k < undone; k++) {
1017 	first_t = m_undone[i]->first;
1018 	num_meshes_t = m_undone[i]->num_meshes;
1019 	for(m = first_t; m < first_t + num_meshes_t; m++)
1020 	  if(mesh_comp(Mlist[j], Mlist[m]) == TRUE) {
1021 	    m_info[j].other_mesh += 1;
1022 	    if (j != m)
1023 	      m_info[m].other_mesh += 1;
1024 	  }
1025       }
1026     }
1027     if (m_info[j].other_mesh == 0) {
1028       fprintf(stderr, "Huh?  mesh isn't identical to itself?\n");
1029       exit(1);
1030     }
1031   }
1032 }
1033 
mesh_comp(m1,m2)1034 mesh_comp(m1, m2)
1035 MELEMENT *m1, *m2;
1036 {
1037   int same;
1038 
1039   same = TRUE;
1040   while(m1 != NULL && m2 != NULL && same == TRUE) {
1041     if (m1->filindex != m2->filindex)
1042       same = FALSE;
1043     else {
1044       m1 = m1->next;
1045       m2 = m2->next;
1046     }
1047 
1048 
1049   if (m1 != NULL || m2 != NULL)
1050     same = FALSE;
1051 
1052   return same;
1053 }
1054 
1055 is_duplicated(m_one)
1056 Minfo m_one;
1057 {
1058   return (m_one.other_mesh != 1);
1059 }
1060 
1061 is_globally_unique(m_one, minimeshes, Mlist, num_mesh)
1062 Minfo m_one;
1063 MELEMENT **Mlist;
1064 int num_mesh, minimeshes;
1065 {
1066   int unique = TRUE;
1067   int i,j;
1068 
1069   for(i = minimeshes; i < num_mesh && unique == TRUE; i++)
1070     if (mesh_comp(Mlist[m_one.mesh_num], Mlist[i]) == TRUE)
1071       unique = FALSE;
1072 
1073   return unique;
1074 }
1075 
1076 choose_this_mesh(m_begin, constraining_mesh, m_info)
1077 Minfo *m_begin, *m_info;
1078 int constraining_mesh;
1079 {
1080   int other_mesh = -1;
1081   int num_dups = 1000000;
1082 
1083   m_info[constraining_mesh] = UNCONSTRAINED;
1084 
1085   /* find a good other_mesh */
1086   for(i = m_begin->first; i < m_begin->first + m_begin->num_meshes; i++)
1087     if (i != constraining_mesh)
1088       if (m_info[i].other_mesh < num_dups) {
1089 	other_mesh = i;
1090 	num_dups = m_info[i].other_mesh;
1091       }
1092 
1093   if (m_begin->num_meshes != 1) {
1094     if (other_mesh == -1) {
1095       fprintf(stderr, "Huh?  other_mesh == -1?\n");
1096       exit(1);
1097     }
1098    for(i = m_begin->first; i < m_begin->first + m_begin->num_meshes; i++) {
1099      m_info[i].constraining_mesh = constraining_mesh;
1100      m_info[i].other_mesh = other_mesh;
1101    }
1102   }
1103 }
1104 
1105 /* get all the remaining undone big meshes based on constraing_mesh still -1*/
1106 get_undone(m_undone, undone)
1107 Minfo **m_undone;
1108 int undone;
1109 {
1110   int i, new_undone;
1111 
1112   new_undone = 0;
1113   for(i = 0; i < undone; i++)
1114     if (m_undone[i]->constraining_mesh == -1)
1115       m_undone[new_undone++] = m_undone[i];
1116 
1117   return new_undone;
1118 }
1119 
1120 is_locally_unique(m_undone, mini_mesh, Mlist)
1121 Minfo **m_undone;
1122 int mini_mesh;
1123 MELEMENT **Mlist;
1124 {
1125   int i, k;
1126   int unique = TRUE;
1127 
1128   for(i = 0; i < j && unique == TRUE; i++)
1129     if (mesh_comp(Mlist[j], Mlist[m_undone[i]->constraining_mesh]) == TRUE)
1130       unique = FALSE;
1131 
1132   return unique;
1133 }
1134 
1135 #endif
1136 
1137