├── doc ├── FastHenry_User_Guide.pdf └── FastHenry_nonuniform_gndplane_manual.pdf ├── .vscode └── settings.json ├── .gitignore ├── Makefile ├── src └── fasthenry │ ├── sparse │ ├── MtrxError.h │ ├── MtrxExpt.h │ ├── MAKE.COM │ ├── doc │ │ ├── Makefile │ │ ├── advert.ms │ │ └── install.ms │ ├── Makefile~ │ ├── Makefile.default │ ├── Makefile.x64 │ ├── Makefile │ ├── spRevision │ └── spSMP.c │ ├── Makefile.sysV │ ├── Makefile.default │ ├── Makefile.x64 │ ├── Makefile.solaris │ ├── Makefile.dec │ ├── Makefile.sgi │ ├── Makefile.alpha │ ├── cmplx.h │ ├── default_opts.c │ ├── resusage.h │ ├── patran.h │ ├── calcp.c │ ├── Makefile │ ├── capsolve.c │ ├── cx_ludecomp.c │ ├── makeMakefile.c │ ├── mulGlobal.c │ ├── bigmeshPre_direct.c │ ├── savemat_mod.c │ ├── Prec_cost.c │ ├── regurgitate.c │ ├── deg_mutual.c │ ├── BreakupSeg.c │ ├── mulDo.c │ ├── SetupComputePsi.c │ ├── gp.h │ ├── mulStruct.h │ ├── hole.c │ ├── uglieralloc.c │ ├── direct.c │ ├── SetupMulti.c │ └── writefastcap.c ├── examples ├── tree_sample.hier ├── rom_check_con7_r20.ckt ├── plane.in ├── make_nonuniform.c └── trace.test.release ├── config ├── README.md ├── bin └── plotfastH.m └── README.mit /doc/FastHenry_User_Guide.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samerps/FastHenry2-Sam/HEAD/doc/FastHenry_User_Guide.pdf -------------------------------------------------------------------------------- /doc/FastHenry_nonuniform_gndplane_manual.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samerps/FastHenry2-Sam/HEAD/doc/FastHenry_nonuniform_gndplane_manual.pdf -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "mulglobal.h": "c", 4 | "time.h": "c", 5 | "stdio.h": "c" 6 | } 7 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.inp 3 | *.mat 4 | *.a 5 | bin/fasthenry.exe 6 | bin/Zc.csv 7 | *.obj 8 | bin/fasthenry 9 | *.csv 10 | *.DS_Store 11 | bin/Jcurrents.bin 12 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Master makefile for fastcap and related programs and documentation 2 | 3 | SRC = src 4 | FASTH = $(SRC)/fasthenry 5 | 6 | default: 7 | @echo Specify what to make: 8 | @echo " fasthenry - inductance calculation program" 9 | @echo " clean - remove object files" 10 | 11 | fasthenry: 12 | cd $(FASTH) ; $(MAKE) fasthenry 13 | 14 | 15 | clean: 16 | cd $(FASTH) ; $(MAKE) clean 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/fasthenry/sparse/MtrxError.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ERROR DEFINITIONS for the sparse matrix routines. 3 | * 4 | * Author: Advising professor: 5 | * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli 6 | * UC Berkeley 7 | * 8 | * This file exists solely to make Sparse1.3 upward compatible 9 | * from Sparse1.2. Use of this file is not suggested for use in new 10 | * software. 11 | */ 12 | 13 | #include "spMatrix.h" 14 | -------------------------------------------------------------------------------- /src/fasthenry/sparse/MtrxExpt.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * ERROR DEFINITIONS for the sparse matrix routines. 4 | * 5 | * Author: Advising professor: 6 | * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli 7 | * UC Berkeley 8 | * 9 | * This file exists solely to make Sparse1.3 upward compatible 10 | * from Sparse1.2. Use of this file is not suggested for use in new 11 | * software. 12 | */ 13 | 14 | #include "spMatrix.h" 15 | -------------------------------------------------------------------------------- /src/fasthenry/sparse/MAKE.COM: -------------------------------------------------------------------------------- 1 | $ def lnk$library sys$library:vaxcrtl.olb 2 | $ cc spAllocate.c 3 | $ cc spBuild.c 4 | $ cc spCompat.c 5 | $ cc spFactor.c 6 | $ cc spFortran.c 7 | $ cc spOutput.c 8 | $ cc spSolve.c 9 | $ cc spTest.c 10 | $ cc spUtils.c 11 | $ library/create/object sparse.olb - 12 | spAllocate, - 13 | spBuild, - 14 | spCompat, - 15 | spFactor, - 16 | spFortran, - 17 | spOutput, - 18 | spSolve, - 19 | spUtils 20 | $ link/exe=sparse spTest.obj, sparse.olb/library 21 | $ sparse :== $$disk2:[kundert.sparse]sparse.exe 22 | -------------------------------------------------------------------------------- /src/fasthenry/sparse/doc/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sparse documentation 2 | # 3 | 4 | PRINTER = -Pprado 5 | # PRINTER = -Plps40 6 | 7 | default : usersguide 8 | all : usersguide install advert 9 | 10 | usersguide : spDoc.ms 11 | tbl spDoc.ms | eqn | ptroff -ms $(PRINTER) 12 | 13 | install : install.ms 14 | ptroff -ms $(PRINTER) install.ms 15 | 16 | advert : advert.ms 17 | tbl advert.ms | ptroff -ms $(PRINTER) 18 | 19 | all-lpr : usersguide.lpr install.lpr 20 | 21 | usersguide.lpr : spDoc 22 | spDoc : spDoc.ms 23 | tbl spDoc.ms | neqn | nroff -ms | colcrt - > spDoc 24 | 25 | install.lpr : install.ms 26 | nroff -ms install.ms | colcrt - > install.lpr 27 | 28 | -------------------------------------------------------------------------------- /examples/tree_sample.hier: -------------------------------------------------------------------------------- 1 | 43 2 | 1 B EW 2 3 3 | 2 B EW 4 5 4 | 3 B EW 6 7 5 | 4 B NS 8 9 6 | 5 B NS 10 11 7 | 6 B NS 12 13 8 | 7 B NS 14 15 9 | 8 NONE 10 | 9 B NS 16 17 11 | 10 NONE 12 | 11 B NS 18 19 13 | 12 NONE 14 | 13 B NS 20 21 15 | 14 NONE 16 | 15 B NS 22 23 17 | 16 NONE 18 | 17 NONE 19 | 18 B NS 24 25 20 | 19 NONE 21 | 20 B EW 26 27 22 | 21 NONE 23 | 22 NONE 24 | 23 NONE 25 | 24 B EW 28 29 26 | 25 B EW 30 31 27 | 26 B NS 32 33 28 | 27 B NS 34 35 29 | 28 NONE 30 | 29 NONE 31 | 30 NONE 32 | 31 B EW 36 37 33 | 32 NONE 34 | 33 B NS 38 39 35 | 34 NONE 36 | 35 NONE 37 | 36 B NS 40 41 38 | 37 B NS 42 43 39 | 38 NONE 40 | 39 NONE 41 | 40 NONE 42 | 41 NONE 43 | 42 NONE 44 | 43 NONE -------------------------------------------------------------------------------- /examples/rom_check_con7_r20.ckt: -------------------------------------------------------------------------------- 1 | Simple ROM example. Two inductors with mutual inductance connected in series. 2 | 3 | * ports are p0 m0 p1 m1... 4 | .include equiv_circuitROM_pin_con7_r20.spice 5 | 6 | * and instance of the state space mode 7 | Xstate p0 m0 p1 m1 p2 m2 p3 m3 p4 m4 p5 m5 p6 m6 ROMequiv_pin_con7_r20 8 | 9 | * connect m0 to ground 10 | vgnd0 m0 0 11 | vgnd1 m1 0 12 | vgnd2 m2 0 13 | vgnd3 m3 0 14 | vgnd4 m4 0 15 | vgnd5 m5 0 16 | vgnd6 m6 0 17 | 18 | isrc0 0 p0 ac 1 19 | isrc1 0 p1 ac 0 20 | isrc2 0 p2 ac 0 21 | isrc3 0 p3 ac 0 22 | isrc4 0 p4 ac 0 23 | isrc5 0 p5 ac 0 24 | isrc6 0 p6 ac 0 25 | 26 | *.tran 1ns 2us UIC 27 | .ac dec 5 1 1e12 28 | .options method=gear 29 | .print ac v(p0) v(p1) v(p2) v(p3) v(p4) v(p5) v(p6) 30 | 31 | 32 | -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if test $1 4 | then 5 | name=$1 6 | else 7 | name="default" 8 | fi 9 | 10 | if test "$name" != "default" -a "$name" != "alpha" -a "$name" != "dec" -a "$name" != "sgi" -a "$name" != "sysV" -a "$name" != "solaris" -a "$name" != "x64" 11 | then 12 | echo config: Unknown type: $2. Choose one of: default, alpha, dec, sgi, sysV, solaris, x64 13 | else 14 | /bin/cp src/fasthenry/Makefile.$name src/fasthenry/Makefile 15 | /bin/cp src/zbuf/Makefile.$name src/zbuf/Makefile 16 | 17 | if test "$name" == "x64" 18 | then 19 | /bin/cp src/fasthenry/sparse/Makefile.$name src/fasthenry/sparse/Makefile 20 | /bin/cp src/misc/Makefile.$name src/misc/Makefile 21 | else 22 | /bin/cp src/fasthenry/sparse/Makefile.default src/fasthenry/sparse/Makefile 23 | /bin/cp src/misc/Makefile.default src/misc/Makefile 24 | fi 25 | fi 26 | 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FastHenry 2 | 3 | This project is a fork of the repo by [edilorean](https://github.com/ediloren/FastHenry2). The source code has been modified, and some Linux dependent references have been removed such as those related to time calculations. This allows the code to be compiled on Windows using MSYS 4 | 5 | FastHenry is the premium inductance solver originally developed at M.I.T. on Unix platform. A de-facto golden reference standard, FastHenry extracts the inductances and resistances of any arbitrary 3D conductive geometry by solving the Maxwell equations in quasi-static regime. 6 | 7 | ## Compile Instructions - Windows 8 | 9 | 1. Clone repo 10 | 1. Download [MSYS](https://www.msys2.org/) and follow istallation instructions to install the mingw-w64 GCC tools. 11 | 1. Install [Make](https://packages.msys2.org/packages/make) package 12 | 1. Restart MSYS terminal 13 | 1. Navigate to cloned folder 14 | 1. Run command `make fasthenry` 15 | 1. If compiled successfully, an exe file will be created in the bin folder 16 | 1. optional: run `make clean` to clean project directory and remove object files. 17 | -------------------------------------------------------------------------------- /src/fasthenry/Makefile.sysV: -------------------------------------------------------------------------------- 1 | CFLAGS = -O -DFIVE 2 | 3 | SHELL = /bin/sh 4 | RM = /bin/rm 5 | BIN = ../../bin 6 | 7 | SPLIB = sparse/sparse.a 8 | 9 | OBJS = induct.o gmres.o savemat_mod.o readGeom.o joelself.o writefastcap.o \ 10 | SetupMulti.o calcp.o SetupComputePsi.o mulSetup.o BreakupSeg.o \ 11 | Precond.o addgroundplane.o findpaths.o fillM.o cx_ludecomp.o \ 12 | parse_command_line.o default_opts.o Prec_cost.o hole.o \ 13 | dist_betw_fils.o mutual.o newPrecond.o deg_mutual.o \ 14 | barnoldi.o regurgitate.o 15 | 16 | MOBJS = mulGlobal.o mulDo.o mulMulti.o mulLocal.o mulMats.o direct.o \ 17 | uglieralloc.o capsolve.o 18 | 19 | NONUNIOBJS = find_nonuni_path.o read_tree.o contact.o 20 | 21 | HEADER = induct.h cmplx.h resusage.h 22 | MULHEAD = mulStruct.h mulGlobal.h patran.h resusage.h 23 | NONUNIHEAD = gp.h 24 | 25 | fasthenry: $(OBJS) $(MOBJS) $(NONUNIOBJS) $(SPLIB) 26 | $(CC) -o fasthenry $(CFLAGS) $(OBJS) $(MOBJS) $(NONUNIOBJS) $(SPLIB) -lm 27 | mv fasthenry $(BIN)/fasthenry 28 | 29 | $(SPLIB): 30 | cd sparse; make 31 | 32 | clean: 33 | $(RM) -f *.o 34 | cd sparse; make clean 35 | 36 | $(OBJS): $(HEADER) $(MULHEAD) 37 | 38 | $(MOBJS): $(MULHEAD) 39 | 40 | $(NONUNIOBJS): $(HEADER) $(MULHEAD) $(NONUNIHEAD) 41 | -------------------------------------------------------------------------------- /src/fasthenry/Makefile.default: -------------------------------------------------------------------------------- 1 | CFLAGS = -O -DFOUR 2 | 3 | SHELL = /bin/sh 4 | RM = /bin/rm 5 | BIN = ../../bin 6 | 7 | SPLIB = sparse/sparse.a 8 | 9 | OBJS = induct.o gmres.o savemat_mod.o readGeom.o joelself.o writefastcap.o \ 10 | SetupMulti.o calcp.o SetupComputePsi.o mulSetup.o BreakupSeg.o \ 11 | Precond.o addgroundplane.o findpaths.o fillM.o cx_ludecomp.o \ 12 | parse_command_line.o default_opts.o Prec_cost.o hole.o \ 13 | dist_betw_fils.o mutual.o newPrecond.o deg_mutual.o \ 14 | barnoldi.o regurgitate.o 15 | 16 | MOBJS = mulGlobal.o mulDo.o mulMulti.o mulLocal.o mulMats.o direct.o \ 17 | uglieralloc.o capsolve.o 18 | 19 | NONUNIOBJS = find_nonuni_path.o read_tree.o contact.o 20 | 21 | HEADER = induct.h cmplx.h resusage.h 22 | MULHEAD = mulStruct.h mulGlobal.h patran.h resusage.h 23 | NONUNIHEAD = gp.h 24 | 25 | fasthenry: $(OBJS) $(MOBJS) $(NONUNIOBJS) $(SPLIB) 26 | $(CC) -o fasthenry $(CFLAGS) $(OBJS) $(MOBJS) $(NONUNIOBJS) $(SPLIB) -lm 27 | mv fasthenry $(BIN)/fasthenry 28 | 29 | $(SPLIB): 30 | cd sparse; make 31 | 32 | clean: 33 | $(RM) -f *.o 34 | cd sparse; make clean 35 | 36 | $(OBJS): $(HEADER) $(MULHEAD) 37 | 38 | $(MOBJS): $(MULHEAD) 39 | 40 | $(NONUNIOBJS): $(HEADER) $(MULHEAD) $(NONUNIHEAD) 41 | -------------------------------------------------------------------------------- /src/fasthenry/Makefile.x64: -------------------------------------------------------------------------------- 1 | CFLAGS = -O -DFOUR -m64 2 | 3 | SHELL = /bin/sh 4 | RM = /bin/rm 5 | BIN = ../../bin 6 | 7 | SPLIB = sparse/sparse.a 8 | 9 | OBJS = induct.o gmres.o savemat_mod.o readGeom.o joelself.o writefastcap.o \ 10 | SetupMulti.o calcp.o SetupComputePsi.o mulSetup.o BreakupSeg.o \ 11 | Precond.o addgroundplane.o findpaths.o fillM.o cx_ludecomp.o \ 12 | parse_command_line.o default_opts.o Prec_cost.o hole.o \ 13 | dist_betw_fils.o mutual.o newPrecond.o deg_mutual.o \ 14 | barnoldi.o regurgitate.o 15 | 16 | MOBJS = mulGlobal.o mulDo.o mulMulti.o mulLocal.o mulMats.o direct.o \ 17 | uglieralloc.o capsolve.o 18 | 19 | NONUNIOBJS = find_nonuni_path.o read_tree.o contact.o 20 | 21 | HEADER = induct.h cmplx.h resusage.h 22 | MULHEAD = mulStruct.h mulGlobal.h patran.h resusage.h 23 | NONUNIHEAD = gp.h 24 | 25 | fasthenry: $(OBJS) $(MOBJS) $(NONUNIOBJS) $(SPLIB) 26 | $(CC) -o fasthenry $(CFLAGS) $(OBJS) $(MOBJS) $(NONUNIOBJS) $(SPLIB) -lm 27 | mv fasthenry $(BIN)/fasthenry 28 | 29 | $(SPLIB): 30 | cd sparse; make 31 | 32 | clean: 33 | $(RM) -f *.o 34 | cd sparse; make clean 35 | 36 | $(OBJS): $(HEADER) $(MULHEAD) 37 | 38 | $(MOBJS): $(MULHEAD) 39 | 40 | $(NONUNIOBJS): $(HEADER) $(MULHEAD) $(NONUNIHEAD) 41 | -------------------------------------------------------------------------------- /src/fasthenry/Makefile.solaris: -------------------------------------------------------------------------------- 1 | CFLAGS = -O -DFIVE -DSOLARIS 2 | 3 | SHELL = /bin/sh 4 | RM = /bin/rm 5 | BIN = ../../bin 6 | 7 | SPLIB = sparse/sparse.a 8 | 9 | OBJS = induct.o gmres.o savemat_mod.o readGeom.o joelself.o writefastcap.o \ 10 | SetupMulti.o calcp.o SetupComputePsi.o mulSetup.o BreakupSeg.o \ 11 | Precond.o addgroundplane.o findpaths.o fillM.o cx_ludecomp.o \ 12 | parse_command_line.o default_opts.o Prec_cost.o hole.o \ 13 | dist_betw_fils.o mutual.o newPrecond.o deg_mutual.o \ 14 | barnoldi.o regurgitate.o 15 | 16 | MOBJS = mulGlobal.o mulDo.o mulMulti.o mulLocal.o mulMats.o direct.o \ 17 | uglieralloc.o capsolve.o 18 | 19 | NONUNIOBJS = find_nonuni_path.o read_tree.o contact.o 20 | 21 | HEADER = induct.h cmplx.h resusage.h 22 | MULHEAD = mulStruct.h mulGlobal.h patran.h resusage.h 23 | NONUNIHEAD = gp.h 24 | 25 | fasthenry: $(OBJS) $(MOBJS) $(NONUNIOBJS) $(SPLIB) 26 | $(CC) -o fasthenry $(CFLAGS) $(OBJS) $(MOBJS) $(NONUNIOBJS) $(SPLIB) -lm 27 | mv fasthenry $(BIN)/fasthenry 28 | 29 | $(SPLIB): 30 | cd sparse; make 31 | 32 | clean: 33 | $(RM) -f *.o 34 | cd sparse; make clean 35 | 36 | $(OBJS): $(HEADER) $(MULHEAD) 37 | 38 | $(MOBJS): $(MULHEAD) 39 | 40 | $(NONUNIOBJS): $(HEADER) $(MULHEAD) $(NONUNIHEAD) 41 | -------------------------------------------------------------------------------- /src/fasthenry/Makefile.dec: -------------------------------------------------------------------------------- 1 | CFLAGS = -O -DFOUR -DDEC -Olimit 2000 2 | 3 | SHELL = /bin/sh 4 | RM = /bin/rm 5 | BIN = ../../bin 6 | 7 | SPLIB = sparse/sparse.a 8 | 9 | OBJS = induct.o gmres.o savemat_mod.o readGeom.o joelself.o writefastcap.o \ 10 | SetupMulti.o calcp.o SetupComputePsi.o mulSetup.o BreakupSeg.o \ 11 | Precond.o addgroundplane.o findpaths.o fillM.o cx_ludecomp.o \ 12 | parse_command_line.o default_opts.o Prec_cost.o hole.o \ 13 | dist_betw_fils.o mutual.o newPrecond.o deg_mutual.o \ 14 | barnoldi.o regurgitate.o 15 | 16 | MOBJS = mulGlobal.o mulDo.o mulMulti.o mulLocal.o mulMats.o direct.o \ 17 | uglieralloc.o capsolve.o 18 | 19 | NONUNIOBJS = find_nonuni_path.o read_tree.o contact.o 20 | 21 | HEADER = induct.h cmplx.h resusage.h 22 | MULHEAD = mulStruct.h mulGlobal.h patran.h resusage.h 23 | NONUNIHEAD = gp.h 24 | 25 | fasthenry: $(OBJS) $(MOBJS) $(NONUNIOBJS) $(SPLIB) 26 | $(CC) -o fasthenry $(CFLAGS) $(OBJS) $(MOBJS) $(NONUNIOBJS) $(SPLIB) -lm 27 | mv fasthenry $(BIN)/fasthenry 28 | 29 | $(SPLIB): 30 | cd sparse; make 31 | 32 | clean: 33 | $(RM) -f *.o 34 | cd sparse; make clean 35 | 36 | $(OBJS): $(HEADER) $(MULHEAD) 37 | 38 | $(MOBJS): $(MULHEAD) 39 | 40 | $(NONUNIOBJS): $(HEADER) $(MULHEAD) $(NONUNIHEAD) 41 | -------------------------------------------------------------------------------- /src/fasthenry/Makefile.sgi: -------------------------------------------------------------------------------- 1 | CFLAGS = -O -DFOUR -DSGI -Olimit 2000 -cckr 2 | 3 | SHELL = /bin/sh 4 | RM = /bin/rm 5 | BIN = ../../bin 6 | 7 | SPLIB = sparse/sparse.a 8 | 9 | OBJS = induct.o gmres.o savemat_mod.o readGeom.o joelself.o writefastcap.o \ 10 | SetupMulti.o calcp.o SetupComputePsi.o mulSetup.o BreakupSeg.o \ 11 | Precond.o addgroundplane.o findpaths.o fillM.o cx_ludecomp.o \ 12 | parse_command_line.o default_opts.o Prec_cost.o hole.o \ 13 | dist_betw_fils.o mutual.o newPrecond.o deg_mutual.o \ 14 | barnoldi.o regurgitate.o 15 | 16 | MOBJS = mulGlobal.o mulDo.o mulMulti.o mulLocal.o mulMats.o direct.o \ 17 | uglieralloc.o capsolve.o 18 | 19 | NONUNIOBJS = find_nonuni_path.o read_tree.o contact.o 20 | 21 | HEADER = induct.h cmplx.h resusage.h 22 | MULHEAD = mulStruct.h mulGlobal.h patran.h resusage.h 23 | NONUNIHEAD = gp.h 24 | 25 | fasthenry: $(OBJS) $(MOBJS) $(NONUNIOBJS) $(SPLIB) 26 | $(CC) -o fasthenry $(CFLAGS) $(OBJS) $(MOBJS) $(NONUNIOBJS) $(SPLIB) -lm 27 | mv fasthenry $(BIN)/fasthenry 28 | 29 | $(SPLIB): 30 | cd sparse; make 31 | 32 | clean: 33 | $(RM) -f *.o 34 | cd sparse; make clean 35 | 36 | $(OBJS): $(HEADER) $(MULHEAD) 37 | 38 | $(MOBJS): $(MULHEAD) 39 | 40 | $(NONUNIOBJS): $(HEADER) $(MULHEAD) $(NONUNIHEAD) 41 | -------------------------------------------------------------------------------- /src/fasthenry/Makefile.alpha: -------------------------------------------------------------------------------- 1 | CFLAGS = -O -DFOUR -DDEC -Olimit 2000 -DALPHA 2 | 3 | SHELL = /bin/sh 4 | RM = /bin/rm 5 | BIN = ../../bin 6 | 7 | SPLIB = sparse/sparse.a 8 | 9 | OBJS = induct.o gmres.o savemat_mod.o readGeom.o joelself.o writefastcap.o \ 10 | SetupMulti.o calcp.o SetupComputePsi.o mulSetup.o BreakupSeg.o \ 11 | Precond.o addgroundplane.o findpaths.o fillM.o cx_ludecomp.o \ 12 | parse_command_line.o default_opts.o Prec_cost.o hole.o \ 13 | dist_betw_fils.o mutual.o newPrecond.o deg_mutual.o \ 14 | barnoldi.o regurgitate.o 15 | 16 | MOBJS = mulGlobal.o mulDo.o mulMulti.o mulLocal.o mulMats.o direct.o \ 17 | uglieralloc.o capsolve.o 18 | 19 | NONUNIOBJS = find_nonuni_path.o read_tree.o contact.o 20 | 21 | HEADER = induct.h cmplx.h resusage.h 22 | MULHEAD = mulStruct.h mulGlobal.h patran.h resusage.h 23 | NONUNIHEAD = gp.h 24 | 25 | fasthenry: $(OBJS) $(MOBJS) $(NONUNIOBJS) $(SPLIB) 26 | $(CC) -o fasthenry $(CFLAGS) $(OBJS) $(MOBJS) $(NONUNIOBJS) $(SPLIB) -lm 27 | mv fasthenry $(BIN)/fasthenry 28 | 29 | $(SPLIB): 30 | cd sparse; make 31 | 32 | clean: 33 | $(RM) -f *.o 34 | cd sparse; make clean 35 | 36 | $(OBJS): $(HEADER) $(MULHEAD) 37 | 38 | $(MOBJS): $(MULHEAD) 39 | 40 | $(NONUNIOBJS): $(HEADER) $(MULHEAD) $(NONUNIHEAD) 41 | -------------------------------------------------------------------------------- /src/fasthenry/sparse/Makefile~: -------------------------------------------------------------------------------- 1 | # Makefile for Sparse1.3 2 | # 3 | # Ken Kundert 4 | # UC Berkeley 5 | # 6 | CFLAGS = -O 7 | LINTFLAGS = -lc -lm 8 | SHELL = /bin/sh 9 | CC = cc 10 | 11 | HFILES = spConfig.h spDefs.h spMatrix.h 12 | CFILES = spAllocate.c spBuild.c spFactor.c spOutput.c spSolve.c spUtils.c \ 13 | spCompat.c spFortran.c 14 | OFILES = spAllocate.o spBuild.o spFactor.o spOutput.o spSolve.o spUtils.o \ 15 | spCompat.o spFortran.o 16 | LIBRARY = sparse.a 17 | DESTINATION = sparse 18 | TESTC = spTest.c 19 | TESTO = spTest.o 20 | 21 | SOURCE = $(HFILES) $(CFILES) 22 | 23 | $(DESTINATION) : $(LIBRARY) $(TESTO) 24 | $(CC) $(CFLAGS) -o $(DESTINATION) $(TESTO) $(LIBRARY) -lm 25 | 26 | $(LIBRARY) : $(OFILES) 27 | ar r $(LIBRARY) $? 28 | ranlib $(LIBRARY) 29 | 30 | spice : $(LIBRARY) spSMP.o 31 | cp $(LIBRARY) ../SMP.a 32 | ar r ../SMP.a spSMP.o 33 | ranlib ../SMP.a 34 | 35 | lint : 36 | @lint $(LINTFLAGS) $(CFILES) $(TESTC) | grep -v "but never used" 37 | 38 | clean : 39 | rm -f $(OFILES) $(LIBRARY) $(TESTO) $(DESTINATION) spSMP.o core 40 | 41 | touch : 42 | touch -c $(OFILES) $(LIBRARY) 43 | ranlib $(LIBRARY) 44 | 45 | tags : $(SOURCE) $(TESTC) 46 | ctags -t -w $(SOURCE) $(TESTC) 47 | 48 | $(OFILES) : $(HFILES) 49 | $(TESTO) : $(HFILES) 50 | spSMP.o : spMatrix.h ../include/SMPdefs.h 51 | -------------------------------------------------------------------------------- /src/fasthenry/sparse/Makefile.default: -------------------------------------------------------------------------------- 1 | # Makefile for Sparse1.3 2 | # 3 | # Ken Kundert 4 | # UC Berkeley 5 | # 6 | CFLAGS = -O 7 | LINTFLAGS = -lc -lm 8 | SHELL = /bin/sh 9 | CC = cc 10 | 11 | HFILES = spConfig.h spDefs.h spMatrix.h 12 | CFILES = spAllocate.c spBuild.c spFactor.c spOutput.c spSolve.c spUtils.c \ 13 | spCompat.c spFortran.c 14 | OFILES = spAllocate.o spBuild.o spFactor.o spOutput.o spSolve.o spUtils.o \ 15 | spCompat.o spFortran.o 16 | LIBRARY = sparse.a 17 | DESTINATION = sparse 18 | TESTC = spTest.c 19 | TESTO = spTest.o 20 | 21 | SOURCE = $(HFILES) $(CFILES) 22 | 23 | #$(DESTINATION) : $(LIBRARY) $(TESTO) 24 | # $(CC) $(CFLAGS) -o $(DESTINATION) $(TESTO) $(LIBRARY) -lm 25 | 26 | $(LIBRARY) : $(OFILES) 27 | ar r $(LIBRARY) $? 28 | ranlib $(LIBRARY) 29 | 30 | spice : $(LIBRARY) spSMP.o 31 | cp $(LIBRARY) ../SMP.a 32 | ar r ../SMP.a spSMP.o 33 | ranlib ../SMP.a 34 | 35 | lint : 36 | @lint $(LINTFLAGS) $(CFILES) $(TESTC) | grep -v "but never used" 37 | 38 | clean : 39 | rm -f $(OFILES) $(LIBRARY) $(TESTO) $(DESTINATION) spSMP.o core 40 | 41 | touch : 42 | touch -c $(OFILES) $(LIBRARY) 43 | ranlib $(LIBRARY) 44 | 45 | tags : $(SOURCE) $(TESTC) 46 | ctags -t -w $(SOURCE) $(TESTC) 47 | 48 | $(OFILES) : $(HFILES) 49 | #$(TESTO) : $(HFILES) 50 | spSMP.o : spMatrix.h ../include/SMPdefs.h 51 | -------------------------------------------------------------------------------- /src/fasthenry/sparse/Makefile.x64: -------------------------------------------------------------------------------- 1 | # Makefile for Sparse1.3 2 | # 3 | # Ken Kundert 4 | # UC Berkeley 5 | # 6 | CFLAGS = -O -m64 7 | LINTFLAGS = -lc -lm 8 | SHELL = /bin/sh 9 | CC = cc 10 | 11 | HFILES = spConfig.h spDefs.h spMatrix.h 12 | CFILES = spAllocate.c spBuild.c spFactor.c spOutput.c spSolve.c spUtils.c \ 13 | spCompat.c spFortran.c 14 | OFILES = spAllocate.o spBuild.o spFactor.o spOutput.o spSolve.o spUtils.o \ 15 | spCompat.o spFortran.o 16 | LIBRARY = sparse.a 17 | DESTINATION = sparse 18 | TESTC = spTest.c 19 | TESTO = spTest.o 20 | 21 | SOURCE = $(HFILES) $(CFILES) 22 | 23 | #$(DESTINATION) : $(LIBRARY) $(TESTO) 24 | # $(CC) $(CFLAGS) -o $(DESTINATION) $(TESTO) $(LIBRARY) -lm 25 | 26 | $(LIBRARY) : $(OFILES) 27 | ar r $(LIBRARY) $? 28 | ranlib $(LIBRARY) 29 | 30 | spice : $(LIBRARY) spSMP.o 31 | cp $(LIBRARY) ../SMP.a 32 | ar r ../SMP.a spSMP.o 33 | ranlib ../SMP.a 34 | 35 | lint : 36 | @lint $(LINTFLAGS) $(CFILES) $(TESTC) | grep -v "but never used" 37 | 38 | clean : 39 | rm -f $(OFILES) $(LIBRARY) $(TESTO) $(DESTINATION) spSMP.o core 40 | 41 | touch : 42 | touch -c $(OFILES) $(LIBRARY) 43 | ranlib $(LIBRARY) 44 | 45 | tags : $(SOURCE) $(TESTC) 46 | ctags -t -w $(SOURCE) $(TESTC) 47 | 48 | $(OFILES) : $(HFILES) 49 | #$(TESTO) : $(HFILES) 50 | spSMP.o : spMatrix.h ../include/SMPdefs.h 51 | -------------------------------------------------------------------------------- /src/fasthenry/sparse/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sparse1.3 2 | # 3 | # Ken Kundert 4 | # UC Berkeley 5 | # 6 | CFLAGS = -O -m64 -std=gnu89 -DNO_GETHOSTNAME 7 | LINTFLAGS = -lc -lm 8 | SHELL = /bin/sh 9 | CC = cc 10 | 11 | HFILES = spConfig.h spDefs.h spMatrix.h 12 | CFILES = spAllocate.c spBuild.c spFactor.c spOutput.c spSolve.c spUtils.c \ 13 | spCompat.c spFortran.c 14 | OFILES = spAllocate.o spBuild.o spFactor.o spOutput.o spSolve.o spUtils.o \ 15 | spCompat.o spFortran.o 16 | LIBRARY = sparse.a 17 | DESTINATION = sparse 18 | TESTC = spTest.c 19 | TESTO = spTest.o 20 | 21 | SOURCE = $(HFILES) $(CFILES) 22 | 23 | #$(DESTINATION) : $(LIBRARY) $(TESTO) 24 | # $(CC) $(CFLAGS) -o $(DESTINATION) $(TESTO) $(LIBRARY) -lm 25 | 26 | $(LIBRARY) : $(OFILES) 27 | ar r $(LIBRARY) $? 28 | ranlib $(LIBRARY) 29 | 30 | spice : $(LIBRARY) spSMP.o 31 | cp $(LIBRARY) ../SMP.a 32 | ar r ../SMP.a spSMP.o 33 | ranlib ../SMP.a 34 | 35 | lint : 36 | @lint $(LINTFLAGS) $(CFILES) $(TESTC) | grep -v "but never used" 37 | 38 | clean : 39 | rm -f $(OFILES) $(LIBRARY) $(TESTO) $(DESTINATION) spSMP.o core 40 | 41 | touch : 42 | touch -c $(OFILES) $(LIBRARY) 43 | ranlib $(LIBRARY) 44 | 45 | tags : $(SOURCE) $(TESTC) 46 | ctags -t -w $(SOURCE) $(TESTC) 47 | 48 | $(OFILES) : $(HFILES) 49 | #$(TESTO) : $(HFILES) 50 | spSMP.o : spMatrix.h ../include/SMPdefs.h 51 | -------------------------------------------------------------------------------- /bin/plotfastH.m: -------------------------------------------------------------------------------- 1 | function plotfastH(name); 2 | % Load and plot a 3D fasthenry structure produced with "zbuf -m name" 3 | % where name is without the ".mat" 4 | 5 | xt = []; yt = []; zt = []; 6 | xq = []; yq = []; zq = []; 7 | 8 | eval(['load ' name]); 9 | fprintf(1, 'loaded %d panels\n', length(xt) + length(xq)); 10 | hold off; 11 | if length(xt) > 0, 12 | ht = fill3(xt, yt, zt, 'r'); 13 | hold on; 14 | end 15 | X = max([max(xt) max(yt) max(zt)]); 16 | Y = min([min(xt) min(yt) min(zt)]); 17 | 18 | if length(xq) > 0, 19 | hq = fill3(xq, yq, zq, 'y'); 20 | end; 21 | 22 | X = max([X max(xq) max(yq) max(zq)]); 23 | Y = min([Y min(xq) min(yq) min(zq)]); 24 | 25 | 26 | axis([Y X Y X Y X]); 27 | fprintf(1, 'finished filling polygons\n'); 28 | 29 | %return; 30 | 31 | 32 | axis('square'); 33 | %return; 34 | 35 | 36 | set(ht, 'FaceColor', 'w') 37 | set(ht, 'EdgeColor', 'k') 38 | 39 | set(hq, 'FaceColor', 'w') 40 | set(hq, 'EdgeColor', 'k') 41 | axis('square'); 42 | axis('off'); 43 | return; 44 | 45 | %g = get(hq(1), 'LineWidth'); set(hq, 'LineWidth', 2*g); 46 | 47 | f = gcf; 48 | set(f, 'Color', [1 1 1]); 49 | set(f, 'InvertHardcopy', 'off'); 50 | 51 | %set(f, 'PaperOrientation', 'landscape'); 52 | print -deps panels.ps 53 | 54 | return; 55 | 56 | fprintf(1, 'printing...\n'); 57 | print -dps -Plouvre 58 | !lpq -Plouvre 59 | 60 | -------------------------------------------------------------------------------- /src/fasthenry/cmplx.h: -------------------------------------------------------------------------------- 1 | 2 | typedef struct cx_struct { 3 | double real; 4 | double imag; 5 | } CX; 6 | 7 | #define cx_add(z,x,y) \ 8 | do { \ 9 | (z).real = (x).real + (y).real; \ 10 | (z).imag = (x).imag + (y).imag; \ 11 | } while(0) 12 | 13 | #define cx_sub(z,x,y) \ 14 | do { \ 15 | (z).real = (x).real - (y).real; \ 16 | (z).imag = (x).imag - (y).imag; \ 17 | } while(0) 18 | 19 | #define cx_mul(z,x,y) \ 20 | do { \ 21 | (z).real = (x).real * (y).real - (x).imag * (y).imag; \ 22 | (z).imag = (x).imag * (y).real + (x).real * (y).imag; \ 23 | } while(0) 24 | 25 | #define cx_div(z,x,y) \ 26 | do { \ 27 | (z).real = 1.0 / ((y).real * (y).real + (y).imag * (y).imag); \ 28 | (z).imag = (z).real; \ 29 | (z).real *= (x).real * (y).real + (x).imag * (y).imag; \ 30 | (z).imag *= (x).imag * (y).real - (x).real * (y).imag; \ 31 | } while(0) 32 | 33 | #define cx_conj_mul(z,x,y) \ 34 | do { \ 35 | (z).real = (x).real * (y).real + (x).imag * (y).imag; \ 36 | (z).imag = (x).imag * (y).real - (x).real * (y).imag; \ 37 | } while(0) 38 | 39 | #define cx_abs(x) \ 40 | (sqrt((x).real*(x).real+(x).imag*(x).imag)) 41 | 42 | #define cx_scalar_mult(z, alpha, x) \ 43 | do { \ 44 | (z).real = alpha*(x).real; \ 45 | (z).imag = alpha*(x).imag; \ 46 | } while(0) 47 | 48 | static CX CXZERO = { 0, 0 }; 49 | static CX CXONE = { 1, 0 }; 50 | static CX CXMONE = { -1, 0 }; 51 | 52 | -------------------------------------------------------------------------------- /src/fasthenry/default_opts.c: -------------------------------------------------------------------------------- 1 | /* This fills an ind_opts with the default options */ 2 | /* There is little error checking that these are valid */ 3 | #include "induct.h" 4 | 5 | default_opts(opts) 6 | ind_opts *opts; 7 | { 8 | opts->soln_technique = ITERATIVE; /* -s */ 9 | opts->mat_vect_prod = MULTIPOLE; /* -m */ 10 | opts->precond = ON; /* -p */ 11 | opts->order = 2; /* -o */ 12 | opts->level = AUTO; /* -l */ 13 | opts->makeFastCapFile = OFF; /* -f */ 14 | opts->gp_draw = OFF; /* -g */ 15 | opts->auto_refine = ON; /* -a */ 16 | opts->init_refine = 0; /* -i */ 17 | opts->dumpMats = OFF; /* -d */ 18 | opts->orderROM = -1; /* -r */ 19 | opts->onlyROM = 0; /* -M */ 20 | opts->kind = MATLAB; /* -k */ 21 | opts->tol = 1e-3; /* -t */ 22 | opts->abs_tol = 1e-2; /* -b */ 23 | opts->maxiters = 200; /* -c */ 24 | opts->limit = AUTO; /* -e */ 25 | opts->debug = OFF; /* -D */ 26 | opts->portlist = NULL; /* -x */ 27 | opts->suffix = ""; /* -S */ 28 | opts->shell_r0 = 0.87; /* -R */ 29 | opts->regurgitate = FALSE; /* -v */ 30 | opts->fname = NULL; 31 | } 32 | 33 | -------------------------------------------------------------------------------- /src/fasthenry/resusage.h: -------------------------------------------------------------------------------- 1 | /* # ***** sort to /src/header 2 | # ***** */ 3 | /* header where rusage and time structs are defined */ 4 | 5 | #ifdef FOUR 6 | #define NOTOTHER 1 7 | // #include 8 | // #include 9 | // struct rusage timestuff; 10 | #endif 11 | 12 | #ifdef FIVE 13 | #define NOTOTHER 1 14 | // #include 15 | // #include 16 | // #include 17 | // struct tms timestuff; 18 | #endif 19 | 20 | /* define macros for time and resident memory usage checks */ 21 | 22 | // static double dtime = 0.0; 23 | // static long sectime, utime; 24 | 25 | #ifdef NOTOTHER 26 | 27 | #ifdef FOUR /* 4.2,3BSD (tested: Sun4, IBM6000, DEC5000) */ 28 | // #define starttimer getrusage(RUSAGE_SELF, ×tuff); \ 29 | // sectime = timestuff.ru_utime.tv_sec; \ 30 | // utime = timestuff.ru_utime.tv_usec 31 | // #define stoptimer getrusage(RUSAGE_SELF, ×tuff); \ 32 | // dtime = (double)(timestuff.ru_utime.tv_sec - sectime) \ 33 | // + 1.0e-6*(double)(timestuff.ru_utime.tv_usec - utime) 34 | #define DUMPRSS /* */ 35 | #endif /* FOUR */ 36 | 37 | #ifdef FIVE /* for System V (tested: HP300) */ 38 | // #define starttimer times(×tuff); \ 39 | // utime = timestuff.tms_utime 40 | // #define stoptimer times(×tuff); \ 41 | // dtime = (timestuff.tms_utime)-utime; \ 42 | // dtime /= HZ 43 | #define DUMPRSS /* */ 44 | #endif /* FIVE */ 45 | 46 | #else /* default - no timers */ 47 | 48 | // #define starttimer /* */ 49 | // #define stoptimer /* */ 50 | #define DUMPRSS /* */ 51 | 52 | #endif /* NOTOTHER */ 53 | -------------------------------------------------------------------------------- /src/fasthenry/patran.h: -------------------------------------------------------------------------------- 1 | /* # ***** sort to /src/header 2 | # ***** */ 3 | /*************************************************************************** 4 | 5 | This is the header file for patran.c. 6 | 7 | Written by Songmin Kim, July 24, 1990. 8 | 9 | ***************************************************************************/ 10 | /* Refer to Chapter 29, Neutral System, of PATRAN manual for explanation. 11 | The variable names are identical to those that appear in the manual. */ 12 | 13 | typedef struct node { 14 | int ID; 15 | double coord[3]; 16 | } NODE; 17 | 18 | typedef struct element { 19 | int ID, shape, num_nodes; 20 | int corner[4]; 21 | } ELEMENT; 22 | 23 | typedef struct grid { 24 | int ID, *equiv_ID, number_equiv_grids; 25 | double coord[3]; 26 | struct grid *next, *prev; 27 | } GRID; 28 | 29 | typedef struct cfeg { 30 | int ID, NELS, LPH, LPH_ID, LSHAPE, NODES, ICONF, NDIM; 31 | struct cfeg *next, *prev; 32 | int *element_list; 33 | } CFEG; 34 | 35 | typedef struct patch { 36 | int ID, corner[4], conductor_ID; 37 | struct patch *next, *prev; 38 | } PATCH; 39 | 40 | typedef struct sm_patch { 41 | int ID, conductor_ID; 42 | struct sm_patch *next; 43 | } SM_PATCH; 44 | 45 | /* intermediate name struct; used for compatability with patran i/f */ 46 | typedef struct name { 47 | char *name; 48 | SM_PATCH *patch_list; 49 | struct name *next; 50 | } NAME; 51 | 52 | /* used to build linked list of conductor names */ 53 | struct Name { 54 | char *name; 55 | struct Name *next; 56 | struct Name *alias_list; 57 | }; 58 | typedef struct Name Name; 59 | 60 | /* used to make linked lists of iteration or conductor #s */ 61 | struct ITER { 62 | int iter; 63 | struct ITER *next; 64 | }; 65 | typedef struct ITER ITER; 66 | -------------------------------------------------------------------------------- /src/fasthenry/calcp.c: -------------------------------------------------------------------------------- 1 | /* this calls the routine to calculate the filament-filament 2 | interaction exactly */ 3 | 4 | #include "induct.h" 5 | 6 | static int num2nd=0, num4th=0, numexact=0; 7 | static int num2ndsav=0, num4thsav=0, numexactsav=0; 8 | 9 | double calcp(pchg1, pchg2, pfd) 10 | charge *pchg1, *pchg2; 11 | double *pfd; /* left over from fastcap */ 12 | { 13 | double mutual(), selfterm(); 14 | 15 | if (pfd != NULL) 16 | fprintf(stderr, "calcp: I don't know what to do with pfd!=NULL\n"); 17 | 18 | if (pchg1->fil->filnumber == pchg2->fil->filnumber) 19 | /* self term */ 20 | return selfterm(pchg1->fil); 21 | else 22 | /* calculate mutual inductance of the two filaments */ 23 | return mutual(pchg1->fil, pchg2->fil); 24 | } 25 | 26 | /* from the fastcap calcp */ 27 | dumpnums(flag, size) 28 | int flag, size; 29 | { 30 | double total; 31 | 32 | if(flag == ON) { /* if first call */ 33 | num2ndsav = num2nd; 34 | num4thsav = num4th; 35 | numexactsav = numexact; 36 | } 37 | else { 38 | total = num2ndsav + num4thsav + numexactsav; 39 | #if MULDAT == ON 40 | fprintf(stdout, "Potential coefficient counts\n multipole only:\n"); 41 | fprintf(stdout, 42 | " 2nd order: %d %.3g%%; 4th: %d %.3g%%; Integral: %d %.3g%%\n", 43 | num2nd, 100*(num2ndsav/total), num4th, 100*(num4thsav/total), 44 | numexact, 100*(numexactsav/total)); 45 | #endif 46 | total = num2nd + num4th + numexact; 47 | #if MULDAT == ON 48 | fprintf(stdout, " multipole plus adaptive:\n"); 49 | fprintf(stdout, 50 | " 2nd order: %d %.3g%%; 4th: %d %.3g%%; Integral: %d %.3g%%\n", 51 | num2nd, 100*(num2nd/total), num4th, 100*(num4th/total), 52 | numexact, 100*(numexact/total)); 53 | #endif 54 | fprintf(stdout, "Percentage of multiplies done by multipole: %.3g%%\n", 55 | 100*(size*size - total)/(size*size)); 56 | if(size*size == total) 57 | fprintf(stdout, "Warning: no multipole acceleration\n"); 58 | } 59 | } 60 | 61 | double tilelength(nq) 62 | charge *nq; 63 | { 64 | return nq->max_diag; 65 | } 66 | -------------------------------------------------------------------------------- /src/fasthenry/Makefile: -------------------------------------------------------------------------------- 1 | # Default flags (add more specific ones based on the OS below) 2 | CFLAGS := -O -DFOUR -m64 -fcommon -std=gnu89 -DNO_GETHOSTNAME 3 | 4 | # Compiler path for different systems 5 | ifeq ($(OS), Windows_NT) 6 | # Windows-specific settings 7 | CC := gcc # Use the appropriate path to gcc if needed 8 | CFLAGS += -DWINDOWS 9 | 10 | else 11 | UNAME_S := $(shell uname -s) 12 | ifeq ($(UNAME_S), Linux) 13 | # Linux-specific settings 14 | CC := gcc # Replace with the correct path if not default 15 | CFLAGS += -DLINUX 16 | endif 17 | ifeq ($(UNAME_S), Darwin) 18 | # macOS-specific settings 19 | CC := /opt/homebrew/Cellar/gcc/14.2.0_1/bin/gcc-14 # Replace if necessary 20 | CFLAGS += -DMACOS 21 | endif 22 | endif 23 | 24 | # Other variables 25 | SHELL = /bin/sh 26 | RM = /bin/rm 27 | BIN = ../../bin 28 | 29 | SPLIB = sparse/sparse.a 30 | 31 | # Object files 32 | OBJS = induct.o gmres.o savemat_mod.o readGeom.o joelself.o writefastcap.o \ 33 | SetupMulti.o calcp.o SetupComputePsi.o mulSetup.o BreakupSeg.o \ 34 | Precond.o addgroundplane.o findpaths.o fillM.o cx_ludecomp.o \ 35 | parse_command_line.o default_opts.o Prec_cost.o hole.o \ 36 | dist_betw_fils.o mutual.o newPrecond.o deg_mutual.o \ 37 | barnoldi.o regurgitate.o 38 | 39 | MOBJS = mulGlobal.o mulDo.o mulMulti.o mulLocal.o mulMats.o direct.o \ 40 | uglieralloc.o capsolve.o 41 | 42 | NONUNIOBJS = find_nonuni_path.o read_tree.o contact.o 43 | 44 | HEADER = induct.h cmplx.h resusage.h 45 | MULHEAD = mulStruct.h mulGlobal.h patran.h resusage.h 46 | NONUNIHEAD = gp.h 47 | 48 | # Main target 49 | fasthenry: $(OBJS) $(MOBJS) $(NONUNIOBJS) $(SPLIB) 50 | $(CC) -o fasthenry $(CFLAGS) $(OBJS) $(MOBJS) $(NONUNIOBJS) $(SPLIB) -lm 51 | mv fasthenry $(BIN)/fasthenry 52 | 53 | # Sparse library target 54 | $(SPLIB): 55 | cd sparse; make 56 | 57 | # Clean rule 58 | clean: 59 | $(RM) -f *.o 60 | cd sparse; make clean 61 | 62 | # Dependency rules 63 | $(OBJS): $(HEADER) $(MULHEAD) 64 | $(MOBJS): $(MULHEAD) 65 | $(NONUNIOBJS): $(HEADER) $(MULHEAD) $(NONUNIHEAD) -------------------------------------------------------------------------------- /src/fasthenry/capsolve.c: -------------------------------------------------------------------------------- 1 | /* # ***** sort to /src/main 2 | # ***** */ 3 | #include "mulGlobal.h" 4 | 5 | /* 6 | ComputePsi computes the potential from the charge vector, or may 7 | include a preconditioner. It is assumed that the vectors for the 8 | charge and potential have already been set up and that the potential 9 | vector has been zeroed. ARBITRARY VECTORS CAN NOT BE USED. 10 | */ 11 | 12 | computePsi(sys, q, p, size, chglist) 13 | ssystem *sys; 14 | double *q, *p; 15 | int size; 16 | charge *chglist; 17 | { 18 | //extern double dirtime, uptime, downtime, evaltime, prectime; 19 | extern int real_size; 20 | int i; 21 | 22 | ASSERT(p == sys->p); 23 | ASSERT(q == sys->q); 24 | 25 | for(i=1; i <= size; i++) p[i] = 0; 26 | 27 | #if PRECOND != NONE 28 | //starttimer; 29 | mulPrecond(sys, PRECOND); 30 | //stoptimer; 31 | // prectime += dtime; 32 | #endif 33 | 34 | #if EXPGCR == ON 35 | blkCompressVector(q+1, size, real_size, sys->is_dummy+1); 36 | blkAqprod(p+1, q+1, real_size, sqrmat); /* offset since index from 1 */ 37 | blkExpandVector(p+1, size, real_size); /* ap changed to p, r chged to q */ 38 | blkExpandVector(q+1, size, real_size); /* 7 Oct 91 */ 39 | #else 40 | /* moved into SetupComputePsi since it only is done once 41 | //starttimer; 42 | mulDirect(sys); 43 | //stoptimer; 44 | // dirtime += dtime; 45 | */ 46 | 47 | //starttimer; 48 | mulUp(sys); 49 | //stoptimer; 50 | // uptime += dtime; 51 | 52 | #if DUPVEC == ON 53 | dumpLevOneUpVecs(sys); 54 | #endif 55 | 56 | #if DNTYPE == NOSHFT 57 | mulDown(sys); /* do downward pass without local exp shifts */ 58 | #endif 59 | 60 | #if DNTYPE == GRENGD 61 | mulDown(sys); /* do heirarchical local shift dwnwd pass */ 62 | #endif 63 | //stoptimer; 64 | // downtime += dtime; 65 | 66 | //starttimer; 67 | #if MULTI == ON 68 | mulEval(sys); /* evaluate either locals or multis or both */ 69 | #endif 70 | //stoptimer; 71 | // evaltime += dtime; 72 | 73 | #if DMPCHG == LAST 74 | fprintf(stdout, "\nPanel potentials divided by areas\n"); 75 | dumpChgDen(stdout, p, chglist); 76 | fprintf(stdout, "End panel potentials\n"); 77 | #endif 78 | 79 | /* convert the voltage vec entries on dielectric i/f's into eps1E1-eps2E2 */ 80 | /* compute_electric_fields(sys, chglist); */ 81 | 82 | #if 1==0 83 | #if OPCNT == ON 84 | printops(); 85 | exit(0); 86 | #endif /* OPCNT == ON */ 87 | #endif 88 | 89 | #endif /* EXPGCR == ON */ 90 | } 91 | -------------------------------------------------------------------------------- /src/fasthenry/cx_ludecomp.c: -------------------------------------------------------------------------------- 1 | /* Complex LU decomposition routines */ 2 | /* 3 | - returned matrix has L below the diagonal, U above (GVL1 pg 58) 4 | - if allocate == TRUE ends up storing LU (could be a lot) 5 | */ 6 | 7 | #include "induct.h" 8 | 9 | CX **cx_ludecomp(matin, size, allocate) 10 | CX **matin; 11 | int size; 12 | int allocate; 13 | { 14 | extern int fulldirops; 15 | CX factor, **mat, tmp; 16 | int i, j, k; 17 | 18 | if(allocate == TRUE) { 19 | /* allocate for LU matrix and copy A */ 20 | MALLOC(mat, size, CX*, ON, IND); 21 | for(i = 0; i < size; i++) { 22 | MALLOC(mat[i], size, CX, ON, IND); 23 | for(j = 0; j < size; j++) mat[i][j] = matin[i][j]; 24 | } 25 | } 26 | else mat = matin; 27 | 28 | for(k = 0; k < size-1; k++) { /* loop on rows */ 29 | if(mat[k][k].real == 0.0 && mat[k][k].imag == 0.0) { 30 | fprintf(stderr, "ludecomp: zero pivot\n"); 31 | exit(0); 32 | } 33 | for(i = k+1; i < size; i++) { /* loop on remaining rows */ 34 | /*factor = (mat[i][k] /= mat[k][k]);*/ 35 | cx_div(tmp, mat[i][k], mat[k][k]); 36 | factor = mat[i][k] = tmp; 37 | fulldirops++; 38 | for(j = k+1; j < size; j++) { /* loop on remaining columns */ 39 | /* mat[i][j] -= (factor*mat[k][j]);*/ 40 | cx_mul(tmp, factor, mat[k][j]); 41 | cx_sub(mat[i][j], mat[i][j], tmp); 42 | fulldirops++; 43 | } 44 | } 45 | } 46 | return(mat); 47 | } 48 | 49 | /* 50 | For direct solution of Pq = psi, used if DIRSOL == ON or if preconditioning. 51 | */ 52 | void cx_lu_solve(mat, x, b, size) 53 | CX **mat, *x, *b; 54 | int size; 55 | { 56 | extern int fulldirops; 57 | int i, j; 58 | CX tmp; 59 | 60 | /* copy rhs */ 61 | if(x != b) for(i = 0; i < size; i++) x[i] = b[i]; 62 | 63 | /* forward elimination */ 64 | for(i = 0; i < size; i++) { /* loop on pivot row */ 65 | for(j = i+1; j < size; j++) { /* loop on elimnation row */ 66 | /* x[j] -= mat[j][i]*x[i]; */ 67 | cx_mul(tmp, mat[j][i], x[i]); 68 | cx_sub(x[j], x[j], tmp); 69 | fulldirops++; 70 | } 71 | } 72 | 73 | /* back substitution */ 74 | for(i--; i > -1; i--) { /* loop on rows */ 75 | for(j = i+1; j < size; j++) { /* loop on columns */ 76 | /* x[i] -= mat[i][j]*x[j]; */ 77 | cx_mul(tmp, mat[i][j], x[j]); 78 | cx_sub(x[i], x[i], tmp); 79 | fulldirops++; 80 | } 81 | /* x[i] /= mat[i][i]; */ 82 | cx_div(tmp, x[i], mat[i][i]); 83 | x[i] = tmp; 84 | fulldirops++; 85 | } 86 | } 87 | 88 | -------------------------------------------------------------------------------- /examples/plane.in: -------------------------------------------------------------------------------- 1 | * a line (5um wide) over a plane 100um below 2 | * line length=4000um 3 | * 4 | * Since the line is so long, and the discretization doesn't vary along 5 | * the line, this is almost a 2D problem by discretization. But to 6 | * make it truly 2D, the nodes on the ends of the plane must be 7 | * shorted together so no current flows perpendicular to the 8 | * trace direction. That is the purpose of all the "np" node definitions. 9 | * Actually, the line is long enough that we match 2D without shorting them 10 | * together, but if you really wanted to test against 2D, follow the 11 | * instructions at the .equiv lines below. 12 | * 13 | * R/cm = 15 ohm / 0.4 cm = 37.5 Ohm/cm 14 | * L/cm = 14.8 / (2*pi*6e8) / 0.4 cm = 9.81 nH/cm 15 | * 16 | * 17 | .units uM 18 | * 19 | * Define ground plane, sigma=3.15e7 1/(m*ohm)= 31.5 1/(um*ohm) 20 | g1 x1 = -500 y1 = 0 z1 = 0 21 | + x2 = 500 y2 = 0 z2 = 0 22 | + x3 = 500 y3 = 4000 z3 = 0 23 | + thick = 11 sigma= 31.5 24 | *+ seg1 = 20 seg2 = 1 25 | + nhinc = 3 rh=2 26 | * nodes to reference later: 27 | + np1 (0,0,0) 28 | + np2 (0,4000,0) 29 | + np25 (50,4000,0) 30 | + np3 (100,4000,0) 31 | + np35 (150,4000,0) 32 | + np4 (200,4000,0) 33 | + np45 (250,4000,0) 34 | + np5 (300,4000,0) 35 | + np55 (350,4000,0) 36 | + np56 (400,4000,0) 37 | + np57 (450,4000,0) 38 | + np58 (500,4000,0) 39 | + np51 (-50,4000,0) 40 | + np6 (-100,4000,0) 41 | + np65 (-150,4000,0) 42 | + np7 (-200,4000,0) 43 | + np75 (-250,4000,0) 44 | + np8 (-300,4000,0) 45 | + np85 (-350,4000,0) 46 | + np86 (-400,4000,0) 47 | + np87 (-450,4000,0) 48 | + np88 (-500,4000,0) 49 | + np05 (50,0,0) 50 | + np10 (100,0,0) 51 | + np105 (150,0,0) 52 | + np11 (200,0,0) 53 | + np115 (250,0,0) 54 | + np12 (300,0,0) 55 | + np121 (350,0,0) 56 | + np122 (400,0,0) 57 | + np123 (450,0,0) 58 | + np124 (500,0,0) 59 | + np125 (-50,0,0) 60 | + np13 (-100,0,0) 61 | + np135 (-150,0,0) 62 | + np14 (-200,0,0) 63 | + np145 (-250,0,0) 64 | + np15 (-300,0,0) 65 | + np151 (-350,0,0) 66 | + np152 (-400,0,0) 67 | + np153 (-450,0,0) 68 | + np154 (-500,0,0) 69 | +file=NONE 70 | + contact line (-1,0,0,0,4000,-1,2.5,500) 71 | + contact line (1,0,0,0,4000,1,2.5,500) 72 | * 73 | * line width=5um 74 | * thick h=1.7um sigma=3.15e7 1/(m*ohm)=31.5 1/(um*ohm) 75 | * 76 | NS1 x=0 y=0 z=106.35 77 | NS2 x=0 y=4000 z=106.35 78 | ES NS1 NS2 w=5 h=1.7 sigma=31.5 79 | +nwinc=3 nhinc=1 80 | 81 | .equiv NS2 np2 82 | * 83 | * To make this truly 2D, comment out the above line and uncomment the 84 | * following lines up to (but not including) the .external below. 85 | * 86 | *.equiv NS2 np2 np25 np3 np35 np4 np45 np5 np55 np56 np57 np58 np51 np6 np65 np7 np75 np8 np85 np86 np87 np88 87 | *.equiv 88 | *+np1 np05 89 | *+np10 90 | *+np105 np11 np115 np12 91 | *+np121 np122 np123 np124 92 | *+np125 93 | *+np13 np135 np14 np145 np15 np151 np152 np153 np154 94 | 95 | .external NS1 np1 96 | * 97 | .freq fmin=6e8 fmax=6e8 ndec=1 98 | .end 99 | 100 | -------------------------------------------------------------------------------- /src/fasthenry/makeMakefile.c: -------------------------------------------------------------------------------- 1 | /* this makes the makefile I want by brute force since the IBMs lack an 2 | important feature */ 3 | 4 | #include 5 | #include 6 | #include 7 | #define MAXLINE 10000 8 | 9 | char *getoneline(); 10 | 11 | main(argc, argv) 12 | int argc; 13 | char *argv[]; 14 | { 15 | 16 | char *line[2], name[1000], nameroot[1000]; 17 | char linebeg[2][MAXLINE]; 18 | char dir[2][50], depend[2][1000]; 19 | int numlines = 2; 20 | int skip, i; 21 | 22 | line[0] = linebeg[0]; 23 | line[1] = linebeg[1]; 24 | strcpy(line[0],getoneline(stdin)); 25 | strcpy(line[1],getoneline(stdin)); 26 | if (line[0] == NULL || line[1] == NULL) { 27 | fprintf(stderr, "First line: .o files in DIR\nSecond line: .o files in MUL\n"); 28 | exit(1); 29 | } 30 | 31 | remove_returns(line[0]); 32 | remove_returns(line[1]); 33 | 34 | fprintf(stdout, "CFLAGS = -O -DFOUR\n"); 35 | fprintf(stdout, "DIR = .\n"); 36 | fprintf(stdout, "MUL = $(DIR)/MattMulti\n"); 37 | fprintf(stdout, "HEADER = $(DIR)/induct.h $(DIR)/cmplx.h $(DIR)/resusage.h\n"); 38 | fprintf(stdout, "MULHEAD = $(MUL)/mulStruct.h $(MUL)/mulGlobal.h $(MUL)/patran.h\n"); 39 | strcpy(dir[0],"$(DIR)"); 40 | strcpy(dir[1],"$(MUL)"); 41 | strcpy(depend[0], "$(HEADER) $(MULHEAD)"); 42 | strcpy(depend[1], "$(MULHEAD)"); 43 | 44 | fprintf(stdout, "fasthenry:\t%s %s\n",linebeg[0], linebeg[1]); 45 | fprintf(stdout, "\t$(CC) -o fasthenry $(CFLAGS) %s %s -lm\n", 46 | linebeg[0], linebeg[1]); 47 | 48 | for(i = 0; i < numlines; i++) 49 | while(notblankline(line[i])) { 50 | if (sscanf(line[i],"%s%n",name,&skip) == 1) { 51 | get_root(name, nameroot); 52 | fprintf(stdout,"%s.o:\t%s/%s.c %s\n", 53 | nameroot,dir[i],nameroot,depend[i]); 54 | fprintf(stdout,"\t$(CC) $(CFLAGS) -c %s/%s.c\n\n",dir[i],nameroot); 55 | } 56 | else { 57 | fprintf(stderr,"Huh? Rest of line: %s\n",line[i]); 58 | exit(1); 59 | } 60 | line[i] += skip; 61 | } 62 | 63 | } 64 | 65 | 66 | char *getoneline(fp) 67 | FILE *fp; 68 | { 69 | static char line[MAXLINE] = { '\0' }; 70 | char *retchar; 71 | 72 | do { 73 | retchar = fgets(line, MAXLINE, fp); 74 | } while(retchar != NULL && !notblankline(line)); 75 | 76 | if (retchar != NULL && strlen(line) == MAXLINE - 1) 77 | fprintf(stderr,"Warning: line may be too long:\n%s\n",line); 78 | 79 | if (retchar == NULL) 80 | return NULL; 81 | else 82 | return line; 83 | } 84 | 85 | int notblankline(string) 86 | char *string; 87 | { 88 | while( *string!='\0' && isspace(*string)) 89 | string++; 90 | 91 | if (*string == '\0') return 0; 92 | else return 1; 93 | } 94 | 95 | get_root(src, dest) 96 | char *src, *dest; 97 | { 98 | 99 | while(*src != '.' && *src != '\0') 100 | *dest++ = *src++; 101 | 102 | *dest = '\0'; 103 | if (*src != '.') { 104 | fprintf(stderr, "Bad .o name\n"); 105 | } 106 | } 107 | 108 | remove_returns(src) 109 | char *src; 110 | { 111 | while(*src != '\0') { 112 | if (*src == '\n') 113 | *src = ' '; 114 | src++; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/fasthenry/sparse/doc/advert.ms: -------------------------------------------------------------------------------- 1 | .LP 2 | .po 1.5i 3 | .nr PO 1.5i 4 | .rs 5 | .ls 1 6 | .EQ 7 | delim @@ 8 | .EN 9 | 10 | .LG 11 | .LG 12 | .I 13 | .ce 2 14 | Sparse1.3 15 | .sp .1i 16 | A Sparse Linear Equation Solver 17 | .NL 18 | .NL 19 | .sp 0.25i 20 | .LG 21 | .R 22 | .ce 2 23 | .I Kenneth\ S.\ Kundert 24 | .I Alberto\ Sangiovanni-Vincentelli 25 | .NL 26 | .sp 0.25i 27 | .PP 28 | \fISparse1.3\fP is a flexible package of subroutines written in C used 29 | to quickly and accurately solve large sparse systems of linear 30 | equations. The package is able to handle arbitrary real and complex 31 | square matrix equations. Besides being able to solve linear systems, 32 | it is also able to quickly solve transposed systems, find determinants, 33 | and estimate errors due to ill-conditioning in the system of equations 34 | and instability in the computations. \fISparse\fR also provides a test 35 | program that is able read matrix equations from a file, solve them, and 36 | print useful information about the equation and its solution. 37 | .PP 38 | \fISparse1.3\fR is generally as fast or faster than other popular 39 | sparse matrix packages when solving many matrices of similar 40 | structure. \fISparse\fR does not require or assume symmetry and is 41 | able to perform numerical pivoting to avoid unnecessary error in the 42 | solution. It handles its own memory allocation, which allows the user 43 | to forgo the hassle of providing adequate memory. It also has a 44 | natural, flexible, and efficient interface to the calling program. 45 | .PP 46 | \fISparse\fR was originally written for use in circuit simulators and 47 | is particularly apt at handling node- and modified-node admittance 48 | matrices. The systems of linear generated in a circuit simulator stem 49 | from solving large systems of nonlinear equations using Newton's method 50 | and integrating large stiff systems of ordinary differential 51 | equations. However, \fISparse\fR is also suitable for other uses, one 52 | in particular is solving the very large systems of linear equations 53 | resulting from the numerical solution of partial differential 54 | equations. 55 | .PP 56 | The \fISparse1.3\fR package is currently available from the Department 57 | of Electrical Engineering and Computer Sciences of the University of 58 | California, Berkeley. It was written in the C programming language by 59 | Kenneth Kundert and versions exist for the \s-1UNIX\s+1 and 60 | \s-1VAX/VMS\s+1 operating systems. Be sure to specify the version when 61 | ordering. \fISparse1.3\fR has replaced \fISparse1.2\fR; providing 62 | greater capability and speed, and a more refined interface to the 63 | calling program. Besides the native \fISparse1.3\fR interface, two 64 | others are also provided. The first is a \fISparse1.2\fR interface, 65 | to make \fISparse1.3\fR backward compatible. The second allows 66 | \fISparse.13\fR to be called from FORTRAN programs. 67 | .PP 68 | \fISparse\fR is available for a $150.00 charge. The package includes 69 | the source code on tape, the user's guide, and a large selection of 70 | test matrices. To obtain a copy of \fISparse\fR, send a check or money 71 | order payable to the \fIRegents of the University of California\fR to: 72 | .sp 0.25 73 | .nf 74 | EECS Industrial Liaison Program 75 | 461 Cory Hall 76 | University of California 77 | Berkeley, CA 94720 78 | .LP 79 | Please allow four weeks for delivery. 80 | -------------------------------------------------------------------------------- /examples/make_nonuniform.c: -------------------------------------------------------------------------------- 1 | /* Produces a fasthenry input file of filaments on a UNIFORM 2 | plane discretization */ 3 | 4 | #include 5 | #include 6 | 7 | FILE *f_uni, *f_nonuni; 8 | char *MattAlloc(); 9 | 10 | main(argc, argv) 11 | int argc; 12 | char *argv[]; 13 | { 14 | int i,j; 15 | double min_len, x_len, y_len, thickness, z, x_cur; 16 | double *y, *x_horiz, *x_vert; 17 | double *vert_width; 18 | double horiz_len, horiz_width; 19 | double extra_x, extra_y; 20 | double r0, ratio; 21 | int numequiv; 22 | 23 | x_len = 21; 24 | y_len = 21; 25 | thickness = 0.01; 26 | z = 0; 27 | r0 = 0.05; 28 | ratio = 1.0/3.0; 29 | 30 | if (sscanf(argv[1], "%lf", &r0) != 1) { 31 | printf("need one integer argument: The radius of contacts\n"); 32 | exit(1); 33 | } 34 | 35 | numequiv = 200; 36 | 37 | /* f_nonuni = fopen("fh_nonuni.inp","w"); */ 38 | f_nonuni = stdout; 39 | 40 | fprintf(f_nonuni,"* Nonuniform test for r=%lg\n",r0); 41 | fprintf(f_nonuni,".units m\n.default sigma=5.8e7\n\n"); 42 | 43 | extra_x = (x_len - 1)/2.0; 44 | extra_y = (y_len - 1)/2.0; 45 | 46 | fprintf(f_nonuni,"g1 x1=%lg y1=%lg z1=%lg x2=%lg y2=%lg z2=%lg x3=%lg y3=%lg z3=%lg\n", 47 | -extra_x, -extra_y, z, 1 + extra_x, -extra_y, z, 1 + extra_x, 48 | 1 + extra_y, z); 49 | 50 | fprintf(f_nonuni,"+ file=NONE thick=%lg \n", 51 | thickness); 52 | fprintf(f_nonuni,"+ contact decay_rect (0,0, 0, %lg, %lg, %lg, %lg, 3, 3)\n", 53 | r0, r0, r0*ratio, r0*ratio); 54 | fprintf(f_nonuni,"+ contact decay_rect (1,1, 0, %lg, %lg, %lg, %lg, 3, 3)\n", 55 | r0, r0, r0*ratio, r0*ratio); 56 | 57 | 58 | /* equiv points in a circle */ 59 | for(i = 0; i < numequiv; i++) { 60 | fprintf(f_nonuni,"+ n_in_%d (%lg,%lg,%lg)\n",i, r0*cos(i*2*M_PI/numequiv), 61 | r0*sin(i*2*M_PI/numequiv),z); 62 | fprintf(f_nonuni,"+ n_out_%d (%lg,%lg,%lg)\n", 63 | i, 1 + r0*cos(i*2*M_PI/numequiv), 64 | 1 + r0*sin(i*2*M_PI/numequiv),z); 65 | } 66 | 67 | fprintf(f_nonuni,"\n.equiv n_in "); 68 | for(i = 0; i < numequiv; i++) { 69 | fprintf(f_nonuni, "n_in_%d ",i); 70 | if (i%10 == 0) 71 | fprintf(f_nonuni, "\n+ "); 72 | } 73 | 74 | fprintf(f_nonuni,"\n.equiv n_out "); 75 | for(i = 0; i < numequiv; i++) { 76 | fprintf(f_nonuni, "n_out_%d ",i); 77 | if (i%10 == 0) 78 | fprintf(f_nonuni, "\n+ "); 79 | } 80 | 81 | 82 | fprintf(f_nonuni,"\n\n"); 83 | fprintf(f_nonuni,".external n_in n_out\n"); 84 | 85 | fprintf(f_nonuni,".freq fmin=0 fmax=1e9 ndec=1\n"); 86 | fprintf(f_nonuni,".end\n"); 87 | 88 | fclose(f_nonuni); 89 | } 90 | 91 | double **MatrixAlloc(rows, cols, size) 92 | int rows, cols, size; 93 | { 94 | 95 | double **temp; 96 | int i; 97 | 98 | temp = (double **)MattAlloc(rows,sizeof(double *)); 99 | if (temp == NULL) { 100 | printf("not enough space for matrix allocation\n"); 101 | exit(1); 102 | } 103 | 104 | for(i = 0; i < rows; i++) 105 | temp[i] = (double *)MattAlloc(cols,size); 106 | 107 | if (temp[rows - 1] == NULL) { 108 | printf("not enough space for matrix allocation\n"); 109 | exit(1); 110 | } 111 | return(temp); 112 | } 113 | 114 | char* MattAlloc(number, size) 115 | int number, size; 116 | { 117 | 118 | char *blah; 119 | 120 | blah = (char *)malloc(number*size); 121 | 122 | if (blah == NULL) { 123 | fprintf(stderr, "MattAlloc: Couldn't get space. Needed %d\n",number*size); 124 | exit(1); 125 | } 126 | 127 | return blah; 128 | } 129 | -------------------------------------------------------------------------------- /src/fasthenry/sparse/doc/install.ms: -------------------------------------------------------------------------------- 1 | 2 | .LP 3 | .EQ 4 | delim $$ 5 | .EN 6 | .if t .po 1.5i 7 | .if t .nr PO 1.5i 8 | .if n .ll 7.5i 9 | .if n .nr LL 7.5i 10 | .rs 11 | .ls 1 12 | .LP 13 | .LG 14 | .LG 15 | .ce 16 | .I "Sparse1.3 Installation Notes" 17 | .NL 18 | .NL 19 | .sp .25i 20 | .LP 21 | .LG 22 | .B "General Description" 23 | .LP 24 | When \fISparse1.3\fR is loaded from tape, a directory structure will be 25 | created. The head directory is \fBsparse\fR, it contains source and 26 | various utility files. The \fBdoc\fR subdirectory contains the users 27 | manual and the \fBmatrices\fR subdirectory contains a collection of 28 | test matrices and their solution. 29 | .LP 30 | Before compiling, the file \fBspConfig.h\fR should be modified to suit 31 | your needs. Initially, I recommend turning on the DEBUG option and 32 | testing the error state of \fISparse\fR after each call to a 33 | \fISparse\fR routine. After things are working smoothly you can remove 34 | most of the error checking. Also in \fBspConfig.h\fR is the machine 35 | constants. These should be checked and modified before compiling if 36 | you are not using a \s-1VAX\s+1. 37 | .LP 38 | \fISparse\fR is compiled by using the makefile provided. This is a 39 | script file that automatically compiles each file and creates an object 40 | file for all of \fISparse\fR. Also created is an executable test 41 | program called \fBsparse\fR. 42 | .LP 43 | The \fISparse1.3\fR manual is contained in \fBspDoc\fR and 44 | \fBspDoc.ms\fR. \fBspDoc\fR is preformatted and readable on line. 45 | \fBspDoc.ms\fR is a raw \fItroff\fR file. 46 | .sp .25i 47 | .LP 48 | .B UNIX 49 | .LP 50 | The 51 | \fItar\fR 52 | program was used to write 53 | \fISparse\fR 54 | on the tape at 1600 bpi. To read it, simply type: 55 | .IP 56 | .B "tar x" 57 | .LP 58 | This will load \fISparse\fR into the current directory and 59 | automatically create the proper subdirectories. To compile, move into 60 | the \fBsparse\fR directory and type: 61 | .IP 62 | .B make 63 | .LP 64 | To create a printed manual, move into the \fBdoc\fR subdirectory and type: 65 | .IP 66 | .B "make" 67 | .LP 68 | You may have to modify the make file to indicate the name of the printer 69 | the document should be printed on. 70 | .sp .25i 71 | .LP 72 | .B 73 | VMS 74 | .LP 75 | \fISparse\fR was written on the tape in the ansi format at 1600 bpi and 76 | so is readable by \fIcopy\fR. Once the tape has been read, a series of 77 | files with nonsensical names will exist plus the file 78 | \fBUNPACK.COM\fR. This file, when executed, creates the directory 79 | hierarchy and moves the \fISparse\fR files into the proper directory 80 | and gives them the proper names. Thus, \fISparse\fR is installed with 81 | the following command sequence: 82 | .IP 83 | .B "MOUNT MFA0: SPARSE" 84 | .br 85 | .B "COPY MFA0:*.* *.*.*" 86 | .br 87 | .B "@UNPACK" 88 | .LP 89 | The file \fBUNPACK.COM\fR is then no longer needed. 90 | .LP 91 | Before compiling, it is necessary to edit the file \fBMAKE.COM\fR. The 92 | last line of the file must be changed so that the correct directory 93 | name for \fISparse\fR is given. This last line must be executed each 94 | time you relogin and plan to use the \fISparse\fR test program; you may 95 | want to copy it into \fBLOGIN.COM\fR. To compile, type: 96 | .IP 97 | .B @MAKE 98 | .sp .75i 99 | .LP 100 | .B "Good Luck ..." 101 | .LP 102 | Every effort has been made to make \fISparse\fR 103 | a pleasant program to work with. I hope you find it so. If you have 104 | any comments, criticisms, or praise, I would like to hear from you. I 105 | would be especially be interested in reports on any bugs you may find, 106 | however I cannot promise to reply. 107 | 108 | .nf 109 | Ken Kundert 110 | Dept. of Electrical Engineering and Computer Sciences 111 | University of California 112 | Berkeley, California 94720 113 | June 1988 114 | 115 | sparse@ic.berkeley.edu 116 | ucbvax!ic!sparse 117 | -------------------------------------------------------------------------------- /src/fasthenry/mulGlobal.c: -------------------------------------------------------------------------------- 1 | /* # ***** sort to /src/main 2 | # ***** */ 3 | #include "mulGlobal.h" 4 | 5 | long memcount; /* allocated memory counter */ 6 | long memQ2M; /* allocated memory counters by function */ 7 | long memQ2L; 8 | long memQ2P; 9 | long memL2L; 10 | long memM2M; 11 | long memM2L; 12 | long memM2P; 13 | long memL2P; 14 | long memQ2PD; 15 | long memMSC; 16 | long memIND; 17 | 18 | #ifdef MATTDEBUG 19 | long membins[1001]; 20 | #endif 21 | 22 | /* 23 | global timer and operation count accumulators 24 | */ 25 | double prectime; /* time spent doing back solve for prec */ 26 | double prsetime; /* time spent calculating preconditioner */ 27 | double conjtime; /* time spent doing everything but A*q */ 28 | double dirtime; /* time for direct part of P*q */ 29 | double multime; /* time for multipole part of P*q */ 30 | double uptime; /* time in mulUp(), upward pass */ 31 | double downtime; /* time in mulDown(), downward pass */ 32 | double evaltime; /* time in mulEval(), evaluation pass */ 33 | int fulldirops; /* total direct operations - DIRSOL=ON only */ 34 | double lutime; /* factorization time DIRSOL=ON only */ 35 | double fullsoltime; /* time for solves, DIRSOL=ON only */ 36 | int fullPqops; /* total P*q ops using P on disk - EXPGCR=ON */ 37 | 38 | /* 39 | misc global 40 | */ 41 | NAME *start_name = NULL; /* conductor name linked list head */ 42 | NAME *current_name; /* conductor name linked list tail */ 43 | NAME *start_name_this_time; /* cond name list for the current surface */ 44 | char *kill_name_list; /* cond names whose columns are omitted */ 45 | ITER *kill_num_list; /* cond numbers whose columns are omitted */ 46 | char *kinp_name_list; /* cond names omitted from input */ 47 | ITER *kinp_num_list; /* cond numbers omitted from input */ 48 | char *qpic_name_list; /* cond column names that get q picture */ 49 | ITER *qpic_num_list; /* cond column names that get q picture */ 50 | char *kq_name_list; /* cond names removed from q picture */ 51 | ITER *kq_num_list; /* cond numbers removed from q picture */ 52 | 53 | int num_dielec_panels; /* number of dielectric interface panels */ 54 | int num_both_panels; /* number of thin-cond-on-dielec-i/f panels */ 55 | int num_cond_panels; /* number of thick conductor panels */ 56 | int up_size; /* sum of above three (real panels) */ 57 | int num_dummy_panels; /* number of off-panel eval pnt panels */ 58 | int eval_size; /* sum of above two (total panel structs) */ 59 | double iter_tol; /* iterative loop tolerence on ||r|| */ 60 | 61 | /* 62 | command line option variables - all have to do with ps file dumping 63 | */ 64 | #if CAPVEW == ON /* eliminate messy globals if not needed */ 65 | char **argvals; /* copy of argv */ 66 | int argcnt; /* copy of argc */ 67 | int s_; /* TRUE => insert showpage in .ps file(s) */ 68 | int n_; /* TRUE => number faces with input ordering */ 69 | int g_; /* TRUE => dump depth graph and quit */ 70 | int c_; /* TRUE => print command line on .ps file(s) */ 71 | int x_; /* TRUE => axes have been specified */ 72 | int k_; 73 | int rc_; /* TRUE => rm conductors in list from pic */ 74 | int rd_; /* TRUE => remove all dielec i/fs from pic */ 75 | int rb_; /* TRUE => rm BOTH-types in list from pic */ 76 | int q_; /* TRUE => dump shaded plots of q_iter iters */ 77 | int rk_; /* TRUE => rm chg den key in -q plots */ 78 | int m_; /* TRUE => switch to plot gen mode */ 79 | int f_; /* TRUE => don't fill faces (no hidden l rm) */ 80 | int dd_; /* TRUE => dump ttl charges to .ps pictures */ 81 | double view[3]; /* absolute view point of 3D geometry */ 82 | double moffset[2]; /* image offset from lower left corner */ 83 | double elevation; /* elevation of view rel to center of object */ 84 | double azimuth; /* azimuth of view rel to center of object */ 85 | double rotation; /* image rotation, degrees */ 86 | double distance; /* relative distance from center (#radii-1) */ 87 | double linewd; /* postscript line width */ 88 | double scale; /* over all image scale factor */ 89 | double axeslen; /* axes lengths in 3D distance */ 90 | double axes[10][2][3]; /* the 2d image of the coordinate axes */ 91 | int up_axis; /* X,Y or Z => which axis is vertical in pic */ 92 | char *line_file; /* pointer to .fig superimposed line file */ 93 | char *ps_file_base; /* pointer to base name for .ps files */ 94 | #endif 95 | -------------------------------------------------------------------------------- /src/fasthenry/bigmeshPre_direct.c: -------------------------------------------------------------------------------- 1 | /* this preconditions the 2 | /* This preconditions one row. It is mostly a duplicate of indPrecond() 3 | code from olmulPrcond() */ 4 | 5 | #include "induct.h" 6 | #define PARTMESH OFF 7 | 8 | /* This near picks up only the hamming distance one cubes. */ 9 | #define HNEAR(nbr, nj, nk, nl) \ 10 | ((ABS((nbr)->j - (nj)) + ABS((nbr)->k - (nk)) + ABS((nbr)->l - (nl))) <= 1) 11 | 12 | /* This near picks up all 27 neighboring cubes. */ 13 | #define NEAR(nbr, nj, nk, nl) \ 14 | ((ABS((nbr)->j - (nj)) <= 1) && \ 15 | (ABS((nbr)->k - (nk)) <= 1) && \ 16 | (ABS((nbr)->l - (nl)) <= 1)) 17 | 18 | /* This near picks only the diagonal, for testing. */ 19 | #define DNEAR(nbr, nj, nk, nl) \ 20 | (((nbr)->j == (nj)) && \ 21 | ((nbr)->k == (nk)) && \ 22 | ((nbr)->l == (nl)) ) 23 | 24 | FILE *fp; 25 | 26 | bigmesh_direct(sys, indsys, w) 27 | ssystem *sys; 28 | SYS *indsys; 29 | double w; 30 | { 31 | cube *nc, *nnbr, *nnnbr; 32 | int nsize, nnsize; 33 | charge **nc_pc, **nnbr_pc; 34 | int meshmax = 0, *meshnum; 35 | CX **meshmat = NULL; 36 | int *filcount = NULL, *is_in_nc, *maxfilcount, *indx; 37 | int num_mesh = indsys->num_mesh; 38 | int filnum, i, j, k, nj, nk, nl; 39 | MELEMENT *mtran; 40 | MELEMENT **Mtrans = indsys->Mtrans; 41 | MELEMENT **Mlist = indsys->Mlist; 42 | PRE_ELEMENT **Precond = indsys->Precond; 43 | PRE_ELEMENT *pre, *prelast; 44 | int meshsize, realmrow; 45 | int counter; 46 | int debug = 0; 47 | CX **MtZM = indsys->MtZM; 48 | 49 | meshsize = count_tree_meshes(indsys->trees); 50 | 51 | if (meshsize > meshmax) { 52 | CALLOC(meshmat, meshsize + 10, CX*, ON, IND); 53 | for(i = 0; i < meshsize + 10; i++) 54 | CALLOC(meshmat[i], meshsize + 10, CX, ON, IND); 55 | meshmax = meshsize + 10; 56 | } 57 | 58 | /* conveniently, all the bigmeshes (tree meshes) are at the front of Mlist */ 59 | for(i = 0; i < meshsize; i++) 60 | for(j = 0; j < meshsize; j++) 61 | meshmat[i][j] = MtZM[i][j]; 62 | 63 | if (indsys->opts->debug == ON) { 64 | fprintf(stdout, "For big meshes:\n"); 65 | fprintf(stdout, "Inverting a %d x %d matrix\n",meshsize,meshsize); 66 | } 67 | 68 | /* now invert meshmat and skip duplicate rows and cols */ 69 | cx_invert(meshmat, meshsize); 70 | 71 | if (debug == 1) { 72 | savecmplx(fp, "after", meshmat, meshsize, meshsize); 73 | fclose(fp); 74 | } 75 | 76 | #if 1==0 /* the stupid way (adding to what is there) */ 77 | /* add the rows (don't overwrite what's there) to the preconditioner */ 78 | for(i = 0; i < meshsize; i++) { 79 | 80 | prelast = NULL; 81 | for(j = 0, pre = Precond[i]; j < meshsize; j++) { 82 | if (is_in_Precond(Precond[i], j, &prelast) == 0) { 83 | CALLOC(pre, 1, PRE_ELEMENT, ON, IND); 84 | pre->meshcol = j; 85 | pre->value = meshmat[i][j]; 86 | if (prelast == NULL) { 87 | pre->next = Precond[i]; 88 | Precond[i] = pre; 89 | } 90 | else { 91 | pre->next = prelast->next; 92 | prelast->next = pre; 93 | } 94 | } 95 | } 96 | } 97 | #endif 98 | 99 | /* add the rows to the preconditioner */ 100 | for(i = 0; i < meshsize; i++) { 101 | 102 | Precond[i] = NULL; /* a quick dumb solution */ 103 | 104 | if (Precond[i] == NULL) { 105 | CALLOC(Precond[i], 1, PRE_ELEMENT, ON, IND); 106 | Precond[i]->next = NULL; 107 | } 108 | prelast = NULL; 109 | for(j = 0, pre = Precond[i]; j < meshsize; j++) { 110 | if (pre == NULL) { 111 | CALLOC(pre, 1, PRE_ELEMENT, ON, IND); 112 | pre->next = NULL; 113 | if (prelast == NULL) { 114 | fprintf(stderr, "Hey, prelast is null!\n"); 115 | exit(1); 116 | } 117 | prelast->next = pre; 118 | } 119 | 120 | pre->meshcol = j; 121 | pre->value = meshmat[i][j]; 122 | prelast = pre; 123 | pre = pre->next; 124 | } 125 | } 126 | 127 | } 128 | 129 | is_in_Precond(prelist, col, last) 130 | PRE_ELEMENT *prelist, **last; 131 | int col; 132 | { 133 | if (prelist == NULL) { 134 | *last = NULL; 135 | return 0; 136 | } 137 | 138 | if (prelist->meshcol == col) 139 | return 1; 140 | else if (prelist->meshcol > col) { 141 | *last = NULL; 142 | return 0; 143 | } 144 | else { 145 | while(prelist->next != NULL && prelist->next->meshcol < col) 146 | prelist = prelist->next; 147 | 148 | if (prelist->next->meshcol == col) 149 | return 1; 150 | else { 151 | *last = prelist; 152 | return 0; 153 | } 154 | } 155 | } 156 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /src/fasthenry/savemat_mod.c: -------------------------------------------------------------------------------- 1 | /* 2 | * savemat - C language routine to save a matrix in a MAT-file. 3 | * 4 | * We recommend that you use this routine, and its companion loadmat.c, 5 | * for all writing and reading of MAT-files. These routines implement 6 | * "access methods" for MAT-files. By using these routines, instead 7 | * of writing your own code to directly access the MAT-file format, 8 | * you will be unaffected by any changes that may be made to the MAT-file 9 | * structure at a future date. 10 | * 11 | * Here is an example that uses 'savemat' to save two matrices to disk, 12 | * the second of which is complex: 13 | * 14 | * FILE *fp; 15 | * double xyz[1000], ar[1000], ai[1000]; 16 | * fp = fopen("foo.mat","wb"); 17 | * savemat(fp, 2000, "xyz", 2, 3, 0, xyz, (double *)0); 18 | * savemat(fp, 2000, "a", 5, 5, 1, ar, ai); 19 | * fclose(fp); 20 | * 21 | * Author J.N. Little 11-3-86 22 | * Revised 7-23-91 to support ANSI-C 23 | */ 24 | #include 25 | // Enrico 26 | #include 27 | 28 | #ifdef ALPHA 29 | typedef struct { 30 | int type; /* type */ 31 | int mrows; /* row dimension */ 32 | int ncols; /* column dimension */ 33 | int imagf; /* flag indicating imag part */ 34 | int namlen; /* name length (including NULL) */ 35 | } Fmatrix; 36 | #else 37 | typedef struct { 38 | long type; /* type */ 39 | long mrows; /* row dimension */ 40 | long ncols; /* column dimension */ 41 | long imagf; /* flag indicating imag part */ 42 | long namlen; /* name length (including NULL) */ 43 | } Fmatrix; 44 | #endif 45 | 46 | #ifdef __STDC__ 47 | void savemat(FILE *fp, int type, char *pname, int mrows, int ncols, 48 | int imagf, double *preal, double *pimag) 49 | #else 50 | void savemat(fp, type, pname, mrows, ncols, imagf, preal, pimag) 51 | FILE *fp; /* File pointer */ 52 | int type; /* Type flag: Normally 0 for PC, 1000 for Sun, Mac, */ 53 | /* Apollo, and other Motorola format, */ 54 | /* 2000 for VAX D-float, 3000 for VAX G-float, and */ 55 | /* 4000 for CRAY */ 56 | /* Add 1 for text variables, 2 for sparse matrices */ 57 | /* See LOAD in reference section of guide for more info.*/ 58 | char *pname; /* pointer to matrix name */ 59 | int mrows; /* row dimension */ 60 | int ncols; /* column dimension */ 61 | int imagf; /* imaginary flag */ 62 | double *preal; /* pointer to real data */ 63 | double *pimag; /* pointer to imag data */ 64 | #endif 65 | { 66 | Fmatrix x; 67 | int mn; 68 | 69 | x.type = type; 70 | x.mrows = mrows; 71 | x.ncols = ncols; 72 | x.imagf = imagf; 73 | x.namlen = strlen(pname) + 1; 74 | mn = x.mrows * x.ncols; 75 | 76 | fwrite(&x, sizeof(Fmatrix), 1, fp); 77 | fwrite(pname, sizeof(char), (int)x.namlen, fp); 78 | fwrite(preal, sizeof(double), mn, fp); 79 | if (imagf) { 80 | fwrite(pimag, sizeof(double), mn, fp); 81 | } 82 | } 83 | 84 | /* 85 | MODIFIED version of above: added wr_flag to allow multiple writes 86 | to same matrix 87 | wr_flag = 0 => open, print header (like old matlab setup) 88 | wr_flag = 1 => update, print without header 89 | Doesn't work for complex. For complex, full real part must precede 90 | full imaginary. 91 | */ 92 | #ifdef __STDC__ 93 | void savemat_mod(FILE *fp, int type, char *pname, int mrows, int ncols, 94 | int imagf, double *preal, double *pimag, int wr_flag, int mn) 95 | #else 96 | void savemat_mod(fp, type, pname, mrows, ncols, imagf, preal, pimag, 97 | wr_flag, mn) 98 | FILE *fp; /* File pointer */ 99 | int type; /* Type flag: Normally 0 for PC, 1000 for Sun, Mac, */ 100 | /* Apollo, and other Motorola format, */ 101 | /* 2000 for VAX D-float, 3000 for VAX G-float, and */ 102 | /* 4000 for CRAY */ 103 | /* Add 1 for text variables, 2 for sparse matrices */ 104 | /* See LOAD in reference section of guide for more info.*/ 105 | char *pname; /* pointer to matrix name */ 106 | int mrows; /* row dimension */ 107 | int ncols; /* column dimension */ 108 | int imagf; /* imaginary flag */ 109 | double *preal; /* pointer to real data */ 110 | double *pimag; /* pointer to imag data */ 111 | int wr_flag; /* 0 for open, 1 to add to matrix */ 112 | int mn; /* real #entries, this dump only */ 113 | #endif 114 | { 115 | Fmatrix x; 116 | 117 | if(wr_flag == 0) { 118 | x.type = type; 119 | x.mrows = mrows; 120 | x.ncols = ncols; 121 | x.imagf = imagf; 122 | x.namlen = strlen(pname) + 1; 123 | 124 | fwrite(&x, sizeof(Fmatrix), 1, fp); 125 | fwrite(pname, sizeof(char), (int)x.namlen, fp); 126 | } 127 | fwrite(preal, sizeof(double), mn, fp); 128 | /* if (imagf) { 129 | fwrite(pimag, sizeof(double), mn, fp); 130 | } 131 | */ 132 | } 133 | -------------------------------------------------------------------------------- /src/fasthenry/Prec_cost.c: -------------------------------------------------------------------------------- 1 | /* these are functions used in mulSetup.c in determining whether to go down */ 2 | /* further in partitioning levels */ 3 | 4 | #include "induct.h" 5 | 6 | /* this function estimates the size of the matrix which will be inverted 7 | for this cube for the preconditioner. Since M has not been formed, and 8 | the size of the preconditioner is based on meshes, not filaments/charges, 9 | it will estimate that there is one mesh per normal filament and one mesh for 10 | every two ground plane filaments. Thus the number of meshes in a cube 11 | is cube->multisize/2. 12 | */ 13 | 14 | double OneCubeCost(cubes, i,j,k,l,side, dir_cost) 15 | cube *****cubes; 16 | int i,j,k,l,side; 17 | double *dir_cost; 18 | { 19 | int m,n,p; 20 | double total, dir_total, this_size; 21 | 22 | this_size = cubes[i][j][k][l]->upnumeles[0]; 23 | 24 | total = dir_total = 0; 25 | for(m=j-2; m <=j+2; m++) 26 | for(n=k-2; n <=k+2; n++) 27 | for(p=l-2; p <=l+2; p++) 28 | if ( (m >= 0) && (n >= 0) && (p >= 0) 29 | && (m < side) && (n < side) && (p < side) 30 | && (cubes[i][m][n][p] != NULL) ) { 31 | dir_total += cubes[i][m][n][p]->upnumeles[0]; 32 | if (abs(m-j) < 2 && abs(n-k) < 2 && abs(p-l) < 2) 33 | total += cubes[i][m][n][p]->multisize/2.0; 34 | } 35 | 36 | *dir_cost += this_size*dir_total; 37 | 38 | return total*total*total; 39 | } 40 | 41 | double ratio_of_divided_segs(length,charges,indsys) 42 | double length; 43 | charge *charges; 44 | SYS *indsys; 45 | { 46 | SEGMENT *seg; 47 | int totalfils = 0, broken = 0; 48 | double rat; 49 | 50 | if (indsys->opts->auto_refine == OFF) 51 | return 0.0; 52 | 53 | for(seg = indsys->segment; seg != NULL; seg = seg->next) { 54 | totalfils += seg->num_fils; 55 | if (seg->length > length) { 56 | broken += seg->num_fils; 57 | } 58 | } 59 | 60 | rat = (double)broken/(double)totalfils; 61 | if (indsys->opts->debug == ON) 62 | fprintf(stdout, "To be broken ratio: %lg\n", rat); 63 | return rat; 64 | } 65 | 66 | is_gp_charge(chg) 67 | charge *chg; 68 | { 69 | if (chg->fil->segm->node[0]->gp == NULL) 70 | return FALSE; 71 | else 72 | return TRUE; 73 | } 74 | 75 | add_to_counts(nc, cols, evals, cnts) 76 | cube *nc; 77 | int cols, *****evals, *****cnts; 78 | { 79 | cube *na; 80 | 81 | for(na = nc; na != NULL; na = na->parent) 82 | cnts[na->level][na->j][na->k][na->l] += cols*nc->upnumeles[0]; 83 | 84 | evals[nc->level][nc->j][nc->k][nc->l] += 1; 85 | na = nc->parent; 86 | if (na != NULL) 87 | evals[na->level][na->j][na->k][na->l] += 1; 88 | } 89 | 90 | #if 1 == 0 91 | dump_evalcnts(sys) 92 | ssystem *sys; 93 | { 94 | cube *****cubes = sys->cubes; 95 | int i,j,k,m,side; 96 | cube *nc, *na; 97 | 98 | printf(" cube parent Q2P L2P M2P\n"); 99 | printf(" lvl j,k,l j,k,l cubes size_mats cubes size_mats cubes size_mats\n"); 100 | 101 | for(side = 1, i=0; i <= sys->depth; side *= 2, i++) { 102 | for(j=0; j < side; j++) { 103 | for(k=0; k < side; k++) { 104 | for(m = 0; m < side; m++) { 105 | nc = cubes[i][j][k][m]; 106 | if (nc != NULL) { 107 | na = nc->parent; 108 | if (na == NULL) 109 | na = nc; 110 | printf("%3i %3i %3i %3i %3i %3i %3i %3d %10d %3d %10d %3d %10d\n", 111 | i, nc->j, nc->k, nc->l, na->j, na->k, na->l, 112 | sys->evalQ2Ps[i][j][k][m], sys->cntQ2Ps[i][j][k][m], 113 | sys->evalL2Ps[i][j][k][m], sys->cntL2Ps[i][j][k][m], 114 | sys->evalM2Ps[i][j][k][m], sys->cntM2Ps[i][j][k][m]); 115 | } 116 | } 117 | } 118 | } 119 | } 120 | } 121 | 122 | initCounters(sys) 123 | ssystem *sys; 124 | { 125 | int *****make_ints_for_cubes(); 126 | 127 | sys->evalQ2Ps = make_ints_for_cubes(sys); 128 | sys->evalL2Ps = make_ints_for_cubes(sys); 129 | sys->evalM2Ps = make_ints_for_cubes(sys); 130 | sys->cntQ2Ps = make_ints_for_cubes(sys); 131 | sys->cntL2Ps = make_ints_for_cubes(sys); 132 | sys->cntM2Ps = make_ints_for_cubes(sys); 133 | } 134 | 135 | int *****make_ints_for_cubes(sys) 136 | ssystem *sys; 137 | { 138 | int *****cubes; 139 | int i,j,k,m,side; 140 | 141 | CALLOC(cubes, sys->depth+1, int****, ON, AMSC); 142 | 143 | /* allocate for levels 0, 1, and 2 (always used) */ 144 | for(side = 1, i=0; i <= sys->depth; side *= 2, i++) { 145 | CALLOC(cubes[i], side, int***, ON, AMSC); 146 | for(j=0; j < side; j++) { 147 | CALLOC(cubes[i][j], side, int**, ON, AMSC); 148 | for(k=0; k < side; k++) { 149 | CALLOC(cubes[i][j][k], side, int*, ON, AMSC); 150 | for(m = 0; m < side; m++) 151 | cubes[i][j][k][m] = 0; 152 | } 153 | } 154 | } 155 | 156 | return cubes; 157 | } 158 | #endif 159 | -------------------------------------------------------------------------------- /src/fasthenry/sparse/spRevision: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * REVISION HISTORY 4 | * 5 | * Author: 6 | * Kenneth S. Kundert 7 | * University of California at Berkeley 8 | * College of Engineering 9 | * Department of Electrical Engineering and Computer Science 10 | * 11 | * Advising professor: 12 | * Alberto Sangiovanni-Vincentelli 13 | * 14 | * 15 | * Sparse is available for a $150.00 charge. The package includes the 16 | * source code on tape, the user's guide and a paper that discusses techniques 17 | * for solving sparse systems of equations [1]. To obtain a copy of Sparse, 18 | * send a check or money order payable to the Regents of the University of 19 | * California to: 20 | * 21 | * EECS Industrial Liaison Program 22 | * Cindy Manly 23 | * University of California 24 | * Berkeley, CA 94720 25 | * 26 | * Please allow four weeks for delivery. 27 | * 28 | * The University often does not have the resources to consult with 29 | * users on how to use or modify these programs. We would, however, like 30 | * to be notified of any problems or errors in the material provided and 31 | * appreciate copies on tape of any troublesome matrices. If the program 32 | * is enhanced or converted to run on other systems, we would like to receive 33 | * copies of the modified program so that it can be made available to the 34 | * public. 35 | * 36 | * References 37 | * [1] Kenneth S. Kundert. Sparse matrix techniques. In "Circuit Analysis, 38 | * Simulation and Design," vol. 3, pt. 1, Albert E. Ruehli (editor). 39 | * North-Holland, 1986. 40 | */ 41 | 42 | /* 43 | * Copyright information. 44 | * 45 | * Copyright (c) 1985,86,87,88 46 | * by Kenneth S. Kundert and the University of California. 47 | * 48 | * Permission to use, copy, modify, and distribute this software and its 49 | * documentation for any purpose and without fee is hereby granted, provided 50 | * that the above copyright notice appear in all copies and supporting 51 | * documentation and that the authors and the University of California 52 | * are properly credited. The authors and the University of California 53 | * make no representations as to the suitability of this software for 54 | * any purpose. It is provided `as is', without express or implied warranty. 55 | */ 56 | 57 | /* 58 | * >>> Current revision information: 59 | * $Author: kundert $ 60 | * $Date: 85/12/10 21:03:02 $ 61 | * $Revision: 2.2 $ 62 | */ 63 | 64 | 65 | 66 | 67 | 68 | 69 | /* 70 | * >>> History: 71 | * Revision 1.1 January 1985 72 | * Initial release. 73 | * 74 | * Revision 1.1a 20 March 1985 75 | * Modified DecomposeMatrix() and OrderAndDecomposeMatrix() so that 76 | * the parameters Growth, PseudoCondition and LargestElement may be 77 | * given as NULL. 78 | * 79 | * Revision 1.1b 28 March 1985 80 | * Corrected a bug that caused OrderAndDecomposeMatrix() to reorder 81 | * the matrix every time it was called. Also made many of the global 82 | * variables defined in MtrxDecom.c static. 83 | * 84 | * Revision 1.2 October 1985 85 | * This new version of Sparse is meant to make it more compatible 86 | * with interactive circuit simulators. In it the TRANSLATE 87 | * option was added, along with the ability to access the matrix 88 | * with AddElementToMatrix() and AddAdmittanceToMatrix() after it 89 | * has been reordered. Also added were the DeleteRowAndColFromMatrix(), 90 | * CleanMatrix(), GetMatrixSize(), SetMatrixReal() and SetMatrixComplex() 91 | * routines. 92 | * 93 | * Revision 1.2a April 1986 94 | * Fixed a bug that caused the matrix frame to get freed twice and one 95 | * in the test program that caused sparse to crash when a complex matrix 96 | * with no source vector was attempted. 97 | * 98 | * Revision 1.2b July 1986 99 | * Modified the test routine so that it allocates vectors from the heap 100 | * rather than the stack. 101 | * 102 | * Revision 1.2c February 1987 103 | * Fixed off-by-one error in PreorderForModifiedNodal(). 104 | * 105 | * Revision 1.2d 106 | * Modified the pivot selection algorithm so that singletons also meet 107 | * numerical threshold criterion. Deleted some global variables. Modified 108 | * test program to add command line options among other things. Made 109 | * thresholds sticky, so that once a valid threshold has been specified 110 | * for a particular matrix, it becomes the new default. 111 | * 112 | * Revision 1.3a July 1988 113 | * Made numerous changes. Highlights are: 114 | * Routine names shortened and made unique to 8 characters. 115 | * Unordering factorization is faster. 116 | * Added self initialization feature. 117 | * Sparse now aborts on errors that should not occur. 118 | * Cleaned up test program. 119 | * Separated growth and pseudocondition calculations from factorization. 120 | * Added LINPACK condition number estimator. 121 | * Rewrote spMNA_Preorder, algorithm extended to fix inadequacies. 122 | * Eliminated all global variables. 123 | * Added DIAGONAL_PIVOTING option (only diagonal pivoting before). 124 | */ 125 | -------------------------------------------------------------------------------- /README.mit: -------------------------------------------------------------------------------- 1 | FastHenry 3.0.1 information. 2 | 3 | Updated May 28th 2012 by FastFieldSolvers, www.fastfieldsolvers.com 4 | 5 | FastHenry is a program for the efficient extraction of inductances and 6 | resistances of complex 3-D geometries of conductors. 7 | 8 | Configuring for your machine: 9 | 10 | 1. Change to the fasthenry-3.0 directory 11 | 12 | prompt % cd fasthenry-3.0 13 | 14 | 2. Configure for your machine (sets the compilation flags) 15 | 16 | SunOS 4.x, IBM RS 6000's, and other 4.2/3 BSD systems(?): 17 | prompt % config default 18 | 19 | DEC 5000s: 20 | prompt % config dec 21 | 22 | DEC Alphas: 23 | prompt % config alpha 24 | 25 | Silicon Graphics: 26 | prompt % config sgi 27 | and then read the extra instructions in README.sgi 28 | 29 | Linux: 30 | prompt % config default 31 | 32 | prompt % config x64 33 | to force compile for x86 64bit machines 34 | 35 | System V operating systems: 36 | 37 | Sun Solaris: 38 | 39 | prompt % config solaris 40 | 41 | Hewlett-Packard HP-UX, and other System V operating systems: 42 | This has not been thoroughly tested. 43 | 44 | prompt % config sysV 45 | 46 | Notes: 47 | 48 | a. For Versions of solaris before 2.5, The "ranlib" command is obsolete and 49 | doesn't exist. 50 | Either remove the ranlib command from src/fasthenry/sparse/Makefile 51 | or define a null ranlib command in your path or do "make -k all" 52 | 53 | b. In the linking stage, if you get an error that "gethostname" 54 | is undefined, then add "-DNO_GETHOSTNAME" to the CFLAGS line in 55 | src/fasthenry/Makefile and src/zbuf/Makefile after doing config. 56 | For instance 57 | 58 | CFLAGS = -O -DFIVE -DNO_GETHOSTNAME 59 | 60 | 61 | Compiling: 62 | 63 | prompt % cd fasthenry-3.0.1 64 | prompt % make all 65 | 66 | produces the executables: fasthenry-3.0.1/bin/fasthenry 67 | fasthenry-3.0.1/bin/zbuf 68 | fasthenry-3.0.1/bin/ReadOutput 69 | fasthenry-3.0.1/bin/MakeLcircuit 70 | 71 | If you want to save space after "make all", 72 | 73 | prompt % make clean 74 | 75 | will clean up *.o and *.a files. 76 | 77 | Documentation: 78 | 79 | The manuals are in Acrobat Reader pdf format in the directory 'doc' 80 | 81 | ------------------------------------------------------------- 82 | Major changes in 3.0.1 since version 3.0 83 | 84 | - Added various stability bug fixes over original 3.0 distribution 85 | 86 | - Added stability improvement under Linux 87 | 88 | - Added various includes and other minor updates to avoid warnings 89 | with latest versions of GCC 90 | 91 | - Updated source code to compile on 64 bit machines 92 | 93 | - Added Makefile option for 64 bit machines 94 | 95 | ------------------------------------------------------------- 96 | Major changes in 3.0 since version 2.5 97 | 98 | - Specify a nonuniform discretization of a reference plane to 99 | capture small features in fewer elements. 100 | 101 | - Two approaches for generating spice equivalent circuits are available: 102 | 103 | 1. An equivalent circuit for a single frequency. 104 | 105 | 2. A circuit which models the frequency 106 | dependent resistances and inductances through a reduced state-space 107 | representation 108 | 109 | Comments: Method 1 will not model frequency dependent resistance 110 | and inductance since it gives and R and L at the single specified 111 | frequency. Method 2 will model the full effects up to some frequency. 112 | 113 | - Major Bug fix: 114 | For reference planes which form segments with different 115 | widths in the x-direction versus the Y direction, the sizes weren't 116 | computed correctly in version 2.0 and above. This has been fixed. 117 | 118 | 119 | - The zbuf program now takes the ``-m'' argument to produce a 120 | Matlab file for faster visualization in matlab. This is very beneficial for 121 | large files since producing the postscript file can take $n^2$ time. 122 | The matlab file can be viewed within matlab with the 123 | fasthenry-3.0/bin/plotfastH.m matlab function. The file 124 | zbuffile.mat would be produced with ``zbuf -m zbuffile'' which can 125 | then be viewed in matlab with ``>> plotfastH('zbuffile.mat')''. 126 | Also, you can modify the file src/zbuf/dump_struct.c to output in YOUR own 127 | format instead of matlab. 128 | 129 | - Sparse preconditioner. Specify -p shells to use a 130 | preconditioner based on Byron Krauter's sparse inductance technique. 131 | 132 | - Regurgitate the input file with -v to see what FastHenry 133 | thinks it has read. Also can translate and reflect geometry before output. 134 | 135 | ------------------------------------------------------------- 136 | 137 | Changes since Version 1.0 138 | 139 | Version 1.5: 140 | 141 | 1. Better filament mutual inductance approximation for very thin segments. 142 | 2. Ability to specify ground plane holes. See example hole.inp and 143 | some of the comments toward the end of the file hole.c (I have 144 | not had a chance to update the manual.) 145 | 3. Other command line options. (Give an erroneous option at the command line 146 | to see the added options) 147 | 4. Some bug fixes. 148 | 149 | 150 | Version 2.0 - this is a far improvement over the past versions 151 | 152 | In summary: 153 | 1. A better preconditioner which allows efficient analysis of 154 | reference planes. 155 | 2. Accurate modeling with thin filaments. 156 | 3. More detailed manual 157 | 4. Many, many other features 158 | 159 | 160 | ----------------------------------------------------------------- 161 | 162 | -------------------------------------------------------------------------------- /src/fasthenry/regurgitate.c: -------------------------------------------------------------------------------- 1 | /* This regurgitates the input file to the output with some 2 | translations and replications if desired */ 3 | /* It outputs in SI units only */ 4 | 5 | #include "induct.h" 6 | 7 | void regurgitate(indsys) 8 | SYS *indsys; 9 | { 10 | /* functions to shift coordinates */ 11 | void translate(), reflect_x(), reflect_y(), reflect_origin(), do_nothing(); 12 | 13 | /* spit out geometries and .externals */ 14 | spit(indsys, do_nothing, ""); 15 | 16 | /* 17 | spit(indsys, reflect_x, "_X"); 18 | spit(indsys, reflect_y, "_Y"); 19 | spit(indsys, reflect_origin, "_XY"); 20 | */ 21 | 22 | do_end_stuff(indsys); 23 | } 24 | 25 | do_end_stuff(indsys) 26 | SYS *indsys; 27 | { 28 | fprintf(stdout, ".freq fmin=%lg fmax=%lg ndec=%lg\n",indsys->fmin, 29 | indsys->fmax, 1.0/indsys->logofstep); 30 | 31 | fprintf(stdout, ".end\n"); 32 | 33 | } 34 | 35 | 36 | 37 | static double delta_x, delta_y, delta_z; 38 | 39 | /* set amount of translation for translate() */ 40 | set_translate(x, y, z) 41 | double x, y, z; 42 | { 43 | delta_x = x; 44 | delta_y = y; 45 | delta_z = z; 46 | } 47 | 48 | void translate(x,y,z,new_x, new_y, new_z) 49 | double x,y,z,*new_x, *new_y, *new_z; 50 | { 51 | *new_x = x + delta_x; 52 | *new_y = y + delta_y; 53 | *new_z = z + delta_z; 54 | } 55 | 56 | /* reflect about x axis (negate y) */ 57 | void reflect_x(x,y,z,new_x, new_y, new_z) 58 | double x,y,z,*new_x, *new_y, *new_z; 59 | { 60 | *new_x = x; 61 | *new_y = -y; 62 | *new_z = z; 63 | } 64 | 65 | /* reflect about y axis (negate x) */ 66 | 67 | void reflect_y(x,y,z,new_x, new_y, new_z) 68 | double x,y,z,*new_x, *new_y, *new_z; 69 | { 70 | *new_x = -x; 71 | *new_y = y; 72 | *new_z = z; 73 | } 74 | 75 | /* reflect about origin (negate x and y) */ 76 | 77 | void reflect_origin(x,y,z,new_x, new_y, new_z) 78 | double x,y,z,*new_x, *new_y, *new_z; 79 | { 80 | *new_x = -x; 81 | *new_y = -y; 82 | *new_z = z; 83 | } 84 | 85 | void do_nothing(x,y,z,new_x, new_y, new_z) 86 | double x,y,z,*new_x, *new_y, *new_z; 87 | { 88 | *new_x = x; 89 | *new_y = y; 90 | *new_z = z; 91 | } 92 | 93 | 94 | /* spit out nodes and segments and .externals */ 95 | 96 | spit(indsys, new_coords, suffix) 97 | SYS *indsys; 98 | void (*new_coords)(); 99 | char *suffix; 100 | { 101 | 102 | NODES *node; 103 | NODELIST *nodel; 104 | SEGMENT *seg; 105 | GROUNDPLANE *gp; 106 | EXTERNAL *ext; 107 | int i; 108 | double x,y,z; 109 | 110 | /* do nodes */ 111 | fprintf(stdout, "* NODES for %s\n",suffix); 112 | for(node = indsys->nodes; node != NULL; node = node->next) { 113 | if (node->type == NORMAL) { 114 | new_coords(node->x, node->y, node->z, &x, &y, &z); 115 | fprintf(stdout, "%s%s x=%lg y=%lg z=%lg\n", node->name, suffix, x, y, z); 116 | } 117 | } 118 | 119 | /*do segments */ 120 | fprintf(stdout, "* Segments for %s\n",suffix); 121 | for(seg = indsys->segment; seg != NULL; seg = seg->next) { 122 | if (seg->type == NORMAL) { 123 | fprintf(stdout, "%s%s %s%s %s%s w=%lg h=%lg nhinc=%d nwinc=%d rw=%lg rh=%lg sigma=%lg", 124 | seg->name, suffix, seg->node[0]->name, suffix, 125 | seg->node[1]->name, suffix, seg->width, 126 | seg->height, seg->hinc, 127 | seg->winc, seg->r_width, seg->r_height, seg->sigma); 128 | if (seg->widthdir != NULL) 129 | fprintf(stdout, " wx=%lg wy=%lg wz=%lg \n", seg->widthdir[XX], 130 | seg->widthdir[YY], seg->widthdir[ZZ]); 131 | else 132 | fprintf(stdout, "\n"); 133 | } 134 | } 135 | 136 | /*do planes */ 137 | fprintf(stdout, "* Planes for %s\n",suffix); 138 | for(gp = indsys->planes; gp != NULL; gp = gp->next) { 139 | 140 | if (is_nonuni_gp(gp)) { 141 | fprintf(stdout, "Nonuniform planes not supported for regurgitation at this time!\n"); 142 | continue; 143 | } 144 | 145 | fprintf(stdout, "%s%s \n",gp->name, suffix); 146 | i = 0; 147 | new_coords(gp->x[i], gp->y[i], gp->z[i], &x, &y, &z); 148 | fprintf(stdout, "+ x1=%lg y1=%lg z1=%lg\n",x, y, z); 149 | 150 | i = 1; 151 | new_coords(gp->x[i], gp->y[i], gp->z[i], &x, &y, &z); 152 | fprintf(stdout, "+ x2=%lg y2=%lg z2=%lg\n",x, y, z); 153 | 154 | i = 2; 155 | new_coords(gp->x[i], gp->y[i], gp->z[i], &x, &y, &z); 156 | fprintf(stdout, "+ x3=%lg y3=%lg z3=%lg\n",x, y, z); 157 | 158 | fprintf(stdout, "+ seg1=%d seg2=%d\n", gp->seg1, gp->seg2); 159 | fprintf(stdout, "+ thick=%lg ", gp->thick); 160 | fprintf(stdout, "segwid1=%lg segwid2=%lg ", gp->segwid1, gp->segwid2); 161 | fprintf(stdout, "sigma=%lg\n", gp->sigma); 162 | 163 | for(nodel = gp->usernode_coords; nodel != NULL; nodel=nodel->next) { 164 | fprintf(stdout, "+ %s (%lg, %lg, %lg)\n", nodel->name, nodel->x, 165 | nodel->y, nodel->z); 166 | } 167 | 168 | if (gp->list_of_holes != NULL) 169 | fprintf(stdout, "Holes cannot be regurgitated at this time!\n"); 170 | 171 | } 172 | 173 | /* do .equivs */ 174 | fprintf(stdout, "* .equivs for %s\n",suffix); 175 | for(node = indsys->nodes; node != NULL; node = node->next) { 176 | if (node->type == NORMAL && node != getrealnode(node)) { 177 | fprintf(stdout, ".equiv %s%s %s%s\n", node->name, suffix, 178 | getrealnode(node)->name, suffix); 179 | } 180 | } 181 | 182 | /* do .externals */ 183 | 184 | for(ext = indsys->externals; ext != NULL; ext = ext->next) { 185 | fprintf(stdout, ".external %s%s %s%s ", 186 | getrealnode(ext->source->node[0])->name, suffix, 187 | getrealnode(ext->source->node[1])->name, suffix); 188 | if (strcmp(ext->portname,"") != 0) 189 | fprintf(stdout, "%s%s\n",ext->portname, suffix); 190 | else 191 | fprintf(stdout, "\n"); 192 | } 193 | } 194 | 195 | 196 | 197 | 198 | -------------------------------------------------------------------------------- /src/fasthenry/deg_mutual.c: -------------------------------------------------------------------------------- 1 | /* This file contains functions for computing the mutual inductance 2 | between fils which have one or more degenerate dimensions. For example, 3 | it's width = 10^4 * height */ 4 | 5 | #include "induct.h" 6 | 7 | #define LEN 4 8 | #define WID 2 9 | #define HEIGHT 1 10 | 11 | enum degen_type find_deg_dims(fil) 12 | FILAMENT *fil; 13 | { 14 | double max; 15 | 16 | max = MAX(fil->length, fil->width); 17 | max = MAX(max, fil->height); 18 | 19 | return (fil->length/max < DEG_TOL)*LEN + (fil->width/max < DEG_TOL)*WID 20 | + (fil->height/max < DEG_TOL)*HEIGHT; 21 | } 22 | 23 | double compute_for_degenerate(fil_j, fil_m, whperp, x_j, y_j, 24 | deg_j, deg_m, dist) 25 | FILAMENT *fil_j, *fil_m; 26 | int whperp; 27 | double *x_j, *y_j; /* unit vectors in the fil coord sys */ 28 | enum degen_type deg_j, deg_m; 29 | double dist; 30 | { 31 | 32 | FILAMENT nfil_j, nfil_m; /* new temp fils */ 33 | double *nx_j, *ny_j; 34 | 35 | if (deg_j == brick && deg_m == brick) { 36 | /* neither is degenerate, this shouldn't happen */ 37 | fprintf(stderr,"Hey, compute_degenerate was called, impossible!\n"); 38 | exit(1); 39 | } 40 | 41 | if ((deg_j == flat || deg_j == skinny)&&(deg_m == flat || deg_m == skinny)){ 42 | setup_tape_to_tape(fil_j,fil_m,whperp,x_j,y_j,deg_j,deg_m, 43 | &nfil_j,&nfil_m, &nx_j, &ny_j); 44 | return exact_mutual(&nfil_j, &nfil_m, whperp, nx_j, ny_j, deg_j, deg_m); 45 | } 46 | else if ( deg_m == brick && (deg_j == flat || deg_j == skinny) 47 | || deg_j == brick && (deg_m == flat || deg_m == skinny)) 48 | return do_tape_to_brick(fil_j, fil_m, whperp, x_j, y_j, deg_j, deg_m); 49 | else if ( deg_j == too_long && deg_m == too_long) 50 | return fourfil(fil_j, fil_m); 51 | else if (deg_j == too_long || deg_j == too_long) 52 | return fourfil(fil_j, fil_m); 53 | else 54 | return fourfil(fil_j, fil_m); 55 | 56 | } 57 | 58 | setup_tape_to_tape(fil_j, fil_m, whperp, x_j, y_j, deg_j, deg_m, 59 | nfil_j, nfil_m, nx_j, ny_j) 60 | FILAMENT *fil_j, *fil_m, *nfil_j, *nfil_m; 61 | int whperp; 62 | double *x_j, *y_j, **nx_j, **ny_j; /* unit vectors in the fil coord sys */ 63 | enum degen_type deg_j, deg_m; 64 | { 65 | 66 | if (deg_j == flat) { 67 | *nfil_j = *fil_j; 68 | *nfil_m = *fil_m; 69 | *nx_j = x_j; 70 | *ny_j = y_j; 71 | } 72 | else if (deg_j == skinny) { 73 | /* turn skinny into flat orientation */ 74 | *nfil_j = *fil_j; 75 | *nfil_m = *fil_m; 76 | /* swap coord sys */ 77 | *ny_j = x_j; 78 | *nx_j = y_j; 79 | /* swap height and width */ 80 | nfil_j->width = fil_j->height; 81 | nfil_j->height = fil_j->width; 82 | nfil_m->width = fil_m->height; 83 | nfil_m->height = fil_m->width; 84 | } 85 | } 86 | 87 | double do_tape_to_brick(fil_j, fil_m, whperp, x_j, y_j, deg_j, deg_m) 88 | FILAMENT *fil_j, *fil_m; 89 | int whperp; 90 | double *x_j, *y_j; /* unit vectors in the fil coord sys */ 91 | enum degen_type deg_j, deg_m; 92 | { 93 | 94 | FILAMENT nfil_j, nfil_m; 95 | double *nx_j, *ny_j, *dR; 96 | double wid_brick[3], hei_brick[3], orig_x[2], orig_y[2], orig_z[2]; 97 | double x_flat[3], y_flat[3]; 98 | double small_dim, sum; 99 | int i,j,gpoints; 100 | extern double **Gweight, **Gpoint; /* gaussian quad weights. */ 101 | enum degen_type ndeg_j, ndeg_m; 102 | 103 | /* 104 | if ( deg_m == brick && (deg_j == flat || deg_j == skinny) 105 | || deg_j == brick && (deg_m == flat || deg_m == skinny)) 106 | return do_tape_to_brick(fil_j, fil_m, whperp, x_j, y_j, deg_j, deg_m); 107 | */ 108 | 109 | if (deg_j == flat) { 110 | nfil_j = *fil_j; 111 | nfil_m = *fil_m; 112 | nx_j = x_j; 113 | ny_j = y_j; 114 | get_wid(fil_m,wid_brick); 115 | get_height(fil_m,wid_brick,hei_brick); 116 | } 117 | else if (deg_j == skinny) { 118 | /* turn skinny into flat orientation */ 119 | nfil_j = *fil_j; 120 | nfil_m = *fil_m; 121 | /* swap coord sys */ 122 | ny_j = x_j; 123 | nx_j = y_j; 124 | /* swap height and width */ 125 | nfil_j.width = fil_j->height; 126 | nfil_j.height = fil_j->width; 127 | nfil_m.width = fil_m->height; 128 | nfil_m.height = fil_m->width; 129 | /* get them swapped */ 130 | get_wid(fil_m,hei_brick); 131 | get_height(fil_m,hei_brick,wid_brick); 132 | } 133 | else if (deg_j == brick) { 134 | /* swap j and m */ 135 | nfil_j = *fil_m; 136 | nfil_m = *fil_j; 137 | get_wid(fil_m,x_flat); 138 | get_height(fil_m,x_flat,y_flat); 139 | 140 | if (deg_m == flat) { 141 | nx_j = x_flat; 142 | ny_j = y_flat; 143 | for(i = 0; i < 3; i++) { 144 | wid_brick[i] = x_j[i]; 145 | hei_brick[i] = y_j[i]; 146 | } 147 | 148 | } 149 | else { 150 | nx_j = y_flat; 151 | ny_j = x_flat; 152 | nfil_j.width = fil_m->height; 153 | nfil_j.height = fil_m->width; 154 | nfil_m.width = fil_j->height; 155 | nfil_m.height = fil_j->width; 156 | for(i = 0; i < 3; i++) { 157 | wid_brick[i] = y_j[i]; 158 | hei_brick[i] = x_j[i]; 159 | } 160 | 161 | } 162 | } 163 | 164 | /* store original brick position */ 165 | for(i = 0; i < 2; i++) { 166 | orig_x[i] = nfil_m.x[i]; 167 | orig_y[i] = nfil_m.y[i]; 168 | orig_z[i] = nfil_m.z[i]; 169 | } 170 | 171 | if (nfil_m.width > nfil_m.height) { 172 | /* the height direction will be done discretely */ 173 | small_dim = nfil_m.height/2; 174 | nfil_m.height = 0; 175 | dR = hei_brick; 176 | if (whperp == 0) /* useful for testing only. if forced == 1 */ 177 | ndeg_m = flat; 178 | else 179 | ndeg_m = skinny; 180 | } 181 | else { 182 | /* the width direction will be done discretely */ 183 | small_dim = nfil_m.width/2; 184 | nfil_m.width = 0; 185 | dR = wid_brick; 186 | if (whperp == 0) 187 | ndeg_m = skinny; 188 | else 189 | ndeg_m = flat; 190 | } 191 | 192 | /* if forced == 1, then setting ndeg_j matters */ 193 | ndeg_j = flat; 194 | nfil_j.height = 0.0; /* insure we use the middle of filament x-section*/ 195 | 196 | gpoints = 3; 197 | /* now do gaussian quadrature of tape_to_tape to approximate */ 198 | sum = 0; 199 | for(i = 0; i < gpoints; i++) { 200 | for(j = 0; j < 2; j++) { 201 | nfil_m.x[j] = orig_x[j] + dR[XX]*small_dim*Gpoint[gpoints][i]; 202 | nfil_m.y[j] = orig_y[j] + dR[YY]*small_dim*Gpoint[gpoints][i]; 203 | nfil_m.z[j] = orig_z[j] + dR[ZZ]*small_dim*Gpoint[gpoints][i]; 204 | } 205 | sum += Gweight[gpoints][i]*exact_mutual(&nfil_j, &nfil_m, whperp, 206 | nx_j, ny_j, ndeg_j, ndeg_m); 207 | } 208 | 209 | return sum/2.0; 210 | } 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | -------------------------------------------------------------------------------- /src/fasthenry/BreakupSeg.c: -------------------------------------------------------------------------------- 1 | /* this breaks a segment that is too long, into many shorter segments */ 2 | #include "induct.h" 3 | 4 | #define DIVFACT 1 /* a factor that is always 1 except for debugging */ 5 | 6 | DivideSegs(length, charges, indsys, is_initial) 7 | double length; 8 | charge *charges; 9 | SYS *indsys; 10 | int is_initial; /* is this the initial refinement call */ 11 | { 12 | SEGMENT *seg; 13 | int warned, warn_refine; 14 | 15 | warned = warn_refine = 0; 16 | 17 | for(seg = indsys->segment; seg != NULL; seg = seg->next) { 18 | if (seg->length > length/DIVFACT) { 19 | if (indsys->opts->auto_refine == ON || is_initial == TRUE) { 20 | if (seg->type == NORMAL) 21 | BreakupSeg(seg, length/DIVFACT, charges, indsys); 22 | else if (!warned) { 23 | fprintf(stdout, "DivideSegs: Warning: tried to divide an indivisable segment.\n"); 24 | fprintf(stdout, " Segment length: %lf, maximum allowed length: %lf", 25 | seg->length, length/DIVFACT); 26 | fprintf(stdout, " The segment is probably part of a ground plane.\n"); 27 | fprintf(stdout, " If so, decrease the partitioning level by 1 or refine the ground plane\n"); 28 | warned = 1; 29 | } 30 | } 31 | else if (!warn_refine) { 32 | warn_refine = 1; 33 | if (indsys->opts->mat_vect_prod == MULTIPOLE) 34 | fprintf(stdout, "Warning: couldn't refine segments as needed because auto_refine == OFF.\n This will decrease multipole accuracy.\n"); 35 | } 36 | 37 | } 38 | } 39 | } 40 | 41 | BreakupSeg(seg, maxlength, charges, indsys) 42 | SEGMENT *seg; 43 | double maxlength; 44 | charge *charges; 45 | SYS *indsys; 46 | { 47 | double oldlength, x, y, z, dx, dy, dz; 48 | int i, j, pieces; 49 | NODES *node0, *node1, *node; 50 | SEGMENT *newseg, *lastseg, *condseg, *origsegnext; 51 | charge *chg; 52 | NODES *nodelast, *newnode; 53 | NODES *makenode(); 54 | static char name[80 + MAXDEP*3]; 55 | charge *chgend; 56 | charge *oldnext; 57 | charge *assignFil(); 58 | NPATH *apath; 59 | SPATH *condpath, *lastpath, *headpath, *condbeg, *condend; 60 | int backwards; 61 | 62 | oldlength = seg->length; 63 | pieces = seg->length/maxlength + 1; 64 | 65 | // Enrico, commented line because length 66 | // is re-calculated later, see bug fix 67 | //seg->length = seg->length/pieces; 68 | origsegnext = seg->next; 69 | 70 | node0 = seg->node[0]; 71 | node1 = seg->node[1]; 72 | 73 | dx = (node1->x - node0->x)/ pieces; 74 | dy = (node1->y - node0->y)/ pieces; 75 | dz = (node1->z - node0->z)/ pieces; 76 | 77 | nodelast = node0; 78 | sprintf(name, "%s_0",node0->name); 79 | x = nodelast->x + dx; 80 | y = nodelast->y + dy; 81 | z = nodelast->z + dz; 82 | 83 | // Enrico, bug fix 84 | // The following piece of code has a potential numerical problem. 85 | // The problem arises when 'node0', 'node1' end points coordinates 86 | // are big numbers, but the segment length is small. 87 | // In this case, breaking up the segment, the new length of the first 88 | // sub-segment was calculated 89 | // with 'seg->length = seg->length/pieces;' (see above), while the new 90 | // end points coodinates by calculating 'dx', 'dy', 'dz' (small) and 91 | // adding them to 'node0->x', 'node0->y', 'node0->z' (big). 92 | // A possible fix would be: x = node0->x + dx = 93 | // = node0->x + (node1->x - node0->x)/ pieces = (node0->x*(pieces-1) + node1->x) / pieces; 94 | // but since all new sub-segments nodes positions are calculated starting 95 | // from 'dx', 'dy', 'dz' it is more straightforward to re-calculate 96 | // the length, as it is done for all sub-segments but the first one 97 | // later on by 'makeseg()'. 98 | // Note that this bug caused the problems in 'joelself.c', see the bug 99 | // fix in 'exact_mutual()', since there the segment length was again 100 | // calculated (indirectly, as a projection) but starting from the nodes 101 | // positions and then compared with the length stored in 'seg->length' 102 | seg->length = sqrt( (node0->x - x)*(node0->x - x) 103 | + (node0->y - y)*(node0->y - y) 104 | + (node0->z - z)*(node0->z - z) ); 105 | // 106 | // end of bug fix 107 | // 108 | 109 | if (nodelast->type != NORMAL) { 110 | printf("Internal bug. nodelast->type != NORMAL\n"); 111 | exit(1); 112 | } 113 | 114 | newnode = makenode(name, indsys->num_nodes++, x, y, z, nodelast->type, NULL); 115 | newnode->next = node0->next; 116 | node0->next = newnode; 117 | 118 | remove_from_connected_segs(seg->node[1], seg, NULL); 119 | seg->node[1] = newnode; 120 | add_to_connected_segs(newnode, seg, NULL); 121 | 122 | alterFils(seg, newnode, dx, dy, dz); /* modify the segment's fils */ 123 | 124 | lastseg = seg; 125 | nodelast = newnode; 126 | chgend = seg->filaments[seg->num_fils-1].pchg; 127 | oldnext = chgend->next; 128 | for(i = 1; i < pieces; i++) { 129 | 130 | if (i != pieces - 1) { 131 | x = nodelast->x + dx; 132 | y = nodelast->y + dy; 133 | z = nodelast->z + dz; 134 | sprintf(name, "%s_%d",node0->name, i); 135 | newnode = makenode(name, indsys->num_nodes++, x, y, z, nodelast->type, 136 | NULL); 137 | newnode->next = nodelast->next; 138 | nodelast->next = newnode; 139 | 140 | if (nodelast->type != NORMAL) { 141 | printf("Internal bug. nodelast->type != NORMAL\n"); 142 | exit(1); 143 | } 144 | 145 | } 146 | else 147 | newnode = node1; 148 | 149 | sprintf(name, "%s_%d",seg->name,i); 150 | newseg = makeseg(name, nodelast, newnode, seg->height, seg->width, 151 | seg->sigma, seg->hinc, seg->winc, seg->r_height, 152 | seg->r_width, seg->widthdir, 153 | indsys->num_segs++, NORMAL, NULL); 154 | 155 | newseg->next = lastseg->next; 156 | lastseg->next = newseg; 157 | 158 | chgend = assignFil(newseg, &(indsys->num_fils), chgend); 159 | 160 | lastseg = newseg; 161 | nodelast = newnode; 162 | 163 | } /* for(i = pieces..) */ 164 | chgend->next = oldnext; 165 | 166 | } 167 | 168 | alterFils(seg, node, dx, dy, dz) 169 | SEGMENT *seg; 170 | NODES *node; 171 | double dx, dy, dz; 172 | { 173 | FILAMENT *fil; 174 | charge *chg; 175 | int i; 176 | 177 | for(i = 0; i < seg->num_fils; i++) { 178 | fil = &(seg->filaments[i]); 179 | fil->x[1] = fil->x[0] + dx; 180 | fil->y[1] = fil->y[0] + dy; 181 | fil->z[1] = fil->z[0] + dz; 182 | fil->length = seg->length; 183 | fil->lenvect[XX] = fil->x[1] - fil->x[0]; 184 | fil->lenvect[YY] = fil->y[1] - fil->y[0]; 185 | fil->lenvect[ZZ] = fil->z[1] - fil->z[0]; 186 | chg = fil->pchg; 187 | chg->max_diag = chg->min_diag = fil->length; 188 | chg->x = (fil->x[0] + fil->x[1])/2.0; 189 | chg->y = (fil->y[0] + fil->y[1])/2.0; 190 | chg->z = (fil->z[0] + fil->z[1])/2.0; 191 | } 192 | } 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | -------------------------------------------------------------------------------- /src/fasthenry/mulDo.c: -------------------------------------------------------------------------------- 1 | /* # ***** sort to /src/main 2 | # ***** */ 3 | #include "mulGlobal.h" 4 | 5 | #if OPCNT == ON 6 | static directops=0, upops=0, downops=0, evalops=0, evaldops=0, evalmops=0; 7 | #endif 8 | 9 | /* 10 | Compute the direct piece. 11 | */ 12 | mulDirect(sys) 13 | ssystem *sys; 14 | { 15 | int i, j, k, dsize, *is_dummy, *is_dielec; 16 | double pc, *p, *q, *qn, *pn, **mat; 17 | cube *nextc; 18 | 19 | /* Assumes the potential vector has been zero'd!!!! */ 20 | for(nextc=sys->directlist; nextc != NULL; nextc = nextc->dnext) { 21 | dsize = nextc->directnumeles[0]; /* Equals number of charges. */ 22 | q = nextc->directq[0]; 23 | p = nextc->eval; 24 | is_dummy = nextc->nbr_is_dummy[0]; 25 | is_dielec = nextc->is_dielec; 26 | /* Inside Cube piece. */ 27 | mat = nextc->directmats[0]; 28 | for(j = dsize - 1; j >= 0; j--) { 29 | #if NUMDPT == 2 30 | if(is_dielec[j]) continue; 31 | #endif 32 | for(k = dsize - 1; k >= 0; k--) { 33 | if(!is_dummy[k]) p[j] += mat[j][k] * q[k]; 34 | #if OPCNT == ON 35 | directops++; 36 | #endif 37 | } 38 | } 39 | /* Through all nearest nbrs. */ 40 | for(i=nextc->directnumvects - 1; i > 0; i--) { 41 | mat = nextc->directmats[i]; 42 | qn = nextc->directq[i]; 43 | is_dummy = nextc->nbr_is_dummy[i]; 44 | for(j = dsize - 1; j >= 0; j--) { 45 | #if NUMDPT == 2 46 | if(is_dielec[j]) continue; 47 | #endif 48 | for(k = nextc->directnumeles[i] - 1; k >= 0; k--) { 49 | if(!is_dummy[k]) p[j] += mat[j][k] * qn[k]; 50 | #if OPCNT == ON 51 | directops++; 52 | #endif 53 | } 54 | } 55 | } 56 | } 57 | } 58 | 59 | /* 60 | Block diagonal or Overlapped Preconditioner. 61 | */ 62 | mulPrecond(sys, type) 63 | ssystem *sys; 64 | int type; 65 | { 66 | int i, j, k, dsize, *is_dummy; 67 | double pc, *p, *q, *qn, *pn, **mat; 68 | cube *nc; 69 | 70 | if(type == BD) { 71 | for(nc=sys->precondlist; nc != NULL; nc = nc->pnext) { 72 | solve(nc->precond, nc->prevectq, nc->prevectq, nc->presize); 73 | } 74 | } 75 | else { 76 | /* Assumes the potential vector has been zero'd!!!! */ 77 | for(nc=sys->directlist; nc != NULL; nc = nc->dnext) { 78 | dsize = nc->directnumeles[0]; /* Equals number of charges. */ 79 | q = nc->directq[0]; 80 | p = nc->eval; 81 | is_dummy = nc->nbr_is_dummy[0]; 82 | /* Inside Cube piece. */ 83 | mat = nc->precondmats[0]; 84 | for(j = dsize - 1; j >= 0; j--) { 85 | for(k = dsize - 1; k >= 0; k--) { 86 | if(!is_dummy[k]) p[j] += mat[j][k] * q[k]; 87 | } 88 | } 89 | /* Through all nearest nbrs. */ 90 | for(i=nc->directnumvects - 1; i > 0; i--) { 91 | mat = nc->precondmats[i]; 92 | is_dummy = nc->nbr_is_dummy[i]; 93 | if(mat != NULL) { 94 | qn = nc->directq[i]; 95 | for(j = dsize - 1; j >= 0; j--) { 96 | for(k = nc->directnumeles[i] - 1; k >= 0; k--) { 97 | if(!is_dummy[k]) p[j] += mat[j][k] * qn[k]; 98 | } 99 | } 100 | } 101 | } 102 | } 103 | /* Copy ps back to qs and zero ps. */ 104 | for(nc=sys->directlist; nc != NULL; nc = nc->dnext) { 105 | dsize = nc->directnumeles[0]; /* Equals number of charges. */ 106 | q = nc->directq[0]; 107 | p = nc->eval; 108 | for(j = dsize - 1; j >= 0; j--) { 109 | q[j] = p[j]; 110 | p[j] = 0.0; 111 | } 112 | } 113 | } 114 | } 115 | 116 | 117 | /* 118 | Loop through upward pass. 119 | */ 120 | mulUp(sys) 121 | ssystem *sys; 122 | { 123 | int i, j, k, l; 124 | int msize; 125 | double *multi, *rhs, **mat; 126 | cube *nextc; 127 | 128 | if(sys->depth < 2) return; /* ret if upward pass not possible/worth it */ 129 | 130 | /* Through all the depths, starting from the bottom and not doing top. */ 131 | for(i = sys->depth; i > 0; i--) { 132 | /* Through all the cubes at depth. */ 133 | for(nextc=sys->multilist[i]; nextc != NULL; nextc = nextc->mnext) { 134 | msize = nextc->multisize; 135 | multi = nextc->multi; 136 | for(j=0; j < msize; j++) multi[j] = 0; 137 | /* Through all the nonempty children of cube. */ 138 | for(j=nextc->upnumvects - 1; j >= 0; j--) { 139 | mat = nextc->upmats[j]; 140 | rhs = nextc->upvects[j]; 141 | for(k = nextc->upnumeles[j] - 1; k >= 0; k--) { 142 | for(l = msize - 1; l >= 0; l--) { 143 | multi[l] += mat[l][k] * rhs[k]; 144 | #if OPCNT == ON 145 | upops++; 146 | #endif 147 | } 148 | } 149 | } 150 | } 151 | } 152 | } 153 | 154 | 155 | /* 156 | evaluation pass - use after mulDown or alone. 157 | */ 158 | void mulEval(sys) 159 | ssystem *sys; 160 | { 161 | int i, j, k, size, *is_dielec; 162 | cube *nc; 163 | double *eval, **mat, *vec; 164 | 165 | if(sys->depth < 2) return; /* ret if upward pass not possible/worth it */ 166 | 167 | for(nc = sys->directlist; nc != NULL; nc = nc->dnext) { 168 | size = nc->upnumeles[0]; /* number of eval pnts (chgs) in cube */ 169 | eval = nc->eval; /* vector of evaluation pnt potentials */ 170 | is_dielec = nc->is_dielec; /* vector of DIELEC/BOTH panel flags */ 171 | 172 | /* do the evaluations */ 173 | for(i = nc->evalnumvects - 1; i >= 0; i--) { 174 | if (nc->eval_isQ2P[i] == sys->DirectEval) { /* added 12/92 MK */ 175 | mat = nc->evalmats[i]; 176 | vec = nc->evalvects[i]; 177 | for(j = size - 1; j >= 0; j--) { 178 | #if NUMDPT == 2 179 | if(is_dielec[j]) continue; 180 | #endif 181 | for(k = nc->evalnumeles[i] - 1; k >= 0; k--) { 182 | eval[j] += mat[j][k] * vec[k]; 183 | #if OPCNT == ON 184 | evalops++; 185 | if (sys->DirectEval == TRUE) 186 | evaldops++; 187 | else if (sys->DirectEval == FALSE) 188 | evalmops++; 189 | else 190 | {printf("huh?"); exit(1);} 191 | #endif 192 | } 193 | } 194 | } 195 | } 196 | } 197 | } 198 | 199 | /* 200 | Loop through downward pass. 201 | */ 202 | mulDown(sys) 203 | ssystem *sys; 204 | { 205 | cube *nc; 206 | int depth, i, j, k, lsize; 207 | double **mat, *rhs, *local; 208 | 209 | if(sys->depth < 2) return; /* ret if upward pass not possible/worth it */ 210 | 211 | for(depth=2; depth <= sys->depth; depth++) { 212 | for(nc=sys->locallist[depth]; nc != NULL; nc = nc->lnext) { 213 | lsize = nc->localsize; 214 | local = nc->local; 215 | for(j=0; j < lsize; j++) local[j] = 0; 216 | /* Through all the locals for the cube. */ 217 | for(i=nc->downnumvects - 1; i >= 0; i--) { 218 | mat = nc->downmats[i]; 219 | rhs = nc->downvects[i]; 220 | for(j = lsize - 1; j >= 0; j--) { 221 | for(k = nc->downnumeles[i] - 1; k >= 0; k--) { 222 | local[j] += mat[j][k] * rhs[k]; 223 | #if OPCNT == ON 224 | downops++; 225 | #endif 226 | } 227 | } 228 | } 229 | } 230 | } 231 | } 232 | 233 | 234 | #if OPCNT == ON 235 | printops() 236 | { 237 | printf("Number of Direct Multi-Adds = %d\n", directops); 238 | printf("Number of Upward Pass Multi-Adds = %d\n", upops); 239 | printf("Number of Downward Pass Multi-Adds = %d\n", downops); 240 | printf("Number of Evaluation Pass Multi-Adds = %d\n", evalops); 241 | printf("Number of Evaluation Pass Direct Multi-Adds = %d\n", evaldops); 242 | printf("Number of Evaluation Pass Other Multi-Adds = %d\n", evalmops); 243 | printf("Total Number of Multi-Adds = %d\n", directops+upops+downops+evalops); 244 | } 245 | #endif 246 | -------------------------------------------------------------------------------- /examples/trace.test.release: -------------------------------------------------------------------------------- 1 | Comparisons for using the "contact trace" utility 2 | 3 | This gives results verifying the "contact trace" and "contact connection" 4 | utilities. 5 | 6 | We wish to use the trace and connection utilities 7 | to match known results. Particularly, we want to see if defining a diagonal 8 | trace maintains the good results. 9 | 10 | Each section below gives the modifications to the original input file 11 | given at the bottom of this document. 12 | 13 | A. using decay_rect for everything (as in Summer96/comparision/3d_example2.inp) 14 | (4884 elements, 135 sec (level 5) on alpha/ocelot)) 15 | Row 1: ns1 to np1 16 | Impedance matrix for frequency = 3.3e+08 1 x 1 17 | 3.75027 +3.16843j 18 | 19 | B. Using the trace utility for the trace: 20 | (3690 elements, 242 secs (level 4) on Alpha) 21 | 22 | *+ contact decay_rect (0,0,0,50,2000,13,3000,500,3000) 23 | + contact trace (0,-1000,0,0,1000,0,26,1) 24 | 25 | Row 1: ns1 to np1 26 | Impedance matrix for frequency = 3.3e+08 1 x 1 27 | 3.74841 +3.16417j 28 | 29 | C. Using the connection utility also: 30 | (2604 elements, 76 seconds) 31 | *+ contact decay_rect (0,-1000,0,30,30,10,10,3000,3000) 32 | *+ contact decay_rect (0, 1000,0,30,30,10,10,3000,3000) 33 | + contact connection np1 (0,-1000,0,30,30,2.5) 34 | + contact connection np2 (0, 1000,0,30,30,2.5) 35 | *+ np1 (0,-1000,0) 36 | *+ np2 (0,1000,0) 37 | 38 | Row 1: ns1 to np1 39 | Impedance matrix for frequency = 3.3e+08 1 x 1 40 | 3.63203 +3.16448j 41 | 42 | Resistance has dropped as expected since we are now forcing all 43 | nodes under the connection to be at the same potential. 44 | 45 | D. More accurately trying to capture contact: 46 | 3714 elements, level 4, 244 secs 47 | 48 | + contact connection np1 (0,-1000,0,26,26,3) 49 | + contact connection np2 (0, 1000,0,26,26,3) 50 | 51 | Row 1: ns1 to np1 52 | Impedance matrix for frequency = 3.3e+08 1 x 1 53 | 3.62884 +3.16465j 54 | 55 | 56 | E. Let's try a diagonal trace of same dimension (note ratio=2.5 for this one) 57 | 9790 filaments, level 7!, 110 seconds 58 | 59 | A diagonal trace takes many more elements since we can't exploit 60 | the slow change in current along the direction of current flow 61 | since its not along the x or y axis. 62 | 63 | + contact trace (-707.1,-707.1,0,707.1,707.1,0,26,1) 64 | + contact connection np1 (-707.1,-707.1,0,26,26,2.5) 65 | + contact connection np2 (707.1, 707.1,0,26,26,2.5) 66 | 67 | NS1 x=-707.1 y=-707.1 z=223.5 68 | NS2 x=707.1 y=707.1 z=223.5 69 | 70 | Row 1: ns1 to np1 71 | Impedance matrix for frequency = 3.3e+08 1 x 1 72 | 3.64035 +3.18872j 73 | 74 | Hmm, accuracy could be because multipole went down to level 7 for some 75 | reason. 76 | 77 | F. Let;s try same as E above, but manually ask for a coarser discretization 78 | below trace at 45 degrees 79 | 80 | + contact trace (-707.1,-707.1,0,707.1,707.1,0,26,10) 81 | 82 | 2736 elements, level 4, 123 secs 83 | 84 | Row 1: ns1 to np1 85 | Impedance matrix for frequency = 3.3e+08 1 x 1 86 | 3.6437 +3.16781j 87 | 88 | Odd, quite accurate. Perhaps we are lucky. See trial H. 89 | 90 | G. Let's do E, but run it with "-l 5" to force level 5 91 | 9484 fils, 426 sec 92 | 93 | Row 1: ns1 to np1 94 | Impedance matrix for frequency = 3.3e+08 1 x 1 95 | 3.64923 +3.18364j 96 | 97 | Not much different from E 98 | 99 | H. How much can we play with the scale factor before this makes 100 | a difference (scale factor = 20) 101 | 102 | + contact trace (-707.1,-707.1,0,707.1,707.1,0,26,20) 103 | 104 | 2308 fils, 115 seconds level 4 105 | 106 | Row 1: ns1 to np1 107 | Impedance matrix for frequency = 3.3e+08 1 x 1 108 | 3.63131 +3.17088j 109 | 110 | Ok, so it's gone back up again, so it is probably luck that F was accurate. 111 | Still a surprisingly 112 | small effect, probably because Si is so resistive and 330MHz isn't 113 | that high a frequency. Let's pick a higher frequency. 33 GHz: 114 | 115 | I. do the above comparisions for f=33GHz 116 | 133 secs. 117 | 118 | .freq fmin=3.3e10 fmax=3.3e10 ndec=1 119 | 120 | I1. For trial D, with ratio=2.5 (scale = 1, trace in y direction) 121 | 2946 fils, 157 secs 122 | 123 | + contact trace (0,-1000,0,0,1000,0,26,1) 124 | + contact connection np1 (0,-1000,0,26,26,2.5) 125 | + contact connection np2 (0, 1000,0,26,26,2.5) 126 | NS1 x=0 y=-1000 z=223.5 127 | NS2 x=0 y=1000 z=223.5 128 | *NS1 x=-707.1 y=-707.1 z=223.5 129 | *NS2 x=707.1 y=707.1 z=223.5 130 | 131 | Row 1: ns1 to np1 132 | Impedance matrix for frequency = 3.3e+10 1 x 1 133 | 12.7711 +205.346j 134 | 135 | I2.Trying the above with some extra discretization along length (decay_rect) 136 | + contact decay_rect (0,0,0,26,2000,13,100,500,3000) 137 | *+ contact trace (0,-1000,0,0,1000,0,26,1) 138 | 139 | Row 1: ns1 to np1 140 | Impedance matrix for frequency = 3.3e+10 1 x 1 141 | 12.7465 +205.59j 142 | 143 | Seems to be good results. 144 | 145 | 146 | I3. Diagonal trace: For scale=20 (trial H at 33GHz, (trace diagonal)) 147 | 148 | + contact trace (-707.1,-707.1,0,707.1,707.1,0,26,20) 149 | 150 | Row 1: ns1 to np1 151 | Impedance matrix for frequency = 3.3e+10 1 x 1 152 | 11.1734 +213.896j 153 | 154 | I4.For scale=10 (trial F at 33GHz) 155 | 145 secs 156 | 157 | + contact trace (-707.1,-707.1,0,707.1,707.1,0,26,10) 158 | 159 | Row 1: ns1 to np1 160 | Impedance matrix for frequency = 3.3e+10 1 x 1 161 | 12.5388 +207.403j 162 | 163 | I5.For scale=1 (trial E) 164 | 314 sec, 60 iters, level 7 165 | 166 | + contact trace (-707.1,-707.1,0,707.1,707.1,0,26,1) 167 | 168 | Row 1: ns1 to np1 169 | Impedance matrix for frequency = 3.3e+10 1 x 1 170 | 9.77926 +217.875j 171 | 172 | 173 | ************************************************************ 174 | ** So big question: Why does the diagonal trace give better results 175 | ** when the scale factor is 10 rather than 1??? 176 | ** (compare I1 to I5 vs. I1 to I4 for f=33GHz and 177 | ** B to E vs B to F for f=330MHz) 178 | ** The higher scale factor is enlarging elements which should lead to less 179 | ** accurate results. However when 180 | ** the scale factor goes to 20, results seem to deviate again. 181 | ************************************************************ 182 | 183 | 184 | * same as Summer96/comparison/3d_example2.inp but using the "contact trace" 185 | * 186 | * a M5 line (26um wide, 1um thick) over Si substrate 8um below, sigma=2.6e7 187 | * 430um thick substrate, sigma=1.5e4 1/(ohm*m) 188 | * line length=1000um 189 | .units uM 190 | * 191 | * Define substrate, sigma=1.5e4 1/(m*ohm)= 0.015 1/(um*ohm) 192 | g1 x1 = -1500 y1 = -1500 z1 = 0 193 | + x2 = 1500 y2 = -1500 z2 = 0 194 | + x3 = 1500 y3 = 1500 z3 = 0 195 | + thick = 430 sigma= 0.015 196 | *+ seg1 = 100 seg2 = 100 197 | + file=NONE 198 | * under the trace 199 | *+ contact decay_rect (0,0,0,50,2000,13,3000,500,3000) 200 | + contact trace (0,-1000,0,0,1000,0,26,1) 201 | * the contacts 202 | + contact decay_rect (0,-1000,0,30,30,10,10,3000,3000) 203 | + contact decay_rect (0, 1000,0,30,30,10,10,3000,3000) 204 | + 205 | + nhinc = 3 rh=2 206 | * nodes to reference later: 207 | + np1 (0,-1000,0) 208 | + np2 (0,1000,0) 209 | * 210 | * line width=26um 211 | * thick h=1um sigma=2.6e7 1/(m*ohm)=26 1/(um*ohm) 212 | * 213 | NS1 x=0 y=-1000 z=223.5 214 | NS2 x=0 y=1000 z=223.5 215 | EM5 NS1 NS2 w=26 h=1 sigma=26 nwinc=4 nhinc=1 216 | .equiv NS2 np2 217 | .external NS1 np1 218 | * 219 | .freq fmin=3.3e8 fmax=3.3e8 ndec=1 220 | .end 221 | -------------------------------------------------------------------------------- /src/fasthenry/SetupComputePsi.c: -------------------------------------------------------------------------------- 1 | /* this sets up the vectors to call Fastcap's ComputePsi */ 2 | /* It will be called twice for each coordinate direction. Once for real 3 | and once for imaginary */ 4 | 5 | #include "induct.h" 6 | 7 | /* Vs will contain the result, Im is the 'q', Size is the size of vectors. */ 8 | /* This will alter Im. Im = Precond*Im */ 9 | SetupComputePsi(Vs, sys, Im, size, chglist, w, R, indsys) 10 | CX *Vs, *Im; 11 | int size; 12 | ssystem *sys; 13 | charge *chglist; 14 | double w; /* radian frequency */ 15 | double *R; /* resistance vector */ 16 | SYS *indsys; 17 | { 18 | extern double dirtime; 19 | double *q, *p; 20 | static CX *Ib = NULL, *Vb = NULL, *Vdirect = NULL, *ctemp; 21 | int branches; 22 | CX temp; 23 | MELEMENT *mtemp; 24 | charge *chg; 25 | int i, j; 26 | double rtemp; 27 | MELEMENT **Mtrans, **Mlist; 28 | double maxdiff,pdiff; 29 | int maxindx; 30 | int ind_opcnt_mult = 0, ind_opcnt_real = 0; 31 | 32 | branches = indsys->num_fils; 33 | Mtrans = indsys->Mtrans; 34 | Mlist = indsys->Mlist; 35 | 36 | if (Ib == NULL) { 37 | Ib = (CX *)MattAlloc(branches, sizeof(CX)); 38 | Vb = (CX *)MattAlloc(branches, sizeof(CX)); 39 | ctemp = (CX *)MattAlloc(size, sizeof(CX)); 40 | #ifndef NODEBUG 41 | Vdirect = (CX *)MattAlloc(branches, sizeof(CX)); 42 | #endif 43 | } 44 | 45 | for(i = 0; i < branches; i++) 46 | Vb[i] = CXZERO; 47 | 48 | q = sys->q; 49 | p = sys->p; 50 | ASSERT(size == indsys->num_mesh); 51 | 52 | if (indsys->precond_type == LOC) { 53 | multPrecond(indsys->Precond, Im, ctemp, size); 54 | for(i = 0; i < size; i++) 55 | Im[i] = ctemp[i]; 56 | } 57 | else if (indsys->precond_type == SPARSE) 58 | spSolve(indsys->sparMatrix, Im, Im); 59 | 60 | /* do Ib = Mtrans*Im */ 61 | for(i = 0; i < branches; i++) { 62 | Ib[i] = CXZERO; 63 | for(mtemp = Mtrans[i]; mtemp != NULL; mtemp = mtemp->mnext) { 64 | if (mtemp->sign == 1) 65 | cx_add(Ib[i], Ib[i], Im[mtemp->filindex]); 66 | else 67 | cx_sub(Ib[i], Ib[i], Im[mtemp->filindex]); 68 | } 69 | } 70 | 71 | /* Evaluate M*L*Mt*Im = M*L*Ib using the multipole algorithm */ 72 | 73 | /* Do all of the non-direct parts first */ 74 | sys->DirectEval = FALSE; 75 | for(i = 0; i < 3; i++) { /* for each of the coordinate directions */ 76 | 77 | /* do the real part */ 78 | for(chg = chglist; chg != NULL; chg = chg->next) { 79 | /* fill the pseudo-charge vector */ 80 | q[chg->index] = Ib[chg->fil->filnumber].real*chg->fil->lenvect[i]; 81 | #if OPCNT == ON 82 | ind_opcnt_mult++; 83 | #endif 84 | 85 | } 86 | computePsi(sys, q, p, branches, chglist); 87 | for(chg = chglist; chg != NULL; chg = chg->next) { 88 | /* add potential due to i direction */ 89 | Vb[chg->fil->filnumber].real += p[chg->index]*chg->fil->lenvect[i]*MUOVER4PI; 90 | #if OPCNT == ON 91 | ind_opcnt_mult++; 92 | #endif 93 | } 94 | 95 | /* do the imaginary part */ 96 | for(chg = chglist; chg != NULL; chg = chg->next) { 97 | /* fill the pseudo-charge vector */ 98 | q[chg->index] = Ib[chg->fil->filnumber].imag*chg->fil->lenvect[i]; 99 | #if OPCNT == ON 100 | ind_opcnt_mult++; 101 | #endif 102 | } 103 | computePsi(sys, q, p, branches, chglist); 104 | for(chg = chglist; chg != NULL; chg = chg->next) { 105 | /* add potential due to i direction */ 106 | Vb[chg->fil->filnumber].imag += p[chg->index]*chg->fil->lenvect[i]*MUOVER4PI; 107 | #if OPCNT == ON 108 | ind_opcnt_mult++; 109 | #endif 110 | } 111 | 112 | } 113 | 114 | /* do the direct parts */ 115 | sys->DirectEval = TRUE; 116 | 117 | /* do the real part of the Direct part */ 118 | for(i = 1; i <= branches; i++) 119 | p[i] = 0; 120 | for(chg = chglist; chg != NULL; chg = chg->next) 121 | /* fill the pseudo-charge vector */ 122 | q[chg->index] = Ib[chg->fil->filnumber].real; 123 | 124 | /* starttimer; */ 125 | mulDirect(sys); 126 | mulEval(sys); 127 | /* stoptimer; */ 128 | // dirtime += dtime; 129 | 130 | for(chg = chglist; chg != NULL; chg = chg->next) { 131 | /* add potential due to i direction */ 132 | Vb[chg->fil->filnumber].real += p[chg->index]; 133 | } 134 | 135 | /* do the imaginary part of the Direct part */ 136 | for(i = 1; i <= branches; i++) 137 | p[i] = 0; 138 | for(chg = chglist; chg != NULL; chg = chg->next) 139 | /* fill the pseudo-charge vector */ 140 | q[chg->index] = Ib[chg->fil->filnumber].imag; 141 | 142 | /* starttimer; */ 143 | mulDirect(sys); 144 | mulEval(sys); 145 | /* stoptimer; */ 146 | // dirtime += dtime; 147 | 148 | for(chg = chglist; chg != NULL; chg = chg->next) { 149 | /* add potential due to i direction */ 150 | Vb[chg->fil->filnumber].imag += p[chg->index]; 151 | } 152 | 153 | /* do Vs = M*Vb*jw */ 154 | for(i = 0; i < size; i++) { 155 | Vs[i] = CXZERO; 156 | for(mtemp = Mlist[i]; mtemp != NULL; mtemp = mtemp->mnext) 157 | if (mtemp->sign == 1) 158 | cx_add(Vs[i], Vs[i], Vb[mtemp->filindex]); 159 | else 160 | cx_sub(Vs[i], Vs[i], Vb[mtemp->filindex]); 161 | 162 | /* multiply by jw */ 163 | rtemp = -Vs[i].imag*w; 164 | Vs[i].imag = Vs[i].real*w; 165 | Vs[i].real = rtemp; 166 | } 167 | 168 | /* add in M*R*Mt*Im = M*R*Ib */ 169 | for(i = 0; i < size; i++) { 170 | for(mtemp = Mlist[i]; mtemp != NULL; mtemp = mtemp->mnext) { 171 | cx_scalar_mult(temp, mtemp->sign*R[mtemp->filindex], Ib[mtemp->filindex]); 172 | cx_add(Vs[i], Vs[i], temp); 173 | #if OPCNT == ON 174 | ind_opcnt_mult+=2; 175 | ind_opcnt_real+=2; 176 | #endif 177 | } 178 | } 179 | 180 | #if OPCNT == ON 181 | printf("Inductance (mesh to branch) mults: %d\n",ind_opcnt_mult); 182 | printf("Just doing MRMtIm: %d\n",ind_opcnt_real); 183 | printops(); 184 | exit(0); 185 | #endif 186 | 187 | #ifdef NODEBUG 188 | /* for debugging, compare to direct Vb = ZM Ib */ 189 | realmatCXvec(Vdirect, indsys->Z, Ib, branches); 190 | maxdiff = 0; 191 | maxindx = 0; 192 | for(i = 0; i < branches; i++) { 193 | if (cx_abs(Vb[i]) > 1e-23) { 194 | cx_sub(temp, Vdirect[i], Vb[i]); 195 | pdiff = cx_abs(temp )/cx_abs(Vb[i]) ; 196 | } 197 | else 198 | pdiff = cx_abs(Vb[i]); 199 | 200 | if (pdiff > maxdiff) { 201 | maxdiff = pdiff; 202 | maxindx = i; 203 | } 204 | } 205 | if (maxdiff < .3) 206 | printf("maxdiff: %g Vb[%d]=%g Vdirect[%d]=%g\n", 207 | maxdiff,maxindx,cx_abs(Vb[maxindx]),maxindx,cx_abs(Vdirect[maxindx])); 208 | else 209 | printf("***maxdiff: %g Vb[%d]=%g Vdirect[%d]=%g***\n", 210 | maxdiff,maxindx,cx_abs(Vb[maxindx]),maxindx,cx_abs(Vdirect[maxindx])); 211 | 212 | 213 | #endif 214 | } 215 | 216 | realmatCXvec(y, A, x, size) 217 | CX *y, *x; 218 | double **A; 219 | int size; 220 | { 221 | int i, j; 222 | CX temp; 223 | 224 | for (i = 0; i < size; i++) { 225 | y[i] = CXZERO; 226 | for(j = 0; j < size; j++) { 227 | cx_scalar_mult(temp, A[i][j], x[j]); 228 | cx_add(y[i], y[i], temp); 229 | } 230 | } 231 | } 232 | 233 | /* this function fixes Eval matrices which are computed directly */ 234 | /* This is necessary since direct mutual terms are not componentwise, 235 | but the multipole routines are called once for each component direction. 236 | Basically, componentwise multiplication will cause the elements 237 | to be multiplied by the dot product of the fil->lenvect vectors of 238 | the two filaments. This will divide that product out. Also, MUOVER4PI 239 | must also be divided out 240 | */ 241 | 242 | fixEvalDirect(qchgs, numqchgs, is_dummy, pchgs, numpchgs, mat) 243 | charge **qchgs, **pchgs; 244 | int numqchgs, numpchgs; 245 | int *is_dummy; 246 | double **mat; 247 | { 248 | int i,j, k; 249 | double dotprod, magi, magj; 250 | double *lenvecti, *lenvectj; 251 | static double eps = EPS; 252 | 253 | for(i = 0; i < numpchgs; i++) { 254 | lenvecti = pchgs[i]->fil->lenvect; 255 | magi = 0; 256 | for(k = 0; k < 3; k++) 257 | magi += lenvecti[k]*lenvecti[k]; 258 | for(j = 0; j < numqchgs; j++) { 259 | lenvectj = qchgs[j]->fil->lenvect; 260 | magj = dotprod = 0; 261 | for(k = 0; k < 3; k++) { 262 | magj += lenvectj[k]*lenvectj[k]; 263 | dotprod += lenvecti[k]*lenvectj[k]; 264 | } 265 | if (fabs(dotprod)/sqrt(magi*magj) > EPS) /* filaments aren't perpendicular */ 266 | mat[i][j] = mat[i][j]/(dotprod*MUOVER4PI); 267 | else { /* if they are, mat[i][j] == 0.0, hopefully */ 268 | if (mat[i][j] != 0.0) 269 | printf("Warning: dot product = %lg < EPS, but mat[i][j] = %lg\n",dotprod, mat[i][j]); 270 | } 271 | } 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /src/fasthenry/gp.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef _GP_H 4 | #define _GP_H 5 | 6 | #include "induct.h" 7 | 8 | #define TRUE 1 9 | #define FALSE 0 10 | 11 | #define CLEAR 0 12 | #define NOCLEAR 1 13 | 14 | #define NOT_CHECKED 0 15 | #define CHECKED 1 16 | 17 | #define ALIVE 0 18 | #define DEAD 1 19 | 20 | #define X_DIR 0 21 | #define Y_DIR 1 22 | 23 | /* number of cells a node can be a part of */ 24 | #define NUM_N_CELLS 4 25 | 26 | /* number of cells an edge can be a part of */ 27 | #define NUM_E_CELLS 2 28 | 29 | /* number of edges a cell has and their directions */ 30 | #define NUMEDGES 4 31 | #define NORTH 0 32 | #define EAST 1 33 | #define SOUTH 2 34 | #define WEST 3 35 | 36 | /* number of nodes to a cell and their positions */ 37 | #define NUMNODES 4 38 | #define NE 0 39 | #define SE 1 40 | #define SW 2 41 | #define NW 3 42 | 43 | #define NUMADJ 4 44 | #define N 0 45 | #define E 1 46 | #define S 2 47 | #define W 3 48 | 49 | typedef struct llist { 50 | void *ptr; 51 | struct llist *next; 52 | } Llist; 53 | 54 | /* 55 | In FastHenry 2.0, a plane was a grid of segments in both x and y where 56 | the four segments making a square we call a 'cell'. 57 | Now let's assume our plane is made up of a grid of these cells, and 58 | now we allow a cell to be broken into subcells in a hierarchical fashion 59 | for nonuniform discretizations */ 60 | 61 | typedef struct nonuni_gp { 62 | struct gcell *root_cell; /* root of the discretization tree */ 63 | 64 | int num_nodes; 65 | int num_cells; 66 | int num_leaves; /* number of leaves == number of meshes if num_z_pts=1 */ 67 | int num_seg_groups; /* number of segs if no z-directed segs */ 68 | 69 | /* define relative coordinate system for plane so that top and bottom 70 | of plane are in x-y plane */ 71 | 72 | /* coordinates of one corner of 3D rectangular solid in real coords */ 73 | double x0, y0, z0; /* origin_p */ 74 | 75 | /* The plane axis directions */ 76 | double ux_x, ux_y, ux_z; /* ux=unit vector along gp x direction */ 77 | double uy_x, uy_y, uy_z; /* uy=unit vector along gp y direction */ 78 | /* So, given plane coords (xp,yp), real coord is: 79 | origin_p + xp * ux + yp * uy */ 80 | 81 | double uz_x, uz_y, uz_z; /* unit vector along gp z dir */ 82 | /*double thickness; */ 83 | 84 | /* describe discretization in z direction */ 85 | int num_z_pts; 86 | double *z_pts; /*on the interval [0,1] describe where points should be*/ 87 | 88 | /* so if num_z_pts = 3, there will be 3 layers of x-y segs and two 89 | zdirected segments connecting the layers. Example: 90 | z_pts[0] = 0, z_pts[1] = 0.5, z_pts[2] = 1, then the z-directed 91 | segments will go from 0 - 0.5, and 0.5 - 1. where 0 is 92 | the bottom. 93 | */ 94 | 95 | /* also the center points for filaments and their thicknesses */ 96 | double *thick; 97 | double *z_c; 98 | 99 | /* linked list of all the nodes */ 100 | struct g_nodes *nodelist; 101 | 102 | /* fastH old ground plane */ 103 | struct Groundplane *grndp; 104 | 105 | /* has the cell edge info been corrupted because i didn't think i'd need it*/ 106 | char is_edge_corrupted; 107 | 108 | } Nonuni_gp; 109 | 110 | /* hierarchal cells to represent a nonuniformly discretized plane of 111 | material. */ 112 | 113 | /* a node in the tree */ 114 | typedef struct gcell { 115 | 116 | int index; /* an index for debugging */ 117 | void *children; /* a pointer to a structure representing the subcells*/ 118 | char children_type; /* what is the structure for the children */ 119 | /* the children types: */ 120 | #ifdef NONE 121 | #undef NONE 122 | #endif 123 | #define NONE 0x0 124 | #define BI 0x1 /* cell is divided in half */ 125 | #define QUAD 0x2 /* cell is divided into four */ 126 | #define GRID_2D 0x3 /* a 2D grid of cells */ 127 | 128 | char ishole; /* does this cell represent a hole */ 129 | 130 | struct gcell *parent; /* The parent of this cell */ 131 | 132 | /* in the root cell coorinate frame, here are two corners of the cell */ 133 | double x0, y0; /* corner closest to origin (SW corner) */ 134 | double x1, y1; /* corner farthest from origin (NE corner) */ 135 | 136 | union { 137 | struct g_edges *edges[NUMEDGES]; /* struct describing the edge of a cell */ 138 | struct g_nodes *nodes[NUMNODES]; /* nodes of cell (only if leaf!) */ 139 | } bndry; 140 | 141 | } Gcell; 142 | 143 | 144 | /* a edge of a cell holds info for the adjacent cell. This structure holds 145 | the info in a tree like fashion */ 146 | 147 | typedef struct g_edges { 148 | 149 | struct gcell *cells[NUM_E_CELLS]; /* cells for which this is a boundary */ 150 | char dirs[NUM_E_CELLS]; /* which direction this edge is within 151 | corresponding cell */ 152 | 153 | /* a pointer to a structure holding children making up this edge 154 | if it is not a leaf */ 155 | 156 | int num_children; /* for an edge, this must be a binary tree! */ 157 | /* or could be unary */ 158 | Gcell **children; /* points to cells */ 159 | 160 | } G_edges; 161 | 162 | typedef struct g_nodes { 163 | 164 | int index; /* an index for debugging */ 165 | double x, y; 166 | 167 | struct gcell *cells[NUM_N_CELLS]; 168 | 169 | /* need all four because of z-directed segs */ 170 | struct g_nodes *adjacent[NUMADJ]; 171 | 172 | char flag; /* flag to mark things */ 173 | 174 | double x_shift, y_shift; /* shift for center of z-directed segments */ 175 | 176 | /* the number of segs is determined by gp->num_z_pts */ 177 | SEGMENT **e_segs; /* array of segs in east direction */ 178 | SEGMENT **n_segs; /* in north direction */ 179 | 180 | struct g_nodes *prev; 181 | struct g_nodes *next; 182 | 183 | } G_nodes; 184 | 185 | /* a binary tree */ 186 | typedef struct bi { 187 | 188 | struct gcell *child1; /* either North or East child */ 189 | struct gcell *child2; /* South or West */ 190 | 191 | char type; /* divided North/South or East/West */ 192 | #define NS 1 193 | #define EW 2 194 | 195 | } Bi; 196 | 197 | /* a quad tree */ 198 | typedef struct quad { 199 | 200 | struct gcell *kids[4]; 201 | 202 | } Quad; 203 | 204 | /* a 2d array of children */ 205 | typedef struct grid_2d { 206 | 207 | struct gcell ***kids; 208 | int x_cells, y_cells; 209 | 210 | } Grid_2d; 211 | 212 | typedef struct { 213 | Nonuni_gp *gp; 214 | } Info; 215 | 216 | typedef struct _nonuni_choice_list { 217 | G_nodes *node; 218 | SEGMENT *seg; 219 | double rank; /* weight for this choice */ 220 | } nonuni_choice_list; 221 | 222 | G_nodes *add_to_gnodelist(); 223 | G_edges *make_one_edge(); 224 | G_edges *make_two_edge(); 225 | G_nodes *get_other_gnode(); 226 | Gcell *new_Gcells(); 227 | Gcell *new_Gcell(); 228 | G_nodes *new_Gnode(); 229 | G_nodes *make_new_node(); 230 | void *gp_malloc(); 231 | G_nodes *get_adjacent_node(); 232 | SEGMENT *make_one_seg(); 233 | G_nodes *find_nearest_nonuni_node(); 234 | Gcell *get_containing_cell(); 235 | Gcell *get_containing_grid_cell(); 236 | Gcell *get_containing_bi_cell(); 237 | SPATH *get_a_nonuni_path(); 238 | Llist *add_ptr_to_list(); 239 | int add_nonuni_choice(); 240 | G_nodes *find_nearest_edge_node(); 241 | G_nodes *scan_edge(); 242 | double get_node_dist(); 243 | double get_dist(); 244 | MELEMENT *add_edge_segs_to_list(); 245 | double get_perimeter(); 246 | NODES *get_nonuni_node_from_list(); 247 | NODES *make_new_node_with_nonuni(); 248 | Llist *get_nodes_inside_rect(); 249 | Llist *bi_get_nodes_inside_rect(); 250 | Llist *grid_get_nodes_inside_rect(); 251 | Llist *which_nodes_inside(); 252 | 253 | /* contact.c */ 254 | G_nodes *find_mid_node(); 255 | Gcell *find_next_cell_along_line(); 256 | double edge_coord(); 257 | Gcell *cut_cell(); 258 | G_nodes *add_new_node(); 259 | NODES *make_fastH_node(); 260 | ContactList *make_contact_connection(); 261 | Gcell *pick_cell_based_on_vec(); 262 | 263 | #define get_x0(cell) (cell->x0) 264 | #define get_y0(cell) (cell->y0) 265 | #define get_x1(cell) (cell->x1) 266 | #define get_y1(cell) (cell->y1) 267 | 268 | /* could also check if children_type == NONE */ 269 | #define is_leaf(cell) (cell->children == NULL) 270 | #define get_children_type(cell) (cell->children_type) 271 | #define get_bi_type(two) (two->type) 272 | #define is_hole(cell) (cell->ishole == TRUE) 273 | 274 | void debug_func(); 275 | #define GP_PANIC(str) { fprintf(stderr,"Internal error in nonuniform plane code: %s\n",str); debug_func(); exit(1); } 276 | 277 | #define DUMP_INDEX(ptr) {if ((ptr) == NULL) \ 278 | fprintf(fp, "x "); \ 279 | else\ 280 | fprintf(fp, "%d ", (ptr)->index);} 281 | 282 | /* #ifndef _GP_GLOBAL 283 | #define _GP_GLOBAL 284 | int opposite[4] = {SW, NW, NE, SE} 285 | #else 286 | extern opposite[4]; 287 | #endif 288 | */ 289 | 290 | /* return opposite direction to dir */ 291 | #define opposite_dir(dir) ( (dir + 2)%4 ) 292 | 293 | #endif /* _GP_H */ 294 | -------------------------------------------------------------------------------- /src/fasthenry/sparse/spSMP.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Spice3 COMPATIBILITY MODULE 3 | * 4 | * Author: Advising professor: 5 | * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli 6 | * UC Berkeley 7 | * 8 | * This module contains routines that make Sparse1.3 a direct 9 | * replacement for the SMP sparse matrix package in Spice3b1. 10 | * Sparse1.3 is in general a faster and more robust package than SMP. 11 | * These advantages become significant on large circuits. 12 | * 13 | * >>> User accessible functions contained in this file: 14 | * SMPaddElt 15 | * SMPmakeElt 16 | * SMPcClear 17 | * SMPclear 18 | * SMPcLUfac 19 | * SMPluFac 20 | * SMPcReorder 21 | * SMPreorder 22 | * SMPcSolve 23 | * SMPsolve 24 | * SMPmatSize 25 | * SMPnewMatrix 26 | * SMPdestroy 27 | * SMPpreOrder 28 | * SMPprint 29 | * SMPgetError 30 | * SMPcProdDiag 31 | */ 32 | 33 | /* 34 | * To replace SMP with Sparse, rename the file spSpice3.h to 35 | * spMatrix.h and place Sparse in a subdirectory of SPICE called 36 | * `sparse'. Then on UNIX compile Sparse by executing `make spice'. 37 | * If not on UNIX, after compiling Sparse and creating the sparse.a 38 | * archive, compile this file (spSMP.c) and spSMP.o to the archive, 39 | * then copy sparse.a into the SPICE main directory and rename it 40 | * SMP.a. Finally link SPICE. 41 | * 42 | * To be compatible with SPICE, the following Sparse compiler options 43 | * (in spConfig.h) should be set as shown below: 44 | * 45 | * REAL YES 46 | * EXPANDABLE YES 47 | * TRANSLATE NO 48 | * INITIALIZE NO or YES, YES for use with test prog. 49 | * DIAGONAL_PIVOTING YES 50 | * ARRAY_OFFSET YES 51 | * MODIFIED_MARKOWITZ NO 52 | * DELETE NO 53 | * STRIP NO 54 | * MODIFIED_NODAL YES 55 | * QUAD_ELEMENT NO 56 | * TRANSPOSE NO 57 | * SCALING NO 58 | * DOCUMENTATION YES 59 | * MULTIPLICATION NO 60 | * DETERMINANT YES 61 | * STABILITY NO 62 | * CONDITION NO 63 | * PSEUDOCONDITION NO 64 | * FORTRAN NO 65 | * DEBUG YES 66 | * spCOMPLEX 1 67 | * spSEPARATED_COMPLEX_VECTORS 1 68 | * spCOMPATIBILITY 0 69 | * 70 | * spREAL double 71 | */ 72 | 73 | /* 74 | * Revision and copyright information. 75 | * 76 | * Copyright (c) 1985,86,87,88 77 | * by Kenneth S. Kundert and the University of California. 78 | * 79 | * Permission to use, copy, modify, and distribute this software and its 80 | * documentation for any purpose and without fee is hereby granted, provided 81 | * that the above copyright notice appear in all copies and supporting 82 | * documentation and that the authors and the University of California 83 | * are properly credited. The authors and the University of California 84 | * make no representations as to the suitability of this software for 85 | * any purpose. It is provided `as is', without express or implied warranty. 86 | */ 87 | 88 | #ifndef lint 89 | static char copyright[] = 90 | "Sparse1.3: Copyright (c) 1985,86,87,88 by Kenneth S. Kundert"; 91 | static char RCSid[] = 92 | "@(#)$Header: spSMP.c,v 1.2 88/06/24 05:02:42 kundert Exp $"; 93 | #endif 94 | 95 | 96 | 97 | 98 | /* 99 | * IMPORTS 100 | * 101 | * >>> Import descriptions: 102 | * spMatrix.h 103 | * Sparse macros and declarations. 104 | * SMPdefs.h 105 | * Spice3's matrix macro definitions. 106 | */ 107 | 108 | #include "spMatrix.h" 109 | #include "../include/SMPdefs.h" 110 | 111 | #define NO 0 112 | #define YES 1 113 | 114 | 115 | /* 116 | * SMPaddElt() 117 | */ 118 | int 119 | SMPaddElt( Matrix, Row, Col, Value ) 120 | SMPmatrix *Matrix; 121 | int Row, Col; 122 | double Value; 123 | { 124 | *spGetElement( (char *)Matrix, Row, Col ) = Value; 125 | return spError( (char *)Matrix ); 126 | } 127 | 128 | /* 129 | * SMPmakeElt() 130 | */ 131 | double * 132 | SMPmakeElt( Matrix, Row, Col ) 133 | SMPmatrix *Matrix; 134 | int Row, Col; 135 | { 136 | return spGetElement( (char *)Matrix, Row, Col ); 137 | } 138 | 139 | /* 140 | * SMPcClear() 141 | */ 142 | void 143 | SMPcClear( Matrix ) 144 | SMPmatrix *Matrix; 145 | { 146 | spClear( (char *)Matrix ); 147 | } 148 | 149 | /* 150 | * SMPclear() 151 | */ 152 | void 153 | SMPclear( Matrix ) 154 | SMPmatrix *Matrix; 155 | { 156 | spClear( (char *)Matrix ); 157 | } 158 | 159 | /* 160 | * SMPcLUfac() 161 | */ 162 | /*ARGSUSED*/ 163 | int 164 | SMPcLUfac( Matrix, PivTol ) 165 | SMPmatrix *Matrix; 166 | double PivTol; 167 | { 168 | spSetComplex( (char *)Matrix ); 169 | return spFactor( (char *)Matrix ); 170 | } 171 | 172 | /* 173 | * SMPluFac() 174 | */ 175 | /*ARGSUSED*/ 176 | int 177 | SMPluFac( Matrix, PivTol, Gmin ) 178 | SMPmatrix *Matrix; 179 | double PivTol, Gmin; 180 | { 181 | spSetReal( (char *)Matrix ); 182 | LoadGmin( (char *)Matrix, Gmin ); 183 | return spFactor( (char *)Matrix ); 184 | } 185 | 186 | /* 187 | * SMPcReorder() 188 | */ 189 | int 190 | SMPcReorder( Matrix, PivTol, PivRel, NumSwaps ) 191 | SMPmatrix *Matrix; 192 | double PivTol, PivRel; 193 | int *NumSwaps; 194 | { 195 | *NumSwaps = 0; 196 | spSetComplex( (char *)Matrix ); 197 | return spOrderAndFactor( (char *)Matrix, (spREAL*)NULL, 198 | (spREAL)PivRel, (spREAL)PivTol, YES ); 199 | } 200 | 201 | /* 202 | * SMPreorder() 203 | */ 204 | int 205 | SMPreorder( Matrix, PivTol, PivRel, Gmin ) 206 | SMPmatrix *Matrix; 207 | double PivTol, PivRel, Gmin; 208 | { 209 | spSetComplex( (char *)Matrix ); 210 | LoadGmin( (char *)Matrix, Gmin ); 211 | return spOrderAndFactor( (char *)Matrix, (spREAL*)NULL, 212 | (spREAL)PivRel, (spREAL)PivTol, YES ); 213 | } 214 | 215 | /* 216 | * SMPcSolve() 217 | */ 218 | void 219 | SMPcSolve( Matrix, RHS, iRHS, Spare, iSpare) 220 | SMPmatrix *Matrix; 221 | double RHS[], iRHS[], Spare[], iSpare[]; 222 | { 223 | spSolve( (char *)Matrix, RHS, RHS, iRHS, iRHS ); 224 | } 225 | 226 | /* 227 | * SMPsolve() 228 | */ 229 | void 230 | SMPsolve( Matrix, RHS, Spare ) 231 | SMPmatrix *Matrix; 232 | double RHS[], Spare[]; 233 | { 234 | spSolve( (char *)Matrix, RHS, RHS, (spREAL*)NULL, (spREAL*)NULL ); 235 | } 236 | 237 | /* 238 | * SMPmatSize() 239 | */ 240 | int 241 | SMPmatSize( Matrix ) 242 | SMPmatrix *Matrix; 243 | { 244 | return spGetSize( (char *)Matrix, 1 ); 245 | } 246 | 247 | /* 248 | * SMPnewMatrix() 249 | */ 250 | int 251 | SMPnewMatrix( pMatrix ) 252 | SMPmatrix **pMatrix; 253 | { 254 | int Error; 255 | *pMatrix = (SMPmatrix *)spCreate( 0, 1, &Error ); 256 | return Error; 257 | } 258 | 259 | /* 260 | * SMPdestroy() 261 | */ 262 | void 263 | SMPdestroy( Matrix ) 264 | SMPmatrix *Matrix; 265 | { 266 | spDestroy( (char *)Matrix ); 267 | } 268 | 269 | /* 270 | * SMPpreOrder() 271 | */ 272 | int 273 | SMPpreOrder( Matrix ) 274 | SMPmatrix *Matrix; 275 | { 276 | spMNA_Preorder( (char *)Matrix ); 277 | return spError( (char *)Matrix ); 278 | } 279 | 280 | /* 281 | * SMPprint() 282 | */ 283 | /*ARGSUSED*/ 284 | void 285 | SMPprint( Matrix, File ) 286 | SMPmatrix *Matrix; 287 | FILE *File; 288 | { 289 | spPrint( (char *)Matrix, 0, 1, 1 ); 290 | } 291 | 292 | /* 293 | * SMPgetError() 294 | */ 295 | void 296 | SMPgetError( Matrix, Col, Row) 297 | SMPmatrix *Matrix; 298 | int *Row, *Col; 299 | { 300 | spWhereSingular( (char *)Matrix, Row, Col ); 301 | } 302 | 303 | /* 304 | * SMPcProdDiag() 305 | */ 306 | int 307 | SMPcProdDiag( Matrix, pMantissa, pExponent) 308 | SMPmatrix *Matrix; 309 | SPcomplex *pMantissa; 310 | int *pExponent; 311 | { 312 | spDeterminant( (char *)Matrix, pExponent, &(pMantissa->real), 313 | &(pMantissa->imag) ); 314 | return spError( (char *)Matrix ); 315 | } 316 | 317 | /* 318 | * LOAD GMIN 319 | * 320 | * This routine adds Gmin to each diagonal element. Because Gmin is 321 | * added to the current diagonal, which may bear little relation to 322 | * what the outside world thinks is a diagonal, and because the 323 | * elements that are diagonals may change after calling spOrderAndFactor, 324 | * use of this routine is not recommended. It is included here simply 325 | * for compatibility with Spice3. 326 | */ 327 | #include "spDefs.h" 328 | 329 | LoadGmin( eMatrix, Gmin ) 330 | 331 | char *eMatrix; 332 | register double Gmin; 333 | { 334 | MatrixPtr Matrix = (MatrixPtr)eMatrix; 335 | register int I; 336 | register ArrayOfElementPtrs Diag; 337 | 338 | /* Begin `spLoadGmin'. */ 339 | ASSERT( IS_SPARSE( Matrix ) ); 340 | 341 | Diag = Matrix->Diag; 342 | for (I = Matrix->Size; I > 0; I--) 343 | Diag[I]->Real += Gmin; 344 | return; 345 | } 346 | -------------------------------------------------------------------------------- /src/fasthenry/mulStruct.h: -------------------------------------------------------------------------------- 1 | /* # ***** sort to /src/header 2 | # ***** */ 3 | #include "patran.h" /* for neutral file interface */ 4 | 5 | struct surface { /* a surface file and its permittivities */ 6 | int type; /* CONDTR, DIELEC or BOTH */ 7 | double trans[3]; /* translation vector applied to surface */ 8 | double ref[3]; /* reference point for normal alignment */ 9 | int ref_inside; /* TRUE=>ref point inside (on - side of) surf*/ 10 | int end_of_chain; /* TRUE=>end o/surf chain all w/same cond#'s */ 11 | char *title; /* title inside surface file */ 12 | char *name; /* surface file name (neutral or quick fmat) */ 13 | char *group_name; /* name of cond group (if any) surf part of */ 14 | double outer_perm; /* relative permitivity on side n pnts into 15 | (n is taken as the normal to 1st panel) */ 16 | double inner_perm; /* relative permitivity on other side 17 | (always zero for type = CONDTR) */ 18 | struct charge *panels; /* linked list of panels on this surface */ 19 | int num_panels; /* number of panels (incl dummies) this surf */ 20 | int num_dummies; /* number of dummy panels on this surf */ 21 | struct surface *next; /* linked list pointers */ 22 | struct surface *prev; 23 | }; 24 | typedef struct surface surface; 25 | 26 | struct charge { /* point charge */ 27 | struct charge *next; /* Next charge in linked list. */ 28 | double corner[4][3]; /* Corner point coordinates. */ 29 | int shape; /* 4=quad panel, 3 = triangular panel. */ 30 | int index; /* charge value index in q array */ 31 | double X[3], Y[3], Z[3]; /* Def coord system, Z is normal direction. */ 32 | double max_diag; /* Longest diagonal of panel. */ 33 | double min_diag; /* Shortest diagonal. */ 34 | double length[4]; /* Edge lengths. */ 35 | double area; /* Area of two triangluar regions. */ 36 | double x, y, z; /* Centroid of the quadlrilateral. */ 37 | double moments[16]; /* Moments of the panel. */ 38 | double *multipole; /* Temporarily Stores Q2M. */ 39 | int cond; /* Conductor number. */ 40 | int order; /* Multipole order. */ 41 | /* things needed to do electric field evaluation by divided difference */ 42 | int dummy; /* TRUE => dummy panel for elec field eval */ 43 | struct surface *surf; /* surface that contains this panel */ 44 | struct charge *pos_dummy; /* eval pnt w/pos displacement from x,y,z */ 45 | struct charge *neg_dummy; /* eval pnt w/neg displacement from x,y,z */ 46 | 47 | struct Filament *fil; /* real filament that this corresponds to */ 48 | }; 49 | typedef struct charge charge; 50 | 51 | struct cube { 52 | /* Definition variables. */ 53 | int index; /* unique index */ 54 | int level; /* 0 => root */ 55 | double x, y, z; /* Position of cube center. */ 56 | int j, k, l; /* cube is cubes[level][j][k][l] */ 57 | int flag; /* used for marking for tree walks */ 58 | 59 | /* Upward Pass variables. */ 60 | int mul_exact; /* TRUE => do not build a multipole expansn */ 61 | struct cube *mnext; /* Ptr to next cube on which to do multi. */ 62 | int upnumvects; /* 0 if empty, 1 on bot level if not empty, 63 | else # nonempty kids. */ 64 | int *upnumeles; /* numeles[0] = # chgs on bot level, else 65 | number of terms in kid's expansion. */ 66 | double **upvects; /* vects[0] = chgs on bot level, else vectors 67 | of kids' expansion terms. */ 68 | int multisize; /* Number of terms in the expansion. */ 69 | double *multi; /* Vector of multi coefficients. */ 70 | double ***upmats; /* Matrices for chgs to multi or multi to multi. 71 | upmats[i] is multisize x upnumeles[i]. */ 72 | int *is_dummy; /* is_dummy[i] = TRUE => panel i is a dummy panel 73 | used for elec field eval - omit from upward pass */ 74 | int *is_dielec; /* is_dielec[i] = TRUE => panel i is on a surf 75 | of type DIELEC or BOTH */ 76 | 77 | /* Downward Pass variables. */ 78 | int loc_exact; /* TRUE => do not build a local expansion */ 79 | struct cube *lnext; /* Ptr to next cube on which to do local. */ 80 | int downnumvects; /* Number of cubes in iteraction list. */ 81 | int *downnumeles; /* # of eles in interact cube's expansion. */ 82 | double **downvects; /* Vects of interact cube's expansion. */ 83 | 84 | int localsize; /* Size of the local expansion */ 85 | double *local; /* Vector of local field coefs */ 86 | double ***downmats; /* Matrices for multi to chg, or multi to local 87 | or local to local. Downnumele x localsize. */ 88 | 89 | struct cube **interList; /* explicit interaction list 90 | - for fake dwnwd passes and eval pass */ 91 | int interSize; /* number of elements in interList 92 | - often != downnumvects nor evalnumvects */ 93 | 94 | /* evaluation pass variables */ 95 | struct cube *enext; /* pntr to next cube to evaluate */ 96 | int evalnumvects; /* for exact = #in inter list, o.w. = 1 */ 97 | int *evalnumeles; /* num of elements in inter list entry exp */ 98 | double **evalvects; /* multi, local, or chgs of ilist entry */ 99 | 100 | double *eval; /* vector of evaluation pnt voltages in cube */ 101 | double ***evalmats; /* matrices for multi to potential, local to 102 | potential or charge to potential */ 103 | int *eval_isQ2P; /* is this matrix done directly? 104 | For inductance stuff 12/92 */ 105 | 106 | /* Direct portion variables. */ 107 | struct cube *dnext; /* Ptr to next cube on which to do direct. */ 108 | struct cube *pnext; /* Ptr to next cube on which to do precond. */ 109 | struct cube *rpnext; /* Reverse ptr to next cube to do precond. */ 110 | int dindex; /* Used to determine lower triang portion. */ 111 | int directnumvects; /* Number of vects, self plus nbrs. */ 112 | int *directnumeles; /* # of elements in the nbrs chg vect. 113 | directnumeles[0] = numchgs in cube. */ 114 | double **directq; /* Vecs of chg vecs, directq[0] this cube's. */ 115 | double ***directmats; /* Potential Coeffs in cube and neighbors. */ 116 | double ***precondmats; /* Precond Coeffs in cube and neighbors. */ 117 | double **directlu; /* Decomposed cube potential Coefficients. */ 118 | double **precond; /* Preconditioner. */ 119 | double *prevectq; /* The charge vector for the preconditioner. */ 120 | double *prevectp; /* The potential vector for preconditioner. */ 121 | int presize; /* Size of the preconditioner. */ 122 | int **nbr_is_dummy; /* Dummy vectors corresponding to directq's */ 123 | 124 | /* Cube structure variables. */ 125 | charge **chgs; /* Array of charge ptrs. Only used lowest level. */ 126 | struct cube **nbrs; /* Array of ptrs to nonemptry nearest neighbors. */ 127 | int numnbrs; /* Number of nonempty neighbors. */ 128 | struct cube **kids; /* Array of children ptrs. */ 129 | int numkids; /* Number of kids. */ 130 | struct cube *parent; /* Ptr to parent cube. */ 131 | 132 | }; 133 | typedef struct cube cube; 134 | 135 | struct ssystem { 136 | int side; /* # cubes per side on lowest level. */ 137 | int depth; /* # of levels of cubes. */ 138 | int order; /* # of levels of cubes. */ 139 | int num_cond; /* number of conductors */ 140 | Name *cond_names; /* conductor name list */ 141 | double perm_factor; /* overall scale factor for permittivities */ 142 | double length; /* Length per cube on lowest level. */ 143 | double minx, miny, minz; /* Coordinates of one corner of the domain. */ 144 | int mul_maxq; /* max #panels in mul_exact cube */ 145 | int mul_maxlq; /* max #panels in lowest level cube */ 146 | int max_panel; /* max #panels in all cubes w/multipole */ 147 | int up_size; /* total #panels in all cubes, incl dummies */ 148 | int loc_maxq; /* max #evaluation points in loc_exact cube */ 149 | int loc_maxlq; /* max #eval pnts in lowest level cube. */ 150 | int max_eval_pnt; /* max #eval pnts in all cubes w/local exp */ 151 | int eval_size; /* total #eval pnts in entire problem */ 152 | double *q; /* The vector of lowest level charges. */ 153 | double *p; /* The vector of lowest level potentials. */ 154 | charge *panels; /* linked list of charge panels in problem */ 155 | cube *****cubes; /* The array of cube pointers. */ 156 | cube **multilist; /* Array of ptrs to first cube in linked list 157 | of cubes to do multi at each level. */ 158 | cube **locallist; /* Array of ptrs to first cube in linked list 159 | of cubes to do local at each level. */ 160 | cube *directlist; /* head of linked lst of low lev cubes w/chg */ 161 | cube *precondlist; /* head of linked lst of precond blks. */ 162 | cube *revprecondlist; /* reversed linked lst of precond blks. */ 163 | int *is_dummy; /* is_dummy[i] = TRUE => panel i is a dummy */ 164 | int *is_dielec; /* is_dielec[i] = TRUE => panel i on dielec */ 165 | int DirectEval; /* TRUE - mulEval will do only Q2P products. 166 | FALSE - mulEval will do all others. 12/92 */ 167 | int real_depth; /* depth w/o fake levels for preconditioner*/ 168 | int debug; /* print debug info */ 169 | /* 170 | int *****evalQ2Ps; 171 | int *****evalL2Ps; 172 | int *****evalM2Ps; 173 | int *****cntQ2Ps; 174 | int *****cntL2Ps; 175 | int *****cntM2Ps; 176 | */ 177 | }; 178 | typedef struct ssystem ssystem; 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | -------------------------------------------------------------------------------- /src/fasthenry/hole.c: -------------------------------------------------------------------------------- 1 | /* The following are support functions for holes in a ground plane. */ 2 | /* For user defined hole functions, alter hole_user1() - hole_user10() */ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "induct.h" 10 | 11 | /* returns TRUE if the next word in line matches str. */ 12 | /* (strips leading spaces from line, but not str) */ 13 | is_next_word(str, line) 14 | char *str, *line; 15 | { 16 | 17 | /* skip leading spaces */ 18 | while(isspace(*line) && *line != '\0') 19 | line++; 20 | 21 | if (*line == '\0') /* anything left? */ 22 | return FALSE; 23 | else { 24 | while(*str != '\0' && *str == *line) { 25 | str++; 26 | line++; 27 | } 28 | if (*str == '\0') 29 | return TRUE; 30 | else 31 | return FALSE; 32 | } 33 | } 34 | 35 | /* has the node been removed because it is part of a ground plane hole? */ 36 | is_hole(node) 37 | NODES *node; 38 | { 39 | return (node->type == GPHOLE); 40 | } 41 | 42 | #define MAXNAME 20 43 | 44 | /* this turns the info in line into a HoleList element */ 45 | HoleList *make_holelist(hole_head, line, units, relx, rely, relz, skip) 46 | HoleList *hole_head; 47 | char *line; 48 | double units, relx, rely, relz; 49 | int *skip; 50 | { 51 | char name[MAXNAME]; 52 | int skip1, skip2, skip3, skip4; 53 | HoleList *holep; 54 | char *linep; 55 | double *vals; 56 | 57 | holep = (HoleList *)Gmalloc(sizeof(HoleList)); 58 | 59 | name[MAXNAME-1] = '\0'; 60 | sscanf(line, "%19s%n",name,&skip1); 61 | line+=skip1; 62 | 63 | if (strcmp("hole",name) != 0) { 64 | fprintf(stderr, "Internal Error: %s is not the word 'hole'\n",name); 65 | exit(1); 66 | } 67 | 68 | name[MAXNAME-1] = '\0'; 69 | sscanf(line, "%19s%n",name,&skip2); 70 | line+=skip2; 71 | 72 | if (name[MAXNAME-1] != '\0') 73 | printf("Warning: hole function '%s' truncated to 19 chars\n",name); 74 | 75 | holep->func = (char *)Gmalloc((strlen(name) + 1)*sizeof(char)); 76 | strcpy(holep->func, name); 77 | holep->units = units; 78 | holep->relx = relx; 79 | holep->rely = rely; 80 | holep->relz = relz; 81 | 82 | skip3 = 0; 83 | while(isspace(*line) && *line != '\0') { 84 | line++; 85 | skip3++; 86 | } 87 | 88 | if (*line != '(') 89 | hole_error("Values for hole must start with '('",line,holep); 90 | 91 | /* let's count how many values we have first */ 92 | linep = line; 93 | holep->numvals = 0; 94 | 95 | while(*linep != ')' && !eos(*linep)) { 96 | linep++; 97 | while(isspace(*linep) || is_one_of(*linep, "1234567890.e+-")) 98 | linep++; 99 | holep->numvals++; 100 | } 101 | if (*linep != ')') 102 | hole_error("Hole values did not end with ')'", line, holep); 103 | 104 | holep->vals = (double *)Gmalloc(holep->numvals*sizeof(double)); 105 | 106 | skip3 += linep - line + 1; 107 | 108 | /* now let's read them in */ 109 | linep = line + 1; /* skip the ( */ 110 | vals = holep->vals; 111 | 112 | while(*linep != ')') { 113 | if (sscanf(linep, "%lf%n",vals,&skip4) != 1) 114 | hole_error("Couldn't read value starting at:",linep,holep); 115 | else { 116 | linep += skip4; 117 | vals++; 118 | linep += skipspace(linep); 119 | if (*linep == ',') 120 | linep++; 121 | } 122 | } 123 | 124 | *skip = skip1 + skip2 + skip3; 125 | 126 | holep->next = hole_head; 127 | return holep; 128 | 129 | } 130 | 131 | skipspace(line) 132 | char *line; 133 | { 134 | int skip = 0; 135 | 136 | while(isspace(*line)) { 137 | skip++; 138 | line++; 139 | } 140 | 141 | return skip; 142 | } 143 | 144 | /* End of string test */ 145 | eos(chr) 146 | char chr; 147 | { 148 | return (chr == '\0'); 149 | } 150 | 151 | hole_error(errstr, line, holep) 152 | char *errstr, *line; 153 | HoleList *holep; 154 | { 155 | fprintf(stderr, "While reading in a %s hole:\n",holep->func); 156 | fprintf(stderr, "%s\n%s",errstr,line); 157 | fprintf(stderr, "The hole format is 'hole (val1,val2,...)'\n"); 158 | fprintf(stderr, "Where type is a string, and valn is a floating point value\n"); 159 | exit(1); 160 | } 161 | 162 | is_one_of(letter, one_of) 163 | char letter, *one_of; 164 | { 165 | for( ; *one_of != '\0'; one_of++) 166 | if (letter == *one_of) 167 | return (1==1); 168 | 169 | return 1==0; 170 | } 171 | 172 | delete_node(node) 173 | NODES *node; 174 | { 175 | node->type = GPHOLE; 176 | } 177 | 178 | /* This calls the functions which make the holes */ 179 | make_holes(holep, gp) 180 | GROUNDPLANE *gp; 181 | HoleList *holep; 182 | { 183 | double relx = holep->relx; 184 | double rely = holep->rely; 185 | double relz = holep->relz; 186 | double units = holep->units; 187 | 188 | if (strncmp("rect",holep->func,4) == 0) 189 | hole_rect(holep, gp, relx, rely, relz, units); 190 | else if (strncmp("circle",holep->func,6) == 0) 191 | hole_circle(holep, gp, relx, rely, relz, units); 192 | else if (strncmp("point",holep->func,5) == 0) 193 | hole_point(holep, gp, relx, rely, relz, units); 194 | else if (strncmp("user1",holep->func,5) == 0) 195 | hole_user1(holep, gp, relx, rely, relz, units); 196 | else if (strncmp("user2",holep->func,5) == 0) 197 | hole_user2(holep, gp, relx, rely, relz, units); 198 | else if (strncmp("user3",holep->func,5) == 0) 199 | hole_user3(holep, gp, relx, rely, relz, units); 200 | else if (strncmp("user4",holep->func,5) == 0) 201 | hole_user4(holep, gp, relx, rely, relz, units); 202 | else if (strncmp("user5",holep->func,5) == 0) 203 | hole_user5(holep, gp, relx, rely, relz, units); 204 | else if (strncmp("user6",holep->func,5) == 0) 205 | hole_user6(holep, gp, relx, rely, relz, units); 206 | else if (strncmp("user7",holep->func,5) == 0) 207 | hole_user7(holep, gp, relx, rely, relz, units); 208 | else 209 | hole_error("Unknown type of hole","",holep); 210 | } 211 | 212 | /* This makes a hole by removing one node nearest to the (x,y,z) given 213 | by holes->vals; 214 | */ 215 | hole_point(holep, gp, relx, rely, relz, units) 216 | GROUNDPLANE *gp; 217 | HoleList *holep; 218 | double relx,rely,relz,units; 219 | { 220 | double *vals = holep->vals; 221 | int i1,j1; 222 | 223 | if (holep->numvals != 3) 224 | hole_error("Exactly 3 values required for a point hole.","",holep); 225 | 226 | delete_node(find_nearest_gpnode(vals[0]*units + relx, vals[1]*units + rely, 227 | vals[2]*units + relz, gp, &i1, &j1)); 228 | } 229 | 230 | /* The following function creates a hole which is in the shape of 231 | a rectangle whose edges are parallel to the ground plane edges. 232 | The 6 values in holep->vals are two (x,y,z) pairs which represent 233 | opposite corners of the rectangle. 234 | */ 235 | hole_rect(holep, gp, relx, rely, relz, units) 236 | GROUNDPLANE *gp; 237 | HoleList *holep; 238 | double relx,rely,relz,units; 239 | { 240 | NODES *node1, *node2; 241 | int i1, j1, i2, j2; 242 | double *vals = holep->vals; 243 | int i_beg, i_end, j_beg, j_end, i, j; 244 | 245 | if (holep->numvals != 6) 246 | hole_error("Exactly 6 values required for a square hole.","",holep); 247 | 248 | node1 = find_nearest_gpnode(vals[0]*units + relx, vals[1]*units + rely, 249 | vals[2]*units + relz, gp, &i1, &j1); 250 | 251 | node2 = find_nearest_gpnode(vals[3]*units + relx, vals[4]*units + rely, 252 | vals[5]*units + relz, gp, &i2, &j2); 253 | 254 | if (i1 <= i2) { 255 | i_beg = i1; 256 | i_end = i2; 257 | } 258 | else { 259 | i_beg = i2; 260 | i_end = i1; 261 | } 262 | 263 | if (j1 <= j2) { 264 | j_beg = j1; 265 | j_end = j2; 266 | } 267 | else { 268 | j_beg = j2; 269 | j_end = j1; 270 | } 271 | 272 | for(i = i_beg; i <= i_end; i++) 273 | for(j = j_beg; j <= j_end; j++) 274 | delete_node(gp->pnodes[i][j]); 275 | 276 | } 277 | 278 | /* The following function makes a hole in the shape of a circle. 279 | It takes 4 values in holep->vals. The first three are (x,y,z) of 280 | the center and the last is the radius, R. 281 | */ 282 | hole_circle(holep, gp, relx, rely, relz, units) 283 | GROUNDPLANE *gp; 284 | HoleList *holep; 285 | double relx,rely,relz,units; 286 | { 287 | NODES *node1, *node2, *nodec; 288 | int i1, j1, i2, j2; 289 | double center[3]; 290 | int i_beg, i_end, j_beg, j_end, i, j, ic, jc; 291 | double R; 292 | double ref1, ref2; 293 | double edge2; 294 | int k_up, k_down, p_left, p_right; 295 | 296 | if (holep->numvals != 4) 297 | hole_error("Exactly 4 values required for a circular hole.","(x,y,z,radius)",holep); 298 | 299 | center[0] = holep->vals[0]*units + relx; 300 | center[1] = holep->vals[1]*units + rely; 301 | center[2] = holep->vals[2]*units + relz; 302 | 303 | R = holep->vals[3]*units; 304 | 305 | /* find node nearest to center as a place to start (a 'reference')*/ 306 | nodec = find_nearest_gpnode(center[0], center[1], center[2], gp, &ic, &jc); 307 | 308 | /* The plane has it's own coordinate system with unit vectors (ux1,uy1,uz1) 309 | and (ux2, uy2, uz2) which are directed along the edges of the plane. 310 | Let's do everything in terms of them */ 311 | 312 | /*find component in the u1 and u2 direction of vector from center to nodec */ 313 | ref1 = dotp(nodec->x - center[0], nodec->y - center[1], nodec->z - center[2], 314 | gp->ux1, gp->uy1, gp->uz1); 315 | ref2 = dotp(nodec->x - center[0], nodec->y - center[1], nodec->z - center[2], 316 | gp->ux2, gp->uy2, gp->uz2); 317 | 318 | if (ref1*ref1 + ref2*ref2 > R) { 319 | fprintf(stderr, "Warning: Discretization too coarse for circle of radius %lf.\n No circlular hole made.\n", holep->vals[3]); 320 | return; 321 | } 322 | 323 | /* We will remove nodes inside the circle in strips running in u2 direction*/ 324 | k_up = (R - ref1)/gp->d1; 325 | k_down = (-R - ref1)/gp->d1; 326 | 327 | if (k_up < 0 || k_down > 0) { 328 | printf("Internal Error: k_up or k_down of the wrong sign\n"); 329 | exit(1); 330 | } 331 | 332 | /* loop through all the u2 directed strips */ 333 | for(i = k_down; i <= k_up; i++) { 334 | /* find the u2 component of a point on the strip at u1 = ref1 + i*d1 */ 335 | edge2 = sqrt(R*R - SQUARE(ref1 + i*gp->d1)); 336 | /* count number of cells to the right and left */ 337 | p_right = (edge2 - ref2)/gp->d2; 338 | p_left = (-edge2 - ref2)/gp->d2; 339 | 340 | if (-edge2 - ref2 < 0 && edge2 - ref2 > 0) 341 | for(j = p_left; j <= p_right; j++) 342 | delete_node(gp->pnodes[i+ic][j+jc]); 343 | } 344 | } 345 | 346 | hole_user1(holep, gp, relx, rely, relz, units) 347 | GROUNDPLANE *gp; 348 | HoleList *holep; 349 | double relx,rely,relz,units; 350 | { 351 | } 352 | 353 | hole_user2(holep, gp, relx, rely, relz, units) 354 | GROUNDPLANE *gp; 355 | HoleList *holep; 356 | double relx,rely,relz,units; 357 | { 358 | } 359 | 360 | hole_user3(holep, gp, relx, rely, relz, units) 361 | GROUNDPLANE *gp; 362 | HoleList *holep; 363 | double relx,rely,relz,units; 364 | { 365 | } 366 | 367 | hole_user4(holep, gp, relx, rely, relz, units) 368 | GROUNDPLANE *gp; 369 | HoleList *holep; 370 | double relx,rely,relz,units; 371 | { 372 | } 373 | 374 | hole_user5(holep, gp, relx, rely, relz, units) 375 | GROUNDPLANE *gp; 376 | HoleList *holep; 377 | double relx,rely,relz,units; 378 | { 379 | } 380 | 381 | hole_user6(holep, gp, relx, rely, relz, units) 382 | GROUNDPLANE *gp; 383 | HoleList *holep; 384 | double relx,rely,relz,units; 385 | { 386 | } 387 | 388 | hole_user7(holep, gp, relx, rely, relz, units) 389 | GROUNDPLANE *gp; 390 | HoleList *holep; 391 | double relx,rely,relz,units; 392 | { 393 | } 394 | 395 | -------------------------------------------------------------------------------- /src/fasthenry/uglieralloc.c: -------------------------------------------------------------------------------- 1 | /* # ***** sort to /src/misc 2 | # ***** */ 3 | 4 | /* A memory allocator with only the ability to free all memory allocated. 5 | It is a modification of the description below. MK 11/95 6 | */ 7 | 8 | /* 9 | memory allocator for fastcap 10 | - almost identical to Kerigan & Ritchie sec 8.7 11 | - differs in that there is no free list since fastcap never frees any memory 12 | - also the amount of memory sbrk()'d is exactly equal (within a unit) to 13 | the requested amount if its more than NALLOC units 14 | this cuts down on unused blocks usually added to the free list 15 | while still keeping the number of sbrk()'s down 16 | - the regular allocation functions are still availible for stdio to use 17 | although stdio buffers are passed over when new memory is set up 18 | - machine dependancy should be confined to the type `ALIGN' and 19 | `MORECORE()' (i.e. non-UNIX machines won't have brk(), sbrk()) 20 | - no attempt is made to make allocation efficient in terms of virtual pages 21 | */ 22 | #include 23 | 24 | // Enrico 25 | #include 26 | #include 27 | 28 | #define NALLOC 8184 /* >= sizeof(HEADER)*NALLOC bytes sbrk()'d */ 29 | #define MAGICN 0xaaaaaaaaL /* used to check fidelity of allocated blks */ 30 | #define UGDEBG 0 /* 0=> most efficient, no verification 31 | 1=> ualloc_verify() checks magicno, size 32 | 2=> ualloc_verify() prints lots to stdout 33 | - can reduce efficiency due to big HEADER */ 34 | 35 | typedef double ALIGN; /* all allocated mem starts on an ALIGN bdry */ 36 | 37 | union header { /* allocated block header - all mem allocated 38 | in units of sizeof(HEADER) bytes */ 39 | struct { 40 | #if UGDEBG == 1 || UGDEBG == 2 41 | long magicno; /* to check for overwrites */ 42 | union header *ptr; /* next allocated block */ 43 | #endif 44 | #if UGDEBG == 2 45 | union header *enlarged; /* limit of newly enlarged block */ 46 | union header *enlgdfrom; /* base pointer of newly added block */ 47 | unsigned int osize; /* size before enlargement/truncation */ 48 | unsigned int request; /* nbytes requested from allocator */ 49 | #endif 50 | unsigned int size; /* block size (memory + 1 or 2 header units) */ 51 | } s; 52 | union header *lastblock; /* For freeing (MK 11/95) */ 53 | ALIGN x; /* for alignment only, never referenced */ 54 | }; 55 | 56 | typedef union header HEADER; 57 | 58 | /* 59 | uses calloc to get a new block of memory 60 | - any header space put in by calloc is wasted 61 | - zeros memory 62 | - an alternative to mocore() but should only be used if sbrk() doesnt zero 63 | */ 64 | #define MORECORE(SIZE) (HEADER *)calloc(1, SIZE*sizeof(HEADER)) 65 | 66 | // Enrico 67 | //char *calloc(); 68 | //char *malloc(); 69 | 70 | static HEADER *base = NULL; /* base of allocated block list */ 71 | static HEADER *allocp = NULL; /* last allocated block */ 72 | static unsigned int sizeofHDR = sizeof(HEADER); 73 | 74 | static HEADER *lastblock = NULL; /* pointer to last allocated block */ 75 | /* for freeing purposes */ 76 | 77 | /* 78 | asks operating system for more memory which is added to the top block 79 | - memory not zeroed out 80 | */ 81 | static HEADER *mocore(nu) 82 | unsigned int nu; 83 | { 84 | HEADER *cp; 85 | 86 | cp = (HEADER *)calloc(nu+1,sizeofHDR); 87 | if(cp == NULL) return(NULL); 88 | 89 | /* set pointer to last block for freeing */ 90 | cp->lastblock = lastblock; 91 | lastblock = cp; 92 | 93 | #ifdef MATTDEBUG2 94 | printf("%x\n", cp); 95 | #endif 96 | 97 | return(cp + 1); 98 | } 99 | 100 | /* fills space with value */ 101 | fill_it(mem, k, nbytes) 102 | void *mem; 103 | char k; 104 | int nbytes; 105 | { 106 | /* printf("will fill: %x + 1 = %x\n",(HEADER *)mem - 1, (HEADER *)mem);*/ 107 | memset( mem, k, nbytes); 108 | } 109 | 110 | /* frees lastblock and the linked list of each block before it 111 | */ 112 | void ufree() 113 | { 114 | HEADER *ptr, *next; 115 | 116 | ptr = lastblock; 117 | while(ptr != NULL) { 118 | next = ptr->lastblock; 119 | 120 | #ifdef MATTDEBUG2 121 | printf("%x\n", ptr); 122 | #endif 123 | 124 | free(ptr); 125 | ptr = next; 126 | } 127 | 128 | allocp = lastblock = NULL; 129 | 130 | } 131 | 132 | 133 | 134 | /* 135 | ugly storage allocator 136 | - no frees 137 | - allocates in blocks at least NALLOC*sizeof(HEADER) bytes long 138 | - ultimately uses mocore(), since no frees are done (sbrk() zeros added 139 | memory) this allocator performs like calloc() w/no explicit assigns to 0 140 | */ 141 | char *ualloc(nbytes) 142 | unsigned int nbytes; 143 | { 144 | HEADER *mocore(); 145 | HEADER *p, *q; 146 | int nunits; /* size in number of sizeof(HEADER)'s */ 147 | int brkunits; /* number to add to heap */ 148 | #if UGDEBG == 2 149 | HEADER *dummy = 0x0; 150 | HEADER *dummyret = 0x0; 151 | #endif 152 | static unsigned int topblksize; /* size of current top block */ 153 | 154 | if(nbytes == 0) return(NULL); /* should probably return something else */ 155 | 156 | #if UGDEBG == 1 || UGDEBG == 2 157 | nunits = 3+(nbytes-1)/sizeofHDR; /* rm for 2 hdrs too */ 158 | #else 159 | nunits = 2+(nbytes-1)/sizeofHDR; /* rm for 1 hdr (gets subtracted later)*/ 160 | #endif 161 | 162 | if((q = allocp) == NULL) { /* no allocation yet */ 163 | if((q = allocp = base = mocore(1)) == NULL) return(NULL); 164 | #ifdef MATTDEBUG 165 | printf("started allocating: size of header == %d\n",sizeof(HEADER)); 166 | #endif 167 | topblksize = 1; 168 | #if UGDEBG == 1 || UGDEBG == 2 169 | base->s.size = 1; 170 | base->s.ptr = base; 171 | base->s.magicno = MAGICN; 172 | #endif 173 | } 174 | 175 | /* 176 | check previously allocated block for room 177 | - if it's big enough, use head (not tail) part of it 178 | - if it's not, break out more memory and discard the previous block 179 | */ 180 | if(topblksize >= nunits) { /* if it's big enough */ 181 | #if UGDEBG == 1 || UGDEBG == 2 182 | p = q; /* copy old top block pointer */ 183 | q += (nunits - 1); /* make q new top block pointer */ 184 | q->s.size = p->s.size - nunits + 1; /* upper block size */ 185 | #else 186 | allocp = q + nunits - 1; 187 | #endif 188 | topblksize -= (nunits - 1); 189 | #if UGDEBG == 2 190 | p->s.osize = p->s.size; /* save size before new block carved out */ 191 | p->s.request = nbytes; /* actual #bytes requested */ 192 | p->s.enlarged = dummy; 193 | p->s.enlgdfrom = dummyret; 194 | #endif 195 | #if UGDEBG == 1 || UGDEBG == 2 196 | q->s.ptr = base; /* top block connected back to base */ 197 | p->s.ptr = q; /* old top block pointer to new top block */ 198 | if(allocp != p) allocp->s.ptr = p; /* link previous old block */ 199 | q->s.magicno = MAGICN; 200 | p->s.size = nunits; /* set up returned block size */ 201 | allocp = q; /* save the top block pointer */ 202 | return((char *) (p+1)); /* return pntr to first unit beyond header */ 203 | #else 204 | return((char *) q); /* use old header location */ 205 | #endif 206 | } 207 | else { /* get more memory, add to top block beyond 208 | any stdio buffers made since last ualloc */ 209 | brkunits = (nunits > NALLOC) ? nunits : NALLOC; 210 | if((q = mocore(brkunits)) == NULL) return(NULL); 211 | #if UGDEBG == 1 || UGDEBG == 2 212 | q->s.size = brkunits; /* setup size, etc. of new top block */ 213 | q->s.magicno = MAGICN; 214 | #endif 215 | topblksize = brkunits; 216 | #if UGDEBG == 2 217 | dummy = q + q->s.size - 1; /* limit pointer of new block */ 218 | dummyret = q; /* base pointer of new block */ 219 | #endif 220 | /* repeat above code to aviod having a loop */ 221 | #if UGDEBG == 1 || UGDEBG == 2 222 | p = q; 223 | q += (nunits - 1); /* make q new top block pointer */ 224 | q->s.size = p->s.size - nunits + 1; /* upper block size */ 225 | #else 226 | allocp = q + nunits - 1; 227 | #endif 228 | topblksize -= (nunits - 1); 229 | #if UGDEBG == 2 230 | p->s.osize = p->s.size; /* save size before new block carved out */ 231 | p->s.request = nbytes; /* actual #bytes requested */ 232 | p->s.enlarged = dummy; 233 | p->s.enlgdfrom = dummyret; 234 | #endif 235 | #if UGDEBG == 1 || UGDEBG == 2 236 | q->s.ptr = base; /* top block connected back to base */ 237 | p->s.ptr = q; /* old top block pointer to new top block */ 238 | if(allocp != p) allocp->s.ptr = p; /* link previous old block */ 239 | q->s.magicno = MAGICN; 240 | p->s.size = nunits; /* set up returned block size */ 241 | allocp = q; /* save the top block pointer */ 242 | return((char *) (p+1)); /* return pntr to first unit beyond header */ 243 | #else 244 | return((char *) q); /* use old header location */ 245 | #endif 246 | } 247 | } 248 | 249 | /* 250 | checks for overwrites at end of blocks 251 | - checks magic numbers and sizes (UGDEBG == 1 or 2) 252 | - checks if length corresponds to pointers (UGDEBG == 1 or 2) 253 | - prints information about list of allocated blocks (UGDEBG == 2) 254 | */ 255 | void ualloc_verify() 256 | { 257 | HEADER *p; 258 | int cnt = 1; 259 | 260 | #if UGDEBG == 1 || UGDEBG == 2 261 | for(p = base;; p = p->s.ptr, cnt++) { 262 | if(p == base && cnt > 1) break; 263 | #endif 264 | #if UGDEBG == 2 265 | fprintf(stdout, 266 | "%d 0x%x 0x%x %u %u bytes (osize %u enlarged from 0x%x to 0x%x)\n", 267 | cnt, p, p->s.ptr, p->s.size, p->s.request, 268 | p->s.osize, p->s.enlgdfrom, p->s.enlarged); 269 | #endif 270 | #if UGDEBG == 1 || UGDEBG == 2 271 | if(p->s.magicno != MAGICN) { 272 | fflush(stdout); 273 | fprintf(stderr, "ualloc_verify: bad block %d magic number\n", cnt); 274 | fflush(stderr); 275 | abort(); 276 | } 277 | if(p->s.ptr - p + 1 < p->s.size) { 278 | fflush(stdout); 279 | fprintf(stderr, "ualloc_verify: bad block size ", cnt); 280 | fprintf(stderr, "(from 0x%x to 0x%x size %u)\n", p, p->s.ptr, p->s.size); 281 | fflush(stderr); 282 | abort(); 283 | } 284 | } 285 | #endif 286 | } 287 | 288 | /* 289 | compares the total address range broken out to amount requested 290 | - efficiency is 100*memcount/(sbrk(0)-base) = 100*requested/(ttl broken out) 291 | - UGDEBG == 2 prints waste values: 292 | ualloc waste = 100*(mem discarded)/(ttl broken out) 293 | stdio waste = 100*(mem discarded to apease stdio usage)/(ttl broken out) 294 | (stdio waste is often zero and ualloc waste does not include the 295 | memory lost in each header struct (a problem with many small things) 296 | - if base == NULL (not using ugly allocator), final break value is printed 297 | */ 298 | void uallocEfcy(memcount) 299 | long memcount; 300 | { 301 | #if UGDEBG == 2 302 | HEADER *p; 303 | unsigned int waste = 0; 304 | unsigned int stdiowaste = 0; 305 | int first = 1; 306 | #endif 307 | int total; 308 | // char *sbrk(); 309 | 310 | // total = (int)(sbrk(0) - (char *)base); 311 | 312 | // if(base == NULL) fprintf(stdout, "(top of memory = 0x%x", sbrk(0)); 313 | // else fprintf(stdout, "(%.3g%% efficiency", 314 | // 100*((double)memcount)/((double)total)); 315 | 316 | #if UGDEBG == 2 317 | /* loop through blocks, get total btyes wasted (by allocator) */ 318 | for(p = base;; p = p->s.ptr) { 319 | if(p == base && first == 0) break; 320 | if(p == NULL) break; /* compatability when ualloc not used */ 321 | if(p->s.request == 0) { 322 | if((p->s.ptr)->s.size >= p->s.size) { /* if block dropped bec. too sm. */ 323 | if(p != allocp) waste += p->s.size - 1; 324 | else waste += p->s.size; 325 | } 326 | else { 327 | if(p != allocp) stdiowaste += p->s.size - 1; 328 | } 329 | } 330 | first = 0; 331 | } 332 | if(p != NULL) 333 | fprintf(stdout, 334 | ", waste: %.2g%% (ualloc), %.2g%% (stdio)", 335 | 100*(double)(waste*sizeof(HEADER))/((double)total), 336 | 100*(double)(stdiowaste*sizeof(HEADER))/((double)total)); 337 | #endif 338 | fprintf(stdout, ")\n"); 339 | 340 | } 341 | -------------------------------------------------------------------------------- /src/fasthenry/direct.c: -------------------------------------------------------------------------------- 1 | /* # ***** sort to /src/direct 2 | # ***** */ 3 | #include "mulGlobal.h" 4 | 5 | double **Q2PDiag(chgs, numchgs, is_dummy, calc) 6 | charge **chgs; 7 | int numchgs, *is_dummy; 8 | int calc; 9 | { 10 | double **mat; 11 | int i, j; 12 | double calcp(); 13 | 14 | /* Allocate storage for the potential coefficients. */ 15 | CALLOC(mat, numchgs, double*, ON, AQ2PD); 16 | for(i=0; i < numchgs; i++) CALLOC(mat[i], numchgs, double, ON, AQ2PD); 17 | 18 | if(calc) { 19 | /* Compute the potential coeffs. */ 20 | /* - exclude dummy panels when they would need to carry charge 21 | - exclude dielec i/f panels when they would lead to evals at their 22 | centers (only if using two-point flux-den-diff evaluations) */ 23 | for(i=0; i < numchgs; i++) { 24 | #if NUMDPT == 2 25 | if(chgs[i]->dummy); /* don't check surface of a dummy */ 26 | else if(chgs[i]->surf->type == DIELEC || chgs[i]->surf->type == BOTH) 27 | continue; 28 | #endif 29 | for(j=0; j < numchgs; j++) { /* need to have charge on them */ 30 | #if SKIPQD == ON 31 | if(chgs[j]->pos_dummy == chgs[i] || chgs[j]->neg_dummy == chgs[i]) 32 | continue; 33 | #endif 34 | if(!is_dummy[j]) mat[i][j] = calcp(chgs[j], chgs[i], NULL); 35 | } 36 | } 37 | } 38 | 39 | #if DSQ2PD == ON 40 | dispQ2PDiag(mat, chgs, numchgs, is_dummy); 41 | #endif 42 | 43 | return(mat); 44 | } 45 | 46 | double **Q2P(qchgs, numqchgs, is_dummy, pchgs, numpchgs, calc) 47 | charge **qchgs, **pchgs; 48 | int numqchgs, numpchgs; 49 | int *is_dummy; 50 | int calc; 51 | { 52 | double **mat; 53 | int i, j; 54 | double calcp(); 55 | 56 | /* Allocate storage for the potential coefficients. P rows by Q cols. */ 57 | CALLOC(mat, numpchgs, double*, ON, AQ2P); 58 | for(i=0; i < numpchgs; i++) { 59 | CALLOC(mat[i], numqchgs, double, ON, AQ2P); 60 | if(calc) { 61 | /* exclude: 62 | - dummy panels in the charge list 63 | - dielectric i/f panels in the eval list (if doing 2-point E's)*/ 64 | #if NUMDPT == 2 65 | if(pchgs[i]->dummy); /* don't check the surface of a dummy */ 66 | else if(pchgs[i]->surf->type == DIELEC || pchgs[i]->surf->type == BOTH) 67 | continue; 68 | #endif 69 | for(j=0; j < numqchgs; j++) { /* only dummy panels in the charge list */ 70 | if(!is_dummy[j]) /* (not the eval list) are excluded */ 71 | mat[i][j] = calcp(qchgs[j], pchgs[i], NULL); 72 | /* old: pchgs[i],qchgs[j] */ 73 | } 74 | } 75 | } 76 | 77 | #if DISQ2P == ON 78 | dispQ2P(mat, qchgs, numqchgs, is_dummy, pchgs, numpchgs); 79 | #endif 80 | 81 | return(mat); 82 | } 83 | 84 | /* 85 | used only in conjunction with DMPMAT == ON and DIRSOL == ON 86 | to make 1st directlist mat = full P mat 87 | */ 88 | double **Q2Pfull(directlist, numchgs) 89 | int numchgs; 90 | cube *directlist; 91 | { 92 | int i, j, fromp, fromq, top, toq; 93 | double **mat, calcp(); 94 | cube *pq, *pp; 95 | charge **pchgs, **qchgs, *eval; 96 | 97 | /* allocate room for full P matrix */ 98 | MALLOC(mat, numchgs, double*, ON, AQ2P); 99 | for(i = 0; i < numchgs; i++) MALLOC(mat[i], numchgs, double, ON, AQ2P); 100 | 101 | /* load the matrix in the style of Q2P() - no attempt to exploit symmetry */ 102 | /* calculate interaction between every direct list entry and entire dlist */ 103 | for(pp = directlist; pp != NULL; pp = pp->dnext) { 104 | pchgs = pp->chgs; 105 | fromp = pchgs[0]->index - 1; /* row index range */ 106 | top = fromp + pp->upnumeles[0]; 107 | for(pq = directlist; pq != NULL; pq = pq->dnext) { 108 | qchgs = pq->chgs; 109 | fromq = qchgs[0]->index - 1; /* column index range */ 110 | toq = fromq + pq->upnumeles[0]; 111 | 112 | for(i = fromp; i < top; i++) { 113 | for(j = fromq; j < toq; j++) { 114 | eval = qchgs[j-fromq]; 115 | mat[i][j] = calcp(pchgs[i-fromp],eval, NULL); 116 | } 117 | } 118 | 119 | } 120 | } 121 | return(mat); 122 | } 123 | 124 | /* 125 | - returned matrix has L below the diagonal, U above (GVL1 pg 58) 126 | - if allocate == TRUE ends up storing P and LU (could be a lot) 127 | */ 128 | double **ludecomp(matin, size, allocate) 129 | double **matin; 130 | int size; 131 | int allocate; 132 | { 133 | extern int fulldirops; 134 | double factor, **mat; 135 | int i, j, k; 136 | 137 | if(allocate == TRUE) { 138 | /* allocate for LU matrix and copy A */ 139 | MALLOC(mat, size, double*, ON, AMSC); 140 | for(i = 0; i < size; i++) { 141 | MALLOC(mat[i], size, double, ON, AMSC); 142 | for(j = 0; j < size; j++) mat[i][j] = matin[i][j]; 143 | } 144 | } 145 | else mat = matin; 146 | 147 | for(k = 0; k < size-1; k++) { /* loop on rows */ 148 | if(mat[k][k] == 0.0) { 149 | fprintf(stderr, "ludecomp: zero piovt\n"); 150 | exit(0); 151 | } 152 | for(i = k+1; i < size; i++) { /* loop on remaining rows */ 153 | factor = (mat[i][k] /= mat[k][k]); 154 | fulldirops++; 155 | for(j = k+1; j < size; j++) { /* loop on remaining columns */ 156 | mat[i][j] -= (factor*mat[k][j]); 157 | fulldirops++; 158 | } 159 | } 160 | } 161 | return(mat); 162 | } 163 | 164 | /* 165 | For direct solution of Pq = psi, used if DIRSOL == ON or if preconditioning. 166 | */ 167 | void solve(mat, x, b, size) 168 | double **mat, *x, *b; 169 | int size; 170 | { 171 | extern int fulldirops; 172 | int i, j; 173 | 174 | /* copy rhs */ 175 | if(x != b) for(i = 0; i < size; i++) x[i] = b[i]; 176 | 177 | /* forward elimination */ 178 | for(i = 0; i < size; i++) { /* loop on pivot row */ 179 | for(j = i+1; j < size; j++) { /* loop on elimnation row */ 180 | x[j] -= mat[j][i]*x[i]; 181 | fulldirops++; 182 | } 183 | } 184 | 185 | /* back substitution */ 186 | for(i--; i > -1; i--) { /* loop on rows */ 187 | for(j = i+1; j < size; j++) { /* loop on columns */ 188 | x[i] -= mat[i][j]*x[j]; 189 | fulldirops++; 190 | } 191 | x[i] /= mat[i][i]; 192 | fulldirops++; 193 | } 194 | } 195 | 196 | /* 197 | In-place inverts a matrix using guass-jordan. 198 | - is_dummy[i] = 0 => ignore row/col i 199 | */ 200 | void invert(mat, size, reorder) 201 | double **mat; 202 | int size, *reorder; 203 | { 204 | int i, j, k, best; 205 | double normal, multiplier, bestval, nextbest; 206 | /* 207 | matlabDump(mat,size,"p"); 208 | */ 209 | for(i=0; i < size; i++) { 210 | best = i; 211 | bestval = ABS(mat[i][i]); 212 | for(j = i+1; j < size; j++) { 213 | nextbest = ABS(mat[i][j]); 214 | if(nextbest > bestval) { 215 | best = j; 216 | bestval = nextbest; 217 | } 218 | } 219 | 220 | /* If reordering, find the best pivot. */ 221 | if(reorder != NULL) { 222 | reorder[i] = best; 223 | if(best != i) { 224 | for(k=0; k < size; k++) { 225 | bestval = mat[k][best]; 226 | mat[k][best] = mat[k][i]; 227 | mat[k][i] = bestval; 228 | } 229 | } 230 | } 231 | 232 | /* First i^{th} column of A. */ 233 | normal = 1.0 / mat[i][i]; 234 | for(j=0; j < size; j++) { 235 | mat[j][i] *= normal; 236 | } 237 | mat[i][i] = normal; 238 | 239 | /* Fix the backward columns. */ 240 | for(j=0; j < size; j++) { 241 | if(j != i) { 242 | multiplier = -mat[i][j]; 243 | for(k=0; k < size; k++) { 244 | if(k != i) mat[k][j] += mat[k][i] * multiplier; 245 | else mat[k][j] = mat[k][i] * multiplier; 246 | } 247 | } 248 | } 249 | } 250 | 251 | /* Unravel the reordering, starting with the last column. */ 252 | if(reorder != NULL) { 253 | for(i=size-2; i >= 0; i--) { 254 | if(reorder[i] != i) { 255 | for(k=0; k < size; k++) { 256 | bestval = mat[k][i]; 257 | mat[k][reorder[i]] = mat[k][i]; 258 | mat[k][i] = bestval; 259 | } 260 | } 261 | } 262 | } 263 | /* 264 | matlabDump(mat,size,"c"); 265 | */ 266 | 267 | } 268 | 269 | /* 270 | Used in conjuction with invert() to remove dummy row/columns 271 | comp_rows = TRUE => remove rows corresponding to ones in is_dummy[] 272 | comp_rows = FALSE => remove cols corresponding to ones in is_dummy[] 273 | comp_rows = BOTH => remove both rows and columns 274 | returns number of rows/cols in compressed matrix 275 | */ 276 | int compressMat(mat, size, is_dummy, comp_rows) 277 | double **mat; 278 | int size, *is_dummy, comp_rows; 279 | { 280 | static int *cur_order; 281 | static int cur_order_array_size = 0; 282 | int cur_order_size, i, j, k; 283 | 284 | if(cur_order_array_size < size) { 285 | CALLOC(cur_order, size, int, ON, AMSC); 286 | } 287 | 288 | /* figure the new order vector (cur_order[i] = index of ith row/col) */ 289 | for(i = cur_order_size = 0; i < size; i++) { 290 | if(!is_dummy[i]) cur_order[cur_order_size++] = i; 291 | } 292 | 293 | if(comp_rows == TRUE || comp_rows == BOTH) { 294 | /* compress by removing rows from the matrix */ 295 | for(i = 0; i < cur_order_size; i++) { 296 | if((k = cur_order[i]) == i) continue; /* if not reordered */ 297 | for(j = 0; j < size; j++) { /* copy the row to its new location */ 298 | mat[i][j] = mat[k][j]; 299 | } 300 | } 301 | } 302 | if(comp_rows == FALSE || comp_rows == BOTH) { 303 | /* compress by removing columns from the matrix */ 304 | for(j = 0; j < cur_order_size; j++) { 305 | if((k = cur_order[j]) == j) continue; /* if not reordered */ 306 | for(i = 0; i < size; i++) { /* copy the col to its new location */ 307 | mat[i][j] = mat[i][k]; 308 | } 309 | } 310 | } 311 | return(cur_order_size); 312 | } 313 | 314 | /* 315 | Used in conjuction with invert() to add dummy row/columns 316 | exp_rows = TRUE => add rows corresponding to ones in is_dummy[] 317 | exp_rows = FALSE => add cols corresponding to ones in is_dummy[] 318 | exp_rows = BOTH => add rows and columns 319 | */ 320 | void expandMat(mat, size, comp_size, is_dummy, exp_rows) 321 | double **mat; 322 | int size, *is_dummy, exp_rows, comp_size; 323 | { 324 | int i, j, k, next_rc; 325 | 326 | if(exp_rows == TRUE || exp_rows == BOTH) { 327 | next_rc = comp_size - 1; 328 | /* add rows to the matrix starting from the bottom */ 329 | for(i = size - 1; i >= 0; i--) { 330 | if(is_dummy[i]) { /* zero out dummy row */ 331 | for(j = 0; j < size; j++) mat[i][j] = 0.0; 332 | } 333 | else { /* copy the row from its compressed location */ 334 | for(j = 0; j < size; j++) mat[i][j] = mat[next_rc][j]; 335 | next_rc--; 336 | } 337 | } 338 | } 339 | if(exp_rows == FALSE || exp_rows == BOTH) { 340 | next_rc = comp_size - 1; 341 | /* add columns to the matrix starting from the right */ 342 | for(j = size - 1; j >= 0; j--) { 343 | if(is_dummy[j]) { /* zero out dummy column */ 344 | for(i = 0; i < size; i++) mat[i][j] = 0.0; 345 | } 346 | else { /* copy the col from its compressed location */ 347 | for(i = 0; i < size; i++) mat[i][j] = mat[i][next_rc]; 348 | next_rc--; 349 | } 350 | } 351 | } 352 | } 353 | 354 | /* 355 | Checks to see if the matrix has the M-matrix sign pattern and if 356 | it is diagonally dominant. 357 | */ 358 | matcheck(mat, rows, size) 359 | double **mat; 360 | int rows, size; 361 | { 362 | double rowsum; 363 | int i, j; 364 | 365 | for(i = rows - 1; i >= 0; i--) { 366 | for(rowsum = 0.0, j = size - 1; j >= 0; j--) { 367 | if((i != j) && (mat[i][j] > 0.0)) { 368 | printf("violation mat[%d][%d] =%g\n", i, j, mat[i][j]); 369 | } 370 | if(i != j) rowsum += ABS(mat[i][j]); 371 | } 372 | printf("row %d diag=%g rowsum=%g\n", i, mat[i][i], rowsum); 373 | if(rowsum > mat[i][i]) { 374 | for(j = size - 1; j >= 0; j--) { 375 | printf("col%d = %g ", j, mat[i][j]); 376 | } 377 | printf("\n"); 378 | } 379 | } 380 | } 381 | 382 | 383 | matlabDump(mat, size, name) 384 | double **mat; 385 | int size; 386 | char *name; 387 | { 388 | FILE *foo; 389 | int i,j; 390 | char fname[100]; 391 | 392 | sprintf(fname, "%s.m", name); 393 | foo = fopen(fname, "w"); 394 | fprintf(foo, "%s = [\n", name); 395 | for(i=0; i < size; i++) { 396 | for(j=0; j < size; j++) { 397 | fprintf(foo, "%.10e ", mat[i][j]); 398 | } 399 | fprintf(foo, "\n"); 400 | } 401 | fprintf(foo, "]\n"); 402 | } 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | -------------------------------------------------------------------------------- /src/fasthenry/SetupMulti.c: -------------------------------------------------------------------------------- 1 | /* this is 'fastcap.c' */ 2 | #include "induct.h" 3 | 4 | ssystem *SetupMulti(chglist, indsys) 5 | charge *chglist; 6 | SYS *indsys; 7 | { 8 | int ttliter, i, j, num_cond; 9 | charge *nq, *input_problem(); 10 | ssystem *sys, *mulInit(); 11 | double **capmat, dirtimesav, mulsetup, initalltime, ttlsetup, ttlsolve; 12 | double relperm; 13 | int autmom, autlev, numMom, numLev; 14 | 15 | int pseudo_lev; /* level for breaking up only */ 16 | 17 | extern int fulldirops, fullPqops; 18 | extern int num_dummy_panels, num_dielec_panels; 19 | extern int num_both_panels, num_cond_panels, up_size, eval_size; 20 | extern char *title, *ps_file_base; 21 | extern long memcount; 22 | extern double prectime, conjtime, dirtime, multime, uptime, downtime; 23 | extern double evaltime, lutime, fullsoltime, prsetime; 24 | extern char *kill_name_list; 25 | 26 | Name *name_list; 27 | 28 | #if DUMPPS == ON || DUMPPS == ALL 29 | char filename[BUFSIZ]; 30 | #endif 31 | 32 | #if CAPVEW == ON 33 | extern char **argvals; 34 | extern int argcnt, m_, q_, dd_; 35 | extern double ***axes; 36 | #endif 37 | 38 | /* initialize memory and time counters, etc. */ 39 | fulldirops = fullPqops = 0; 40 | prectime = conjtime = dirtime = multime = uptime = downtime = 0.0; 41 | evaltime = lutime = fullsoltime = mulsetup = 0.0; 42 | /* memcount = 0; Do this in induct.c */ 43 | /* CALLOC(title, BUFSIZ, char, ON, AMSC); */ 44 | 45 | /* initialize defaults, etc */ 46 | autmom = autlev = ON; 47 | relperm = 1.0; 48 | 49 | #if CAPVEW == ON 50 | /* argvals = argv; 51 | argcnt = argc; 52 | */ 53 | CALLOC(axes, 10, double **, ON, AMSC); 54 | for(i = 0; i < 10; i++) { 55 | CALLOC(axes[i], 2, double *, ON, AMSC); 56 | for(j = 0; j < 2; j++) { 57 | CALLOC(axes[i][j], 3, double, ON, AMSC); 58 | } 59 | } 60 | #endif 61 | 62 | /* get the list of all panels in the problem */ 63 | /* - many command line parameters having to do with the postscript 64 | file dumping interface are passed back via globals (see mulGlobal.c) */ 65 | /* chglist = input_problem(argv, argc, &autmom, &autlev, &relperm, 66 | &numMom, &numLev, &name_list, &num_cond); 67 | */ 68 | if(autmom == ON) numMom = DEFORD; 69 | else numMom = DEFORD; 70 | 71 | #if DIRSOL == ON || EXPGCR == ON 72 | /*fprintf(stderr, "DIRSOL and EXPGCR compile options not implemented\n"); 73 | exit(0);*/ 74 | *numLev = 0; /* put all the charges in first cube */ 75 | *autlev = OFF; 76 | #endif 77 | 78 | #if CAPVEW == ON 79 | /* if no fastcap run is to be done, just dump the psfile */ 80 | /* 81 | if(m_) { 82 | if(!q_) get_ps_file_base(argv, argc); 83 | dump_ps_geometry(chglist, NULL, 0, dd_); 84 | exit(0); 85 | } 86 | */ 87 | #endif 88 | 89 | /* the following is added for FastHenry to alter settings for mulInit()*/ 90 | 91 | autlev = OFF; 92 | numMom = indsys->opts->order; 93 | if (indsys->opts->level == AUTO) 94 | autlev = ON; 95 | else 96 | numLev = indsys->opts->level; 97 | 98 | /* 99 | if (numLev == 0) { 100 | printf("Level to break up segments:"); 101 | scanf("%d",&pseudo_lev); 102 | } 103 | else 104 | */ 105 | pseudo_lev = numLev; 106 | 107 | /* starttimer; */ 108 | sys = mulInit(autlev, numLev, numMom, chglist, indsys, pseudo_lev); 109 | /*Set up cubes, charges.*/ 110 | /* stoptimer */ 111 | // initalltime = dtime; 112 | 113 | numLev = sys->depth; 114 | 115 | /* 116 | sys->num_cond = num_cond; 117 | sys->cond_names = name_list; 118 | */ 119 | 120 | fprintf(stdout, "\nMultipole Summary\n"); 121 | 122 | #if CMDDAT == ON 123 | fprintf(stdout, " Expansion order: %d\n", numMom); 124 | if (sys->depth == sys->real_depth) 125 | fprintf(stdout, " Number of partitioning levels: %d\n", numLev); 126 | else { 127 | fprintf(stdout, " Number of partitioning levels: %d\n", sys->real_depth); 128 | fprintf(stdout, " Number of levels for Preconditioner: %d\n", numLev); 129 | } 130 | /* fprintf(stdout, " Overall permittivity factor: %.3g\n", relperm); */ 131 | #endif 132 | 133 | /* Figure out number of panels and conductors. */ 134 | eval_size = up_size = num_dummy_panels = num_dielec_panels = 0; 135 | num_both_panels = num_cond_panels = 0; 136 | for(nq = chglist; nq != NULL; nq = nq->next) { 137 | if(nq->dummy) num_dummy_panels++; 138 | else if(nq->surf->type == CONDTR) { 139 | num_cond_panels++; 140 | } 141 | else if(nq->surf->type == DIELEC) num_dielec_panels++; 142 | else if(nq->surf->type == BOTH) num_both_panels++; 143 | } 144 | up_size = num_cond_panels + num_both_panels + num_dielec_panels; 145 | eval_size = up_size + num_dummy_panels; 146 | 147 | #if DISSRF == OFF 148 | /* fprintf(stdout, "Title: `%s'\n", title); */ 149 | #endif 150 | fprintf(stdout, " Total number of filaments: %d\n", up_size); 151 | #if 1==0 152 | fprintf(stdout, " Number of conductor panels: %d\n", num_cond_panels); 153 | fprintf(stdout, " Number of dielectric interface panels: %d\n", 154 | num_dielec_panels); 155 | fprintf(stdout, 156 | " Number of thin conductor on dielectric interface panels: %d\n", 157 | num_both_panels); 158 | /*fprintf(stdout, " Number of extra evaluation points: %d\n", 159 | num_dummy_panels);*/ 160 | fprintf(stdout, " Number of conductors: %d\n", num_cond); 161 | #endif 162 | 163 | /*********************************************************************/ 164 | /* exit now if we only want to do multipole setup and never evaluate */ 165 | if (indsys->opts->mat_vect_prod == DIRECT) { 166 | /* fprintf(stdout, " Inductance mem allocated: %7.d kilobytes\n", 167 | memIND/1024); */ 168 | return sys; 169 | } 170 | /*********************************************************************/ 171 | 172 | #if NAMDAT == ON 173 | dumpCondNames(stdout, name_list); 174 | #endif 175 | 176 | if(num_both_panels > 0) { 177 | fprintf(stderr, 178 | "Thin cond panels on dielectric interfaces not supported\n"); 179 | exit(0); 180 | } 181 | 182 | #if CKCLST == ON 183 | fprintf(stdout, "Checking panels..."); 184 | if(has_duplicate_panels(stdout, chglist)) { 185 | fprintf(stdout, "charge list has duplicates\n"); 186 | exit(-1); 187 | } 188 | fprintf(stdout, "no duplicates\n"); 189 | #endif 190 | 191 | #if MULDAT == ON 192 | dumpMulSet(sys, numLev, numMom); 193 | #endif 194 | fflush(stdout); 195 | 196 | /* starttimer; */ 197 | mulMultiAlloc(MAX(sys->max_eval_pnt, sys->max_panel), numMom, sys->depth); 198 | /* stoptimer */ 199 | // initalltime += dtime; /* save initial allocation time */ 200 | 201 | #if DUMPPS == ON || DUMPPS == ALL 202 | strcpy(filename, "psmat.ps"); 203 | dump_ps_mat(filename, 0, 0, eval_size, eval_size, argv, argc, OPEN); 204 | #endif 205 | 206 | mulMatDirect(sys); /* Compute the direct part matrices. */ 207 | 208 | #if DIRSOL == OFF /* with DIRSOL just want to skip to solve */ 209 | 210 | #if PRECOND == BD 211 | /* starttimer; */ 212 | bdmulMatPrecond(sys); 213 | /* stoptimer */ 214 | // prsetime = dtime; /* preconditioner set up time */ 215 | #endif 216 | 217 | #if PRECOND == OL 218 | /* starttimer; */ 219 | olmulMatPrecond(sys); 220 | /* stoptimer */ 221 | // prsetime = dtime; /* preconditioner set up time */ 222 | #endif 223 | 224 | #if DMPREC == ON 225 | dump_preconditioner(sys, chglist, 1); /* dump prec. and P to matlab file */ 226 | #endif 227 | 228 | #if DPSYSD == ON 229 | dissys(sys); 230 | #endif 231 | 232 | #if CKDLST == ON 233 | chkList(sys, DIRECT); 234 | #endif 235 | 236 | #endif /* DIRSOL == OFF */ 237 | dumpnums(ON, eval_size, up_size); /* save num/type of pot. coeff calcs */ 238 | 239 | dirtimesav = dirtime; /* save direct matrix setup time */ 240 | dirtime = 0.0; /* make way for direct solve time */ 241 | 242 | #if DIRSOL == OFF 243 | 244 | #if DUMPPS == ON 245 | dump_ps_mat(filename, 0, 0, eval_size, eval_size, argv, argc, CLOSE); 246 | #endif 247 | 248 | /* starttimer; */ 249 | mulMatUp(sys); /* Compute the upward pass matrices. */ 250 | 251 | #if DNTYPE == NOSHFT 252 | mulMatDown(sys); /* find matrices for no L2L shift dwnwd pass */ 253 | #endif 254 | 255 | #if DNTYPE == GRENGD 256 | mulMatDown(sys); /* find matrices for full Greengard dnwd pass*/ 257 | #endif 258 | 259 | #if CKDLST == ON 260 | chkList(sys, DIRECT); 261 | chkLowLev(sys, DIRECT); 262 | chkEvalLstD(sys, DIRECT); 263 | #endif 264 | 265 | mulMatEval(sys); /* set up matrices for evaluation pass */ 266 | 267 | /* stoptimer */ 268 | // mulsetup = dtime; /* save multipole matrix setup time */ 269 | 270 | dumpnums(OFF, eval_size, up_size); /* dump num/type of pot. coeff calcs */ 271 | 272 | #if DUMPPS == ALL 273 | dump_ps_mat(filename, 0, 0, eval_size, eval_size, argv, argc, CLOSE); 274 | #endif 275 | 276 | #if DISSYN == ON 277 | dumpSynop(sys); 278 | #endif 279 | 280 | #if DMTCNT == ON 281 | dumpMatBldCnts(sys); 282 | #endif 283 | 284 | #endif /* DIRSOL == ON */ 285 | /* 286 | fprintf(stdout, "\nITERATION DATA"); 287 | ttliter = capsolve(&capmat, sys, chglist, eval_size, up_size, num_cond, 288 | name_list); 289 | */ 290 | #if MKSDAT == ON /* dump symmetrized, 4 pi eps scaled matrix */ 291 | /* mksCapDump(capmat, num_cond, relperm, &name_list); */ 292 | #endif 293 | 294 | #if TIMDAT == ON 295 | ttlsetup = initalltime + dirtimesav + mulsetup; 296 | multime = uptime + downtime + evaltime; 297 | ttlsolve = dirtime + multime + prectime + conjtime; 298 | 299 | if (indsys->opts->debug == ON) 300 | fprintf(stdout, "\nTIME AND MEMORY USAGE SYNOPSIS\n"); 301 | #endif 302 | 303 | #ifdef OTHER 304 | if(TIMDAT == ON) { 305 | fprintf(stdout, 306 | "Warning: compilation with OTHER flag gives incorrect times\n"); 307 | } 308 | #endif 309 | 310 | #if TIMDAT == ON 311 | #if 1==0 312 | fprintf(stdout, "Total time: %g\n", ttlsetup + ttlsolve); 313 | fprintf(stdout, " Total setup time: %g\n", ttlsetup); 314 | fprintf(stdout, " Direct matrix setup time: %g\n", dirtimesav); 315 | fprintf(stdout, " Multipole matrix setup time: %g\n", mulsetup); 316 | fprintf(stdout, " Initial misc. allocation time: %g\n", initalltime); 317 | fprintf(stdout, " Total iterative P*q = psi solve time: %g\n", ttlsolve); 318 | fprintf(stdout, " P*q product time, direct part: %g\n", dirtime); 319 | fprintf(stdout, " Total P*q time, multipole part: %g\n", multime); 320 | fprintf(stdout, " Upward pass time: %g\n", uptime); 321 | fprintf(stdout, " Downward pass time: %g\n", downtime); 322 | fprintf(stdout, " Evaluation pass time: %g\n", evaltime); 323 | fprintf(stdout, " Preconditioner solution time: %g\n", prectime); 324 | fprintf(stdout, " Iterative loop overhead time: %g\n", conjtime); 325 | 326 | if(DIRSOL == ON) { /* if solution is done by Gaussian elim. */ 327 | fprintf(stdout,"\nTotal direct, full matrix LU factor time: %g\n",lutime); 328 | fprintf(stdout,"Total direct, full matrix solve time: %g\n",fullsoltime); 329 | fprintf(stdout, "Total direct operations: %d\n", fulldirops); 330 | } 331 | else if(EXPGCR == ON) { /* if solution done iteratively w/o multis */ 332 | fprintf(stdout,"\nTotal A*q operations: %d (%d/iter)\n", 333 | fullPqops, fullPqops/ttliter); 334 | } 335 | #endif 336 | 337 | if (indsys->opts->debug == ON) { 338 | fprintf(stdout, "Total memory allocated: %d kilobytes ", memcount/1024); 339 | uallocEfcy(memcount); 340 | 341 | fprintf(stdout, " Q2M matrix memory allocated: %7.d kilobytes\n", 342 | memQ2M/1024); 343 | memcount = memQ2M; 344 | fprintf(stdout, " Q2L matrix memory allocated: %7.d kilobytes\n", 345 | memQ2L/1024); 346 | memcount += memQ2L; 347 | fprintf(stdout, " Q2P matrix memory allocated: %7.d kilobytes\n", 348 | memQ2P/1024); 349 | memcount += memQ2P; 350 | fprintf(stdout, " L2L matrix memory allocated: %7.d kilobytes\n", 351 | memL2L/1024); 352 | memcount += memL2L; 353 | fprintf(stdout, " M2M matrix memory allocated: %7.d kilobytes\n", 354 | memM2M/1024); 355 | memcount += memM2M; 356 | fprintf(stdout, " M2L matrix memory allocated: %7.d kilobytes\n", 357 | memM2L/1024); 358 | memcount += memM2L; 359 | fprintf(stdout, " M2P matrix memory allocated: %7.d kilobytes\n", 360 | memM2P/1024); 361 | memcount += memM2P; 362 | fprintf(stdout, " L2P matrix memory allocated: %7.d kilobytes\n", 363 | memL2P/1024); 364 | memcount += memL2P; 365 | fprintf(stdout, " Q2PD matrix memory allocated: %7.d kilobytes\n", 366 | memQ2PD/1024); 367 | memcount += memQ2PD; 368 | fprintf(stdout, " Miscellaneous mem. allocated: %7.d kilobytes\n", 369 | memMSC/1024); 370 | memcount += memMSC; 371 | fprintf(stdout, " Inductance mem allocated: %7.d kilobytes\n", 372 | memIND/1024); 373 | memcount += memIND; 374 | fprintf(stdout, " Total memory (check w/above): %7.d kilobytes\n", 375 | memcount/1024); 376 | } 377 | #endif 378 | 379 | return sys; 380 | } 381 | -------------------------------------------------------------------------------- /src/fasthenry/writefastcap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "induct.h" 4 | 5 | 6 | /* this writes a file of faces of the segments suitable to be 7 | read in by keith's program for generating postscript images */ 8 | 9 | void writefastcap(fname, shading_name, indsys) 10 | char *fname, *shading_name; 11 | SYS *indsys; 12 | { 13 | SEGMENT *seg; 14 | NODES *node0, *node1; 15 | double x,y ,z, xbotr, ybotr, zbotr; 16 | int i, j, k; 17 | double hx,hy,hz,mag,wx,wy,wz, height, width; 18 | FILE *fp, *shade_fp; 19 | SEGMENT *segment = indsys->segment; 20 | GROUNDPLANE *gp; 21 | int thin; 22 | 23 | fp = fopen(fname,"w"); 24 | if (fp == NULL) { 25 | printf("can't open zbuffile to write \n"); 26 | exit(1); 27 | } 28 | 29 | shade_fp = fopen(shading_name,"w"); 30 | if (fp == NULL) { 31 | printf("can't open shading file to write \n"); 32 | exit(1); 33 | } 34 | 35 | /* choose shades for segments and save in seg.is_deleted */ 36 | assign_shades(indsys); 37 | 38 | fprintf(fp, "0 This is an inductance picture \n"); 39 | for(i = 0, seg = segment; seg != NULL; seg = seg->next, i++) { 40 | if (seg->type == GPTYPE && indsys->opts->gp_draw == OFF) 41 | continue; /* skip gp segs */ 42 | node0 = seg->node[0]; 43 | node1 = seg->node[1]; 44 | height = seg->height; 45 | width = seg->width; 46 | if (seg->widthdir != NULL) { 47 | wx = seg->widthdir[XX]; 48 | wy = seg->widthdir[YY]; 49 | wz = seg->widthdir[ZZ]; 50 | } 51 | else { 52 | /* default for width direction is in x-y plane perpendic to length*/ 53 | /* so do cross product with unit z*/ 54 | wx = -(node1->y - node0->y)*1.0; 55 | wy = (node1->x - node0->x)*1.0; 56 | wz = 0; 57 | if ( fabs(wx/seg->length) < EPS && fabs(wy/seg->length) < EPS) { 58 | /* if all of x-y is perpendic to length, then choose x direction */ 59 | wx = 1.0; 60 | wy = 0; 61 | } 62 | mag = sqrt(wx*wx + wy*wy + wz*wz); 63 | wx = wx/mag; 64 | wy = wy/mag; 65 | wz = wz/mag; 66 | } 67 | hx = -wy*(node1->z - node0->z) + (node1->y - node0->y)*wz; 68 | hy = -wz*(node1->x - node0->x) + (node1->z - node0->z)*wx; 69 | hz = -wx*(node1->y - node0->y) + (node1->x - node0->x)*wy; 70 | mag = sqrt(hx*hx + hy*hy + hz*hz); 71 | hx = hx/mag; 72 | hy = hy/mag; 73 | hz = hz/mag; 74 | 75 | if (seg->type == GPTYPE && indsys->opts->gp_draw == THIN) 76 | thin = TRUE; 77 | else 78 | thin = FALSE; 79 | 80 | 81 | #if 1==0 82 | /* first node end */ 83 | fprintf(fp, "Q %d ",i); 84 | x = node0->x - 0.5 * wx * width + 0.5 * hx * height; 85 | y = node0->y - 0.5 * wy * width + 0.5 * hy * height; 86 | z = node0->z - 0.5 * wz * width + 0.5 * hz * height; 87 | fprintf(fp,"%lg %lg %lg ",x,y,z); 88 | 89 | x = node0->x - 0.5 * wx * width - 0.5 * hx * height; 90 | y = node0->y - 0.5 * wy * width - 0.5 * hy * height; 91 | z = node0->z - 0.5 * wz * width - 0.5 * hz * height; 92 | fprintf(fp,"%lg %lg %lg ",x,y,z); 93 | 94 | x = node0->x + 0.5 * wx * width - 0.5 * hx * height; 95 | y = node0->y + 0.5 * wy * width - 0.5 * hy * height; 96 | z = node0->z + 0.5 * wz * width - 0.5 * hz * height; 97 | fprintf(fp,"%lg %lg %lg ",x,y,z); 98 | 99 | x = node0->x + 0.5 * wx * width + 0.5 * hx * height; 100 | y = node0->y + 0.5 * wy * width + 0.5 * hy * height; 101 | z = node0->z + 0.5 * wz * width + 0.5 * hz * height; 102 | fprintf(fp,"%lg %lg %lg ",x,y,z); 103 | 104 | fprintf(fp,"\n"); 105 | /* write out shade of grey to color */ 106 | fprintf(shade_fp,"%d\n",seg->is_deleted); 107 | 108 | /* end at other node */ 109 | fprintf(fp, "Q %d ",i); 110 | x = node1->x - 0.5 * wx * width + 0.5 * hx * height; 111 | y = node1->y - 0.5 * wy * width + 0.5 * hy * height; 112 | z = node1->z - 0.5 * wz * width + 0.5 * hz * height; 113 | fprintf(fp,"%lg %lg %lg ",x,y,z); 114 | 115 | x = node1->x - 0.5 * wx * width - 0.5 * hx * height; 116 | y = node1->y - 0.5 * wy * width - 0.5 * hy * height; 117 | z = node1->z - 0.5 * wz * width - 0.5 * hz * height; 118 | fprintf(fp,"%lg %lg %lg ",x,y,z); 119 | 120 | x = node1->x + 0.5 * wx * width - 0.5 * hx * height; 121 | y = node1->y + 0.5 * wy * width - 0.5 * hy * height; 122 | z = node1->z + 0.5 * wz * width - 0.5 * hz * height; 123 | fprintf(fp,"%lg %lg %lg ",x,y,z); 124 | 125 | x = node1->x + 0.5 * wx * width + 0.5 * hx * height; 126 | y = node1->y + 0.5 * wy * width + 0.5 * hy * height; 127 | z = node1->z + 0.5 * wz * width + 0.5 * hz * height; 128 | fprintf(fp,"%lg %lg %lg ",x,y,z); 129 | 130 | fprintf(fp,"\n"); 131 | /* write out shade of grey to color */ 132 | fprintf(shade_fp,"%d\n",seg->is_deleted); 133 | #endif 134 | 135 | if (thin == FALSE) { 136 | /* left side */ 137 | fprintf(fp, "Q %d ",i); 138 | x = node0->x - 0.5 * wx * width + 0.5 * hx * height; 139 | y = node0->y - 0.5 * wy * width + 0.5 * hy * height; 140 | z = node0->z - 0.5 * wz * width + 0.5 * hz * height; 141 | fprintf(fp,"%lg %lg %lg ",x,y,z); 142 | 143 | x = node0->x - 0.5 * wx * width - 0.5 * hx * height; 144 | y = node0->y - 0.5 * wy * width - 0.5 * hy * height; 145 | z = node0->z - 0.5 * wz * width - 0.5 * hz * height; 146 | fprintf(fp,"%lg %lg %lg ",x,y,z); 147 | 148 | x = node1->x - 0.5 * wx * width - 0.5 * hx * height; 149 | y = node1->y - 0.5 * wy * width - 0.5 * hy * height; 150 | z = node1->z - 0.5 * wz * width - 0.5 * hz * height; 151 | 152 | fprintf(fp,"%lg %lg %lg ",x,y,z); 153 | x = node1->x - 0.5 * wx * width + 0.5 * hx * height; 154 | y = node1->y - 0.5 * wy * width + 0.5 * hy * height; 155 | z = node1->z - 0.5 * wz * width + 0.5 * hz * height; 156 | fprintf(fp,"%lg %lg %lg ",x,y,z); 157 | 158 | fprintf(fp,"\n"); 159 | /* write out shade of grey to color */ 160 | fprintf(shade_fp,"%d\n",seg->is_deleted); 161 | 162 | /* right side */ 163 | fprintf(fp, "Q %d ",i); 164 | x = node0->x + 0.5 * wx * width - 0.5 * hx * height; 165 | y = node0->y + 0.5 * wy * width - 0.5 * hy * height; 166 | z = node0->z + 0.5 * wz * width - 0.5 * hz * height; 167 | fprintf(fp,"%lg %lg %lg ",x,y,z); 168 | 169 | x = node0->x + 0.5 * wx * width + 0.5 * hx * height; 170 | y = node0->y + 0.5 * wy * width + 0.5 * hy * height; 171 | z = node0->z + 0.5 * wz * width + 0.5 * hz * height; 172 | fprintf(fp,"%lg %lg %lg ",x,y,z); 173 | 174 | x = node1->x + 0.5 * wx * width + 0.5 * hx * height; 175 | y = node1->y + 0.5 * wy * width + 0.5 * hy * height; 176 | z = node1->z + 0.5 * wz * width + 0.5 * hz * height; 177 | fprintf(fp,"%lg %lg %lg ",x,y,z); 178 | 179 | x = node1->x + 0.5 * wx * width - 0.5 * hx * height; 180 | y = node1->y + 0.5 * wy * width - 0.5 * hy * height; 181 | z = node1->z + 0.5 * wz * width - 0.5 * hz * height; 182 | fprintf(fp,"%lg %lg %lg ",x,y,z); 183 | fprintf(fp, "\n"); 184 | /* write out shade of grey to color */ 185 | fprintf(shade_fp,"%d\n",seg->is_deleted); 186 | } 187 | 188 | /* top */ 189 | fprintf(fp, "Q %d ",i); 190 | x = node0->x - 0.5 * wx * width + 0.5 * hx * height; 191 | y = node0->y - 0.5 * wy * width + 0.5 * hy * height; 192 | z = node0->z - 0.5 * wz * width + 0.5 * hz * height; 193 | fprintf(fp,"%lg %lg %lg ",x,y,z); 194 | 195 | x = node0->x + 0.5 * wx * width + 0.5 * hx * height; 196 | y = node0->y + 0.5 * wy * width + 0.5 * hy * height; 197 | z = node0->z + 0.5 * wz * width + 0.5 * hz * height; 198 | fprintf(fp,"%lg %lg %lg ",x,y,z); 199 | 200 | x = node1->x + 0.5 * wx * width + 0.5 * hx * height; 201 | y = node1->y + 0.5 * wy * width + 0.5 * hy * height; 202 | z = node1->z + 0.5 * wz * width + 0.5 * hz * height; 203 | fprintf(fp,"%lg %lg %lg ",x,y,z); 204 | x = node1->x - 0.5 * wx * width + 0.5 * hx * height; 205 | y = node1->y - 0.5 * wy * width + 0.5 * hy * height; 206 | z = node1->z - 0.5 * wz * width + 0.5 * hz * height; 207 | fprintf(fp,"%lg %lg %lg ",x,y,z); 208 | 209 | fprintf(fp,"\n"); 210 | /* write out shade of grey to color */ 211 | fprintf(shade_fp,"%d\n",seg->is_deleted); 212 | 213 | if (thin == FALSE) { 214 | /* bottom */ 215 | fprintf(fp, "Q %d ",i); 216 | 217 | x = node0->x - 0.5 * wx * width - 0.5 * hx * height; 218 | y = node0->y - 0.5 * wy * width - 0.5 * hy * height; 219 | z = node0->z - 0.5 * wz * width - 0.5 * hz * height; 220 | fprintf(fp,"%lg %lg %lg ",x,y,z); 221 | 222 | x = node0->x + 0.5 * wx * width - 0.5 * hx * height; 223 | y = node0->y + 0.5 * wy * width - 0.5 * hy * height; 224 | z = node0->z + 0.5 * wz * width - 0.5 * hz * height; 225 | fprintf(fp,"%lg %lg %lg ",x,y,z); 226 | x = node1->x + 0.5 * wx * width - 0.5 * hx * height; 227 | y = node1->y + 0.5 * wy * width - 0.5 * hy * height; 228 | z = node1->z + 0.5 * wz * width - 0.5 * hz * height; 229 | fprintf(fp,"%lg %lg %lg ",x,y,z); 230 | x = node1->x - 0.5 * wx * width - 0.5 * hx * height; 231 | y = node1->y - 0.5 * wy * width - 0.5 * hy * height; 232 | z = node1->z - 0.5 * wz * width - 0.5 * hz * height; 233 | fprintf(fp,"%lg %lg %lg ",x,y,z); 234 | 235 | fprintf(fp,"\n"); 236 | /* write out shade of grey to color */ 237 | fprintf(shade_fp,"%d\n",seg->is_deleted); 238 | } 239 | } 240 | 241 | if (indsys->opts->gp_draw == OFF) 242 | for(gp = indsys->planes; gp != NULL; gp = gp->next) { 243 | 244 | unit_cross_product(gp->x[0]-gp->x[1], gp->y[0]-gp->y[1], gp->z[0]-gp->z[1], 245 | gp->x[2]-gp->x[1], gp->y[2]-gp->y[1], gp->z[2]-gp->z[1], 246 | &wx, &wy, &wz); 247 | if (is_nonuni_gp(gp)) 248 | width = gp->thick; 249 | else 250 | width = gp->segs1[0][0]->height; 251 | 252 | for(j = 0; j < 3; j++) { 253 | k = j+1; 254 | fprintf(fp, "Q %d ",i + j); 255 | make_between(fp, gp,wx,wy,wz,width,j,k); 256 | /* shade it white */ 257 | fprintf(shade_fp,"%d\n",0); 258 | } 259 | k = 0; 260 | j = 3; 261 | fprintf(fp, "Q %d ",i + j); 262 | make_between(fp, gp, wx,wy,wz,width,j,k); 263 | fprintf(shade_fp,"%d\n",0); 264 | i += 4; 265 | } 266 | 267 | /* clear is_deleted */ 268 | clear_marks(indsys); 269 | 270 | fclose(fp); 271 | fclose(shade_fp); 272 | } 273 | 274 | make_between(fp, gp, wx,wy,wz,width,j,k) 275 | GROUNDPLANE *gp; 276 | double wx,wy,wz,width; 277 | int j,k; 278 | FILE *fp; 279 | { 280 | double x,y,z; 281 | 282 | x = gp->x[j] - 0.5 * wx * width; 283 | y = gp->y[j] - 0.5 * wy * width; 284 | z = gp->z[j] - 0.5 * wz * width; 285 | fprintf(fp,"%lg %lg %lg ",x,y,z); 286 | 287 | x = gp->x[j] + 0.5 * wx * width; 288 | y = gp->y[j] + 0.5 * wy * width; 289 | z = gp->z[j] + 0.5 * wz * width; 290 | fprintf(fp,"%lg %lg %lg ",x,y,z); 291 | 292 | x = gp->x[k] + 0.5 * wx * width; 293 | y = gp->y[k] + 0.5 * wy * width; 294 | z = gp->z[k] + 0.5 * wz * width; 295 | fprintf(fp,"%lg %lg %lg ",x,y,z); 296 | 297 | x = gp->x[k] - 0.5 * wx * width; 298 | y = gp->y[k] - 0.5 * wy * width; 299 | z = gp->z[k] - 0.5 * wz * width; 300 | fprintf(fp,"%lg %lg %lg ",x,y,z); 301 | 302 | fprintf(fp,"\n"); 303 | } 304 | 305 | unit_cross_product(x1,y1,z1,x2,y2,z2,cx, cy,cz) 306 | double x1,y1,z1,x2,y2,z2,*cx, *cy,*cz; 307 | { 308 | double magc; 309 | 310 | *cx = (y1*z2 - y2*z1); 311 | *cy = (z1*x2 - z2*x1); 312 | *cz = (x1*y2 - x2*y1); 313 | 314 | magc = mag(*cx, *cy, *cz); 315 | 316 | if (magc/mag(x1,y1,z1) > 1e-13) { 317 | /* normalize */ 318 | *cx = *cx/magc; 319 | *cy = *cy/magc; 320 | *cz = *cz/magc; 321 | } 322 | } 323 | 324 | /* attempts to choose shades for each segment to make seeing the condutors 325 | easier. To see shades, run with the zbuf -q options */ 326 | 327 | assign_shades(indsys) 328 | SYS *indsys; 329 | { 330 | int_list *elem; 331 | EXTERNAL *ext; 332 | MELEMENT **Mlist = indsys->Mlist, *m; 333 | int greylev, nodes1, nodes2, i, j; 334 | GROUNDPLANE *gp; 335 | 336 | /* clear is_deleted */ 337 | clear_marks(indsys); 338 | 339 | greylev = 0; 340 | /* color each set of external meshes a different shade of grey */ 341 | for(ext = indsys->externals; ext != NULL; ext = ext->next) { 342 | greylev++; 343 | 344 | /* for each mesh in this set of ext (usually only one) */ 345 | for(elem = ext->indices; elem != NULL; elem = elem->next) 346 | 347 | /* for each filament in this mesh */ 348 | for(m = Mlist[elem->index]; m != NULL; m = m->mnext) 349 | 350 | m->fil->segm->is_deleted = greylev; 351 | } 352 | 353 | greylev += 10; 354 | 355 | /* now do ground planes */ 356 | for(gp = indsys->planes; gp != NULL; gp = gp->next) { 357 | greylev++; 358 | 359 | nodes2 = gp->num_nodes2; 360 | nodes1 = gp->num_nodes1; 361 | 362 | for(i = 0; i < nodes2; i++) 363 | for(j = 0; j < (nodes1 - 1); j++) 364 | if (gp->segs1[j][i] != NULL) /* it's not part of a hole */ 365 | gp->segs1[j][i]->is_deleted = greylev; 366 | 367 | for(i = 0; i < (nodes2 - 1); i++) 368 | for(j = 0; j < nodes1; j++) 369 | if (gp->segs2[j][i] != NULL) /* it's not part of a hole */ 370 | gp->segs2[j][i]->is_deleted = greylev; 371 | } 372 | } 373 | --------------------------------------------------------------------------------