378 lines
9.7 KiB
C++
378 lines
9.7 KiB
C++
#include<stdafx.h>
|
|
#include<stdio.h>
|
|
#include<math.h>
|
|
#include "complex.h"
|
|
#include "csolv.h"
|
|
#include "csolvDlg.h"
|
|
#include "mesh.h"
|
|
#include "spars.h"
|
|
#include "FemmeDocCore.h"
|
|
|
|
//conversion to internal working units of mm
|
|
double units[]={25.4,1.,10.,1000.,0.0254,0.001};
|
|
double sq(double x){ return x*x; }
|
|
|
|
BOOL CFemmeDocCore::AnalyzeProblem(CBigComplexLinProb &L)
|
|
{
|
|
int i,j,k,pctr=0;
|
|
CComplex Me[3][3],be[3]; // element matrices;
|
|
double l[3],p[3],q[3]; // element shape parameters;
|
|
int n[3],ne[3]; // numbers of nodes for a particular element;
|
|
double a,r,z,kludge;
|
|
CComplex K;
|
|
CElement *El;
|
|
|
|
double c = (1.e-6)/eo;
|
|
Depth*=units[LengthUnits];
|
|
extRo*=units[LengthUnits];
|
|
extRi*=units[LengthUnits];
|
|
extZo*=units[LengthUnits];
|
|
kludge=1;
|
|
|
|
TheView->SetDlgItemText(IDC_FRAME1,"Matrix Construction");
|
|
|
|
// do some book-keeping related to fixed boundary conditions;
|
|
// The P vector denotes which nodes have an assigned value
|
|
// The V vector denotes the assigned value
|
|
for(i=0;i<NumNodes;i++)
|
|
{
|
|
L.Q[i]=-2;
|
|
if(meshnode[i].bc >=0)
|
|
if(nodeproplist[meshnode[i].bc].qp==0)
|
|
{
|
|
L.V[i]=nodeproplist[meshnode[i].bc].V;
|
|
L.Q[i]=-1;
|
|
}
|
|
|
|
if(meshnode[i].InConductor>=0)
|
|
if(circproplist[meshnode[i].InConductor].CircType==1)
|
|
{
|
|
L.V[i]=circproplist[meshnode[i].InConductor].V;
|
|
L.Q[i]=meshnode[i].InConductor;
|
|
}
|
|
}
|
|
|
|
// account for fixed boundary conditions along segments;
|
|
for(i=0;i<NumEls;i++)
|
|
{
|
|
for(j=0;j<3;j++){
|
|
k=j+1; if(k==3) k=0;
|
|
if(meshele[i].e[j]>=0)
|
|
{
|
|
if(lineproplist[ meshele[i].e[j] ].BdryFormat==0)
|
|
{
|
|
L.V[meshele[i].p[j]]=lineproplist[meshele[i].e[j]].V;
|
|
L.V[meshele[i].p[k]]=lineproplist[meshele[i].e[j]].V;
|
|
L.Q[meshele[i].p[j]]=-1;
|
|
L.Q[meshele[i].p[k]]=-1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// build element matrices using the matrices derived in Allaire's book.
|
|
for(i=0;i<NumEls;i++)
|
|
{
|
|
// update progress bar
|
|
j=5*((i*20)/NumEls);
|
|
if(j!=pctr){ pctr=j; TheView->m_prog1.SetPos(pctr); }
|
|
|
|
// zero out Me, be;
|
|
for(j=0;j<3;j++){
|
|
for(k=0;k<3;k++) Me[j][k]=0;
|
|
be[j]=0;
|
|
}
|
|
|
|
// Determine shape parameters.
|
|
// l's are element side lengths;
|
|
// p's corresponds to the `b' parameter in Allaire
|
|
// q's corresponds to the `c' parameter in Allaire
|
|
El=&meshele[i];
|
|
|
|
for(k=0;k<3;k++) n[k]=El->p[k];
|
|
p[0]=meshnode[n[1]].y - meshnode[n[2]].y;
|
|
p[1]=meshnode[n[2]].y - meshnode[n[0]].y;
|
|
p[2]=meshnode[n[0]].y - meshnode[n[1]].y;
|
|
q[0]=meshnode[n[2]].x - meshnode[n[1]].x;
|
|
q[1]=meshnode[n[0]].x - meshnode[n[2]].x;
|
|
q[2]=meshnode[n[1]].x - meshnode[n[0]].x;
|
|
for(j=0,k=1;j<3;k++,j++){
|
|
if (k==3) k=0;
|
|
l[j]=sqrt( sq(meshnode[n[k]].x-meshnode[n[j]].x) +
|
|
sq(meshnode[n[k]].y-meshnode[n[j]].y) );
|
|
}
|
|
a=(p[0]*q[1]-p[1]*q[0])/2.;
|
|
r=(meshnode[n[0]].x+meshnode[n[1]].x+meshnode[n[2]].x)/3.;
|
|
|
|
if (ProblemType==AXISYMMETRIC){
|
|
Depth=2.*PI*r;
|
|
|
|
// "Warp" the permeability of this element is part of
|
|
// the conformally mapped external region
|
|
if(labellist[meshele[i].lbl].IsExternal)
|
|
{
|
|
z=(meshnode[n[0]].y+meshnode[n[1]].y+meshnode[n[2]].y)/3. - extZo;
|
|
kludge=(r*r+z*z)/(extRi*extRo);
|
|
}
|
|
else kludge=1;
|
|
}
|
|
|
|
|
|
// x-contribution;
|
|
K = -Depth*blockproplist[El->blk].kx/(4.*a)/kludge;
|
|
for(j=0;j<3;j++)
|
|
for(k=j;k<3;k++)
|
|
{
|
|
Me[j][k] += K*p[j]*p[k];
|
|
if (j!=k) Me[k][j]+=K*p[j]*p[k];
|
|
}
|
|
|
|
// y-contribution;
|
|
K = -Depth*blockproplist[El->blk].ky/(4.*a)/kludge;
|
|
for(j=0;j<3;j++)
|
|
for(k=j;k<3;k++)
|
|
{
|
|
Me[j][k] +=K*q[j]*q[k];
|
|
if (j!=k) Me[k][j]+=K*q[j]*q[k];
|
|
}
|
|
|
|
for(j=0;j<3;j++)
|
|
{
|
|
if (El->e[j] >= 0)
|
|
{
|
|
k=j+1; if(k==3) k=0;
|
|
|
|
if (ProblemType==AXISYMMETRIC)
|
|
Depth=PI*(meshnode[n[j]].x + meshnode[n[k]].x);
|
|
|
|
// contributions to Me, be from derivative boundary conditions;
|
|
if (lineproplist[El->e[j]].BdryFormat==1)
|
|
{
|
|
K =-1000.*Depth*c*lineproplist[El->e[j]].c0*l[j]/6.;
|
|
Me[j][j]+=K*2.;
|
|
Me[k][k]+=K*2.;
|
|
Me[j][k]+=K;
|
|
Me[k][j]+=K;
|
|
|
|
K = 1000.*Depth*c*lineproplist[El->e[j]].c1*l[j]/2.;
|
|
be[j]+=K;
|
|
be[k]+=K;
|
|
}
|
|
|
|
// contribution to be[] from surface charge density;
|
|
if (lineproplist[El->e[j]].BdryFormat==2)
|
|
{
|
|
K =-1000.*Depth*c*lineproplist[El->e[j]].qs*l[j]/2.;
|
|
be[j]+=K;
|
|
be[k]+=K;
|
|
}
|
|
}
|
|
}
|
|
|
|
// process any prescribed nodal values;
|
|
for(j=0;j<3;j++)
|
|
{
|
|
if(L.Q[n[j]]!=-2)
|
|
{
|
|
for(k=0;k<3;k++)
|
|
{
|
|
if(j!=k){
|
|
be[k]-=Me[k][j]*L.V[n[j]];
|
|
Me[k][j]=0;
|
|
Me[j][k]=0;
|
|
}
|
|
}
|
|
be[j]=L.V[n[j]]*Me[j][j];
|
|
}
|
|
}
|
|
|
|
// combine block matrices into global matrices;
|
|
for (j=0;j<3;j++)
|
|
{
|
|
ne[j]=n[j];
|
|
if(meshnode[n[j]].InConductor>=0)
|
|
if(circproplist[meshnode[n[j]].InConductor].CircType==0)
|
|
ne[j]=meshnode[n[j]].InConductor+NumNodes;
|
|
}
|
|
for (j=0;j<3;j++){
|
|
for (k=j;k<3;k++)
|
|
L.Put(L.Get(ne[j],ne[k])-Me[j][k],ne[j],ne[k]);
|
|
L.b[ne[j]]-=be[j];
|
|
|
|
if(ne[j]!=n[j])
|
|
{
|
|
L.Put(L.Get(n[j],n[j])-Me[j][j],n[j],n[j]);
|
|
L.Put(L.Get(n[j],ne[j])+Me[j][j],n[j],ne[j]);
|
|
}
|
|
}
|
|
|
|
} // end of loop that builds element matrices
|
|
|
|
// add in contribution from point charge density;
|
|
for(i=0;i<NumNodes;i++)
|
|
{
|
|
if((meshnode[i].bc>=0) && (L.Q[i]==-2))
|
|
{
|
|
if (ProblemType==AXISYMMETRIC) Depth=2.*PI*meshnode[i].x;
|
|
L.b[i]+=((1.e6)*Depth*c*nodeproplist[meshnode[i].bc].qp);
|
|
L.Q[i]=-1;
|
|
}
|
|
|
|
// some bookkeeping to denote which nodes we can smooth over
|
|
if(meshnode[i].InConductor>=0) L.Q[i]=meshnode[i].InConductor;
|
|
}
|
|
|
|
// Apply any periodicity/antiperiodicity boundary conditions that we have
|
|
for(k=0,pctr=0;k<NumPBCs;k++)
|
|
{
|
|
if (pbclist[k].t==0) L.Periodicity(pbclist[k].x,pbclist[k].y);
|
|
if (pbclist[k].t==1) L.AntiPeriodicity(pbclist[k].x,pbclist[k].y);
|
|
}
|
|
|
|
// Finish building the equations that assign conductor voltage;
|
|
for(i=0;i<NumCircProps;i++)
|
|
{
|
|
// put a placeholder on the main diagonal;
|
|
k=NumNodes+i;
|
|
|
|
if (circproplist[i].CircType==1)
|
|
{
|
|
K=L.Get(0,0);
|
|
L.Put(K,k,k);
|
|
L.b[k]=K*circproplist[i].V;
|
|
}
|
|
|
|
if(circproplist[i].CircType==0)
|
|
{
|
|
for(j=0,K=0;j<L.n;j++) if(j!=k) K+=L.Get(k,j);
|
|
if(K!=0){
|
|
L.Put(-K,k,k);
|
|
L.b[k]=(1.e9)*c*circproplist[i].q;
|
|
}
|
|
else L.Put(L.Get(0,0),k,k);
|
|
|
|
|
|
}
|
|
}
|
|
|
|
// solve the problem;
|
|
if (L.PBCGSolveMod(FALSE)==FALSE) return FALSE;
|
|
|
|
// compute total charge on conductors
|
|
// with a specified voltage
|
|
for(i=0;i<NumCircProps;i++)
|
|
if(circproplist[i].CircType==1)
|
|
circproplist[i].q=ChargeOnConductor(i,L);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//=========================================================================
|
|
//=========================================================================
|
|
|
|
BOOL CFemmeDocCore::WriteResults(CBigComplexLinProb &L)
|
|
{
|
|
// write solution to disk;
|
|
|
|
char c[1024];
|
|
FILE *fp,*fz;
|
|
int i;
|
|
double cf;
|
|
|
|
// first, echo input .fec file to the .res file;
|
|
sprintf(c,"%s.fec",PathName);
|
|
if((fz=fopen(c,"rt"))==NULL){
|
|
Sleep(500);
|
|
if((fz=fopen(c,"rt"))==NULL){
|
|
fprintf(stderr,"Couldn't open %s.fec\n",PathName);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
sprintf(c,"%s.anc",PathName);
|
|
if((fp=fopen(c,"wt"))==NULL){
|
|
Sleep(500);
|
|
if((fp=fopen(c,"wt"))==NULL){
|
|
fprintf(stderr,"Couldn't write to %s.anc\n",PathName);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
while(fgets(c,1024,fz)!=NULL) fputs(c,fp);
|
|
fclose(fz);
|
|
|
|
// then print out node, line, and element information
|
|
fprintf(fp,"[Solution]\n");
|
|
cf=units[LengthUnits];
|
|
fprintf(fp,"%i\n",NumNodes);
|
|
for(i=0;i<NumNodes;i++)
|
|
fprintf(fp,"%.17g %.17g %.17g %.17g %i\n",meshnode[i].x/cf,meshnode[i].y/cf,Re(L.V[i]),Im(L.V[i]),L.Q[i]);
|
|
fprintf(fp,"%i\n",NumEls);
|
|
for(i=0;i<NumEls;i++)
|
|
fprintf(fp,"%i %i %i %i\n",
|
|
meshele[i].p[0],meshele[i].p[1],meshele[i].p[2],meshele[i].lbl);
|
|
|
|
// print out circuit info
|
|
fprintf(fp,"%i\n",NumCircProps);
|
|
for(i=0;i<NumCircProps;i++)
|
|
fprintf(fp,"%.17g %.17g %.17g %.17g\n",
|
|
Re(L.V[NumNodes+i]),Im(L.V[NumNodes+i]),Re(circproplist[i].q),Im(circproplist[i].q));
|
|
|
|
fclose(fp);
|
|
return TRUE;
|
|
}
|
|
|
|
//=========================================================================
|
|
//=========================================================================
|
|
|
|
|
|
CComplex CFemmeDocCore::ChargeOnConductor(int u, CBigComplexLinProb &L)
|
|
{
|
|
int i,k;
|
|
double b[3],c[3]; // element shape parameters;
|
|
int n[3]; // numbers of nodes for a particular element;
|
|
double a,da;
|
|
CComplex Dx,Dy,vx,vy,Z;
|
|
double LengthConv=0.001;
|
|
|
|
for(i=0;i<NumNodes;i++)
|
|
if(meshnode[i].InConductor==u) L.P[i]=1;
|
|
else L.P[i]=0;
|
|
|
|
// build element matrices using the matrices derived in Allaire's book.
|
|
for(i=0,Z=0;i<NumEls;i++)
|
|
{
|
|
for(k=0;k<3;k++) n[k]=meshele[i].p[k];
|
|
|
|
if((L.P[n[0]]!=0) || (L.P[n[1]]!=0) || (L.P[n[2]]!=0))
|
|
{
|
|
// Determine shape parameters.
|
|
b[0]=meshnode[n[1]].y - meshnode[n[2]].y;
|
|
b[1]=meshnode[n[2]].y - meshnode[n[0]].y;
|
|
b[2]=meshnode[n[0]].y - meshnode[n[1]].y;
|
|
c[0]=meshnode[n[2]].x - meshnode[n[1]].x;
|
|
c[1]=meshnode[n[0]].x - meshnode[n[2]].x;
|
|
c[2]=meshnode[n[1]].x - meshnode[n[0]].x;
|
|
da=(b[0]*c[1]-b[1]*c[0]);
|
|
a=da*LengthConv*LengthConv/2.;
|
|
if (ProblemType==AXISYMMETRIC)
|
|
a*=(2.*PI*LengthConv*(meshnode[n[0]].x+meshnode[n[1]].x+meshnode[n[2]].x)/3.);
|
|
else a*=(Depth*LengthConv);
|
|
// get normal vector and element flux density;
|
|
for(k=0,vx=0,vy=0,Dx=0,Dy=0;k<3;k++)
|
|
{
|
|
vx-=(L.P[n[k]]*b[k])/(da*LengthConv);
|
|
vy-=(L.P[n[k]]*c[k])/(da*LengthConv);
|
|
Dx-=(L.V[n[k]]*b[k])/(da*LengthConv);
|
|
Dy-=(L.V[n[k]]*c[k])/(da*LengthConv);
|
|
}
|
|
Dx*=(eo*blockproplist[meshele[i].blk].kx);
|
|
Dy*=(eo*blockproplist[meshele[i].blk].ky);
|
|
|
|
Z+=a*(Dx*vx+Dy*vy);
|
|
}
|
|
}
|
|
|
|
return Z;
|
|
} |