FEMM/femm/Problem.cpp

987 lines
22 KiB
C++

#include "stdafx.h"
#include "problem.h"
#include "fullmatrix.h"
#define ElementsPerSkinDepth 10
/////////////////////////////////////////////////////////////////////////////
// CNode construction
CNode::CNode()
{
x=0.;
y=0.;
IsSelected=FALSE;
BoundaryMarker=-1;
}
CComplex CNode::CC()
{
return (x+I*y);
}
double CNode::GetDistance(double xo, double yo)
{
return sqrt((x-xo)*(x-xo) + (y-yo)*(y-yo));
}
void CNode::ToggleSelect()
{
if (IsSelected==TRUE) IsSelected=FALSE;
else IsSelected=TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CMeshNode construction
CMeshNode::CMeshNode()
{
x=0.; y=0.;
A.re=0; A.im=0;
msk=0;
}
CComplex CMeshNode::CC()
{
return (x+I*y);
}
double CMeshNode::GetDistance(double xo, double yo)
{
return sqrt((x-xo)*(x-xo) + (y-yo)*(y-yo));
}
/////////////////////////////////////////////////////////////////////////////
// CSegment construction
CSegment::CSegment()
{
n0=0;
n1=0;
IsSelected=FALSE;
BoundaryMarker=-1;
InGroup=0;
}
void CSegment::ToggleSelect()
{
if (IsSelected==TRUE) IsSelected=FALSE;
else IsSelected=TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CArcSegment construction
CArcSegment::CArcSegment()
{
n0=0;
n1=0;
IsSelected=FALSE;
MaxSideLength=-1;
ArcLength=90.;
BoundaryMarker=-1;
InGroup=0;
}
void CArcSegment::ToggleSelect()
{
if (IsSelected==TRUE) IsSelected=FALSE;
else IsSelected=TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CNode construction
CBlockLabel::CBlockLabel()
{
x=0.;
y=0.;
MaxArea=0.;
IsSelected=FALSE;
InGroup=0;
InCircuit=0;
BlockType=-1;
IsExternal=FALSE;
IsDefault=FALSE;
Case=0;
dVolts=0.;
J=0.;
FillFactor=1;
o=0;
mu=0;
LocalEnergy=0;
}
void CBlockLabel::ToggleSelect()
{
if (IsSelected==TRUE) IsSelected=FALSE;
else IsSelected=TRUE;
}
double CBlockLabel::GetDistance(double xo, double yo)
{
return sqrt((x-xo)*(x-xo) + (y-yo)*(y-yo));
}
CMaterialProp::CMaterialProp()
{
BlockName="New Material";
mu_x=1.;
mu_y=1.; // permeabilities, relative
BHpoints=0;
Bdata=NULL;
Hdata=NULL;
slope=NULL;
H_c=0.; // magnetization, A/m
Nrg=0.;
Jr=0.;
Ji=0.; // applied current density, MA/m^2
Cduct=0.; // conductivity of the material, MS/m
Lam_d=0.; // lamination thickness, mm
Theta_hn=0.; // hysteresis angle, degrees
Theta_hx=0.; // hysteresis angle, degrees
Theta_hy=0.; // hysteresis angle, degrees
NStrands=0; // number of strands per wire
WireD=0;
LamFill=1.; // lamination fill factor;
LamType=0; // type of lamination;
MuMax=0.; // maximum permeability (used for incremental permeability problems
Frequency=0; // problem frequency in Hz (needed for incremental permeability problems
}
CMaterialProp::~CMaterialProp()
{
if (Bdata!=NULL) free(Bdata);
if (Hdata!=NULL) free(Hdata);
if (slope!=NULL) free(slope);
}
void CMaterialProp::GetSlopes(double omega)
{
if (BHpoints==0) return; // catch trivial case;
if (slope!=NULL){
return; // already have computed the slopes;
}
int i,k;
BOOL CurveOK=FALSE;
BOOL ProcessedLams=FALSE;
CComplexFullMatrix L;
double l1,l2;
CComplex *hn;
double *bn;
CComplex mu;
L.Create(BHpoints);
bn =(double *) calloc(BHpoints,sizeof(double));
hn =(CComplex *)calloc(BHpoints,sizeof(CComplex));
slope=(CComplex *)calloc(BHpoints,sizeof(CComplex));
// strip off some info that we can use during the first
// nonlinear iteration;
mu_x = Bdata[1]/(muo*abs(Hdata[1]));
mu_y = mu_x;
Theta_hx=Theta_hn;
Theta_hy=Theta_hn;
// first, we need to doctor the curve if the problem is
// being evaluated at a nonzero frequency.
if(omega!=0)
{
// Make an effective B-H curve for harmonic problems.
// this one convolves B(H) where H is sinusoidal with
// a sine at the same frequency to get the effective
// amplitude of B
double munow,mumax=0;
for(i=1;i<BHpoints;i++)
{
hn[i]=Hdata[i];
for(k=1,bn[i]=0;k<=i;k++)
{
bn[i]+=Re((4.*(Hdata[k]*Bdata[k-1] -
Hdata[k-1]*Bdata[k])*(-cos((Hdata[k-1]*PI)/(2.*Hdata[i])) +
cos((Hdata[k]*PI)/(2.*Hdata[i]))) + (-Bdata[k-1] +
Bdata[k])*((Hdata[k-1] - Hdata[k])*PI +
Hdata[i]*(-sin((Hdata[k-1]*PI)/Hdata[i]) +
sin((Hdata[k]*PI)/Hdata[i]))))/ ((Hdata[k-1] - Hdata[k])*PI));
}
}
for(i=1;i<BHpoints;i++)
{
Bdata[i]=bn[i];
Hdata[i]=hn[i];
munow=Re(Bdata[i]/Hdata[i]);
if (munow>mumax) mumax=munow;
}
// apply complex permeability to approximate the
// effects of hysteresis. We will follow a kludge
// suggested by O'Kelly where hysteresis angle
// is proportional to permeability. This implies
// that loss goes with B^2
for(i=1;i<BHpoints;i++)
{
Hdata[i]*=exp(I*Bdata[i]*Theta_hn*DEG/(Hdata[i]*mumax));
}
MuMax=mumax/muo;
}
while(CurveOK!=TRUE)
{
// make sure that the space for computing slopes is cleared out
L.Wipe();
// impose natural BC on the `left'
l1=Bdata[1]-Bdata[0];
L.M[0][0]=4./l1;
L.M[0][1]=2./l1;
L.b[0]=6.*(Hdata[1]-Hdata[0])/(l1*l1);
// impose natural BC on the `right'
int n=BHpoints;
l1=Bdata[n-1]-Bdata[n-2];
L.M[n-1][n-1]=4./l1;
L.M[n-1][n-2]=2./l1;
L.b[n-1]=6.*(Hdata[n-1]-Hdata[n-2])/(l1*l1);
for(i=1;i<BHpoints-1;i++)
{
l1=Bdata[i]-Bdata[i-1];
l2=Bdata[i+1]-Bdata[i];
L.M[i][i-1]=2./l1;
L.M[i][i]=4.*(l1+l2)/(l1*l2);
L.M[i][i+1]=2./l2;
L.b[i]=6.*(Hdata[i]-Hdata[i-1])/(l1*l1) +
6.*(Hdata[i+1]-Hdata[i])/(l2*l2);
}
L.GaussSolve();
for(i=0;i<BHpoints;i++) slope[i]=L.b[i];
// now, test to see if there are any "bad" segments in there.
// it is probably sufficient to do this test just on the
// real part of the BH curve...
for(i=1,CurveOK=TRUE;i<BHpoints;i++)
{
double L,c0,c1,c2,d0,d1,u0,u1,X0,X1;
// it is probably sufficient to do this test just on the
// real part of the BH curve. We do the test on just the
// real part of the curve by taking the real parts of
// slope and Hdata
d0=slope[i-1].re;
d1=slope[i].re;
u0=Hdata[i-1].re;
u1=Hdata[i].re;
L=Bdata[i]-Bdata[i-1];
c0=d0;
c1= -(2.*(2.*d0*L + d1*L + 3.*u0 - 3.*u1))/(L*L);
c2= (3.*(d0*L + d1*L + 2.*u0 - 2.*u1))/(L*L*L);
X0=-1.;
X1=-1.;
u0=c1*c1-4.*c0*c2;
// check out degenerate cases
if(c2==0)
{
if(c1!=0) X0=-c0/c1;
}
else if(u0>0)
{
u0=sqrt(u0);
X0=-(c1 + u0)/(2.*c2);
X1=(-c1 + u0)/(2.*c2);
}
//now, see if we've struck gold!
if (((X0>=0.)&&(X0<=L))||((X1>=0.)&&(X1<=L)))
CurveOK=FALSE;
}
if(CurveOK!=TRUE) //remedial action
{
// Smooth out input points
// to get rid of rapid transitions;
// Uses a 3-point moving average
for(i=1;i<BHpoints-1;i++)
{
bn[i]=(Bdata[i-1]+Bdata[i]+Bdata[i+1])/3.;
hn[i]=(Hdata[i-1]+Hdata[i]+Hdata[i+1])/3.;
}
for(i=1;i<BHpoints-1;i++){
Hdata[i]=hn[i];
Bdata[i]=bn[i];
}
}
if((CurveOK==TRUE) && (ProcessedLams==FALSE))
{
// if the material is laminated and has a non-zero conductivity,
// we have to do some work to find the "right" apparent BH
// curve for the material for AC problems. Essentially, we have
// to solve a 1-D finite element problem at each B-H point to
// figure out how much flux the lamination is really carrying.
if((omega!=0) && (Lam_d!=0) && (Cduct!=0))
{
// Calculate a new apparent b and h for each point on the
// curve to account for the laminations.
for(i=1;i<BHpoints;i++)
{
mu=LaminatedBH(omega,i);
bn[i]=abs(mu*Hdata[i]);
hn[i]=bn[i]/mu;
}
// Replace the original BH points with the apparent ones
for(i=1;i<BHpoints;i++)
{
Bdata[i]=bn[i];
Hdata[i]=hn[i];
}
// Make the program check the consistency and recompute the
// proper slopes of the new BH curve one more time;
CurveOK=FALSE;
}
// take care of LamType=0 situation by changing the apparent B-H curve.
if((LamType==0) && (LamFill!=1))
{
// this is changed from the previous version so that
// a complex-valued H can be properly accommodated
// in the algorithm.
for(i=1;i<BHpoints;i++)
{
mu=LamFill*Bdata[i]/Hdata[i]+(1.-LamFill)*muo;
Bdata[i]=abs(mu*Hdata[i]);
Hdata[i]=Bdata[i]/mu;
}
// Make the program check the consistency and recompute the
// proper slopes of the new BH curve one more time;
CurveOK=FALSE;
}
ProcessedLams=TRUE;
}
}
free(bn);
free(hn);
return;
}
CComplex CMaterialProp::LaminatedBH(double w, int i)
{
int k,n,iter=0;
CComplex *m0,*m1,*b,*x;
double L,o,d,ds,B,lastres;
double res=0;
double Relax=1;
CComplex mu,vo,vi,c,H;
CComplex Md,Mo;
BOOL Converged=FALSE;
// Base the required element spacing on the skin depth
// at the surface of the material
mu=Bdata[i]/Hdata[i];
o=Cduct*1.e6;
d=(Lam_d*0.001)/2.;
ds=sqrt(2/(w*o*abs(mu)));
n= ElementsPerSkinDepth * ((int) ceil(d/ds));
L=d/((double) n);
x =(CComplex *)calloc(n+1,sizeof(CComplex));
b =(CComplex *)calloc(n+1,sizeof(CComplex));
m0=(CComplex *)calloc(n+1,sizeof(CComplex));
m1=(CComplex *)calloc(n+1,sizeof(CComplex));
do{
// make sure that the old stuff is wiped out;
for(k=0;k<=n;k++)
{
m0[k]=0;
m1[k]=0;
b[k] =0;
}
// build matrix
for(k=0;k<n;k++)
{
if(iter!=0)
{
B=abs(x[k+1]-x[k])/L;
vi=GetdHdB(B);
vo=GetH(CComplex(B))/B;
}
else
{
vo=1./mu;
vi=1./mu;
}
Md = ( (vi+vo)/(2.*L) + I*w*o*L/4.);
Mo = (-(vi+vo)/(2.*L) + I*w*o*L/4.);
m0[k] += Md;
m1[k] += Mo;
m0[k+1] += Md;
Md = ( (vi-vo)/(2.*L));
Mo = (-(vi-vo)/(2.*L));
b[k] += (Md*x[k] + Mo*x[k+1]);
b[k+1] += (Mo*x[k] + Md*x[k+1]);
}
// set boundary conditions
m1[0] = 0;
b[0] = 0;
b[n] += Hdata[i];
// solve tridiagonal equation
// solution ends up in b;
for(k = 0; k < n; k++)
{
c = m1[k]/m0[k];
m0[k+1] -= m1[k]*c;
b[k+1] -= b[k]*c;
}
b[n] = b[n]/m0[n];
for(k = n-1; k >= 0; k--)
b[k] = (b[k] - m1[k]*b[k + 1])/m0[k];
iter++;
lastres=res;
res=abs(b[n]-x[n])/d;
if (res<1.e-8) Converged=TRUE;
// Do the same relaxation scheme as is implemented
// in the solver to make sure that this effective
// lamination permeability calculation converges
if(iter>5)
{
if ((res>lastres) && (Relax>0.1)) Relax/=2.;
else Relax+= 0.1 * (1. - Relax);
}
for(k=0;k<=n;k++) x[k]=Relax*b[k]+(1.0-Relax)*x[k];
}while(Converged!=TRUE);
mu = x[n]/(Hdata[i]*d);
free(x );
free(b );
free(m0);
free(m1);
return mu;
}
CComplex CMaterialProp::GetdHdB(double B)
{
double b,z,l;
CComplex h;
int i;
b=fabs(B);
if(BHpoints==0) return CComplex(b/(mu_x*muo));
if(b>Bdata[BHpoints-1])
return slope[BHpoints-1];
for(i=0;i<BHpoints-1;i++)
if((b>=Bdata[i]) && (b<=Bdata[i+1])){
l=(Bdata[i+1]-Bdata[i]);
z=(b-Bdata[i])/l;
h=6.*z*(z-1.)*Hdata[i]/l +
(1.-4.*z+3.*z*z)*slope[i] +
6.*z*(1.-z)*Hdata[i+1]/l +
z*(3.*z-2.)*slope[i+1];
return h;
}
return CComplex(0);
}
double CMaterialProp::GetH(double x)
{
return Re(GetH(CComplex(x)));
}
CComplex CMaterialProp::GetH(CComplex x)
{
double b,z,z2,l;
CComplex p,h;
int i;
b=abs(x);
if((BHpoints==0) || (b==0)) return 0;
p=x/b;
if(b>Bdata[BHpoints-1])
return p*(Hdata[BHpoints-1] + slope[BHpoints-1]*(b-Bdata[BHpoints-1]));
for(i=0;i<BHpoints-1;i++)
if((b>=Bdata[i]) && (b<=Bdata[i+1])){
l=Bdata[i+1]-Bdata[i];
z=(b-Bdata[i])/l;
z2=z*z;
h=(1.-3.*z2+2.*z2*z)*Hdata[i] +
z*(1.-2.*z+z2)*l*slope[i] +
z2*(3.-2.*z)*Hdata[i+1] +
z2*(z-1.)*l*slope[i+1];
return p*h;
}
return 0;
}
double CMaterialProp::GetB(double hc)
{
if (BHpoints==0) return muo*mu_x*hc;
double b,bo;
b=0;
do{
bo = b;
b = bo + (hc-GetH(bo))/Re(GetdHdB(bo));
}while (fabs(b-bo)>1.e-8);
return b;
}
// GetEnergy for the magnetostatic case
double CMaterialProp::GetEnergy(double x)
{
double b,z,z2,l,nrg;
double b0,b1,h0,h1,dh0,dh1;
int i;
b=fabs(x);
nrg=0.;
if(BHpoints==0) return 0;
for(i=0;i<BHpoints-1;i++){
b0=Bdata[i]; h0=Re(Hdata[i]);
b1=Bdata[i+1]; h1=Re(Hdata[i+1]);
dh0=Re(slope[i]);
dh1=Re(slope[i+1]);
if((b>=b0) && (b<=b1)){
l=b1-b0;
z=(b-b0)/l;
z2=z*z;
nrg += (dh0*l*l*(6. + z*(-8. + 3.*z))*z2)/12. +
(h0*l*z*(2. + (-2. + z)*z2))/2. -
(h1*l*(-2. + z)*z2*z)/2. +
(dh1*l*l*(-4. + 3.*z)*z2*z)/12;
return nrg;
}
else{
// point isn't in this section, but add in the
// energy required to pass through it.
b0=Bdata[i]; h0=Re(Hdata[i]);
b1=Bdata[i+1]; h1=Re(Hdata[i+1]);
dh0=Re(slope[i]);
dh1=Re(slope[i+1]);
nrg += ((b0 - b1)*((b0 - b1)*(dh0 - dh1) -
6.*(h0 + h1)))/12.;
}
}
// if we've gotten to this point, the point is off the scale,
// so we have to extrapolate the rest of the way...
h0=Re(Hdata[BHpoints-1]);
dh0=Re(slope[BHpoints-1]);
b0=Bdata[BHpoints-1];
nrg += ((b - b0)*(b*dh0 - b0*dh0 + 2*h0))/2.;
return nrg;
}
double CMaterialProp::GetCoEnergy(double b)
{
return (fabs(b)*GetH(b) - GetEnergy(b));
}
double CMaterialProp::DoEnergy(double b1, double b2)
{
// calls the raw routine to get point energy,
// but deals with the load of special cases that
// arise because I insisted on trying to deal with
// laminations on a continuum basis.
double nrg,biron,bair;
// easiest case: the material is linear!
if (BHpoints==0)
{
double h1,h2;
if(LamType==0){ // laminated in-plane
h1=b1/((1.+LamFill*(mu_x-1.))*muo);
h2=b2/((1.+LamFill*(mu_y-1.))*muo);
}
if(LamType==1){ // laminated parallel to x;
h1=b1/((1.+LamFill*(mu_x-1.))*muo);
h2=b1*(LamFill/(mu_y*muo) + (1. - LamFill)/muo);
}
if(LamType==2){ // laminated parallel to x;
h2=b1/((1.+LamFill*(mu_y-1.))*muo);
h1=b1*(LamFill/(mu_x*muo) + (1. - LamFill)/muo);
}
if(LamType>2){
h1=b1/muo;
h2=b2/muo;
}
return ((h1*b1+h2*b2)/2.);
}
// Rats! The material is nonlinear. Now, we have to do
// a bit of work to get the energy.
if(LamType==0) nrg = GetEnergy(sqrt(b1*b1+b2*b2));
if(LamType==1){
biron=sqrt((b1/LamFill)*(b1/LamFill) + b2*b2);
bair=b2;
nrg = LamFill*GetEnergy(biron)+(1-LamFill)*bair*bair/(2.*muo);
}
if(LamType==2){
biron=sqrt((b2/LamFill)*(b2/LamFill) + b1*b1);
bair=b1;
nrg = LamFill*GetEnergy(biron)+(1-LamFill)*bair*bair/(2.*muo);
}
return nrg;
}
double CMaterialProp::DoCoEnergy(double b1, double b2)
{
double nrg,biron,bair;
// easiest case: the material is linear!
// in this case, energy and coenergy are the same!
if (BHpoints==0) return DoEnergy(b1,b2);
if(LamType==0) nrg = GetCoEnergy(sqrt(b1*b1+b2*b2));
if(LamType==1){
biron=sqrt((b1/LamFill)*(b1/LamFill) + b2*b2);
bair=b2;
nrg = LamFill*GetCoEnergy(biron)+(1-LamFill)*bair*bair/(2.*muo);
}
if(LamType==2){
biron=sqrt((b2/LamFill)*(b2/LamFill) + b1*b1);
bair=b1;
nrg = LamFill*GetCoEnergy(biron)+(1-LamFill)*bair*bair/(2.*muo);
}
return nrg;
}
double CMaterialProp::DoEnergy(CComplex b1, CComplex b2)
{
// This one is meant for the frequency!=0 case.
// Fortunately, there's not so much effort in this case.
CComplex mu1,mu2,h1,h2;
GetMu(b1,b2,mu1,mu2);
h1=b1/(mu1*muo);
h2=b2/(mu2*muo);
return (Re(h1*conj(b1)+h2*conj(b2))/4.);
}
double CMaterialProp::DoCoEnergy(CComplex b1, CComplex b2)
{
return DoEnergy(b1,b2);
}
void CMaterialProp::GetMu(CComplex b1, CComplex b2,
CComplex &mu1, CComplex &mu2)
{
// gets the permeability, given a flux density
// version for frequency!=0
CComplex biron;
// easiest case: the material is linear!
if (BHpoints==0)
{
mu1=mu_fdx;
mu2=mu_fdy;
return;
}
// Rats! The material is nonlinear.
if(MuMax>0) // incremental solution case...
{
// Arrgh!!! need incremental permeability about flux density from
// DC solution, not flux density of AC solution here.
// we're assuming that, in this case, b1 and b2 _do_ contain the DC operating point
IncrementalPermeability(sqrt(Re(b1*conj(b1)+b2*conj(b2))),mu1,mu2);
// MsgBox("mu=%g %g; b=%g",Re(mu1),Im(mu1),sqrt(Re(b1*conj(b1)+b2*conj(b2))));
return;
}
CComplex muiron;
if(LamType==0){
biron=sqrt(b1*conj(b1)+b2*conj(b2));
if(abs(biron)<1.e-08) mu1=1./slope[0]; //catch degenerate case
else mu1=biron/GetH(biron);
mu2=mu1;
}
if(LamType==1){
biron=sqrt((b1/LamFill)*(b1/LamFill) + b2*b2);
if(abs(biron)<1.e-08) muiron=1./slope[0];
else muiron=biron/GetH(biron);
mu1=muiron*LamFill;
mu2=1./(LamFill/muiron + (1. - LamFill)/muo);
}
if(LamType==2){
biron=sqrt((b2/LamFill)*(b2/LamFill) + b1*b1);
if(abs(biron)<1.e-08) muiron=1./slope[0];
else muiron=biron/GetH(biron);
mu2=muiron*LamFill;
mu1=1./(LamFill/muiron + (1. - LamFill)/muo);
}
// convert to relative permeability
mu1/=muo;
mu2/=muo;
return;
}
void CMaterialProp::GetMu(double b1, double b2,
double &mu1, double &mu2)
{
// gets the permeability, given a flux density
//
double biron;
mu1=mu2=muo; // default
// catch the incremental permeability case
if (MuMax>0) // for DC problems, MuMax is sleazily used as a flag to tell that it's incremental
{
IncrementalPermeability(sqrt(b1*b1 + b2*b2), mu1, mu2);
return;
}
// easiest case: the material is linear!
if (BHpoints==0)
{
if(LamType==0){ // laminated in-plane
mu1=((1.+LamFill*(mu_x-1.))*muo);
mu2=((1.+LamFill*(mu_y-1.))*muo);
}
if(LamType==1){ // laminated parallel to x;
mu1=((1.+LamFill*(mu_x-1.))*muo);
mu2=1./(LamFill/(mu_y*muo) + (1. - LamFill)/muo);
}
if(LamType==2){ // laminated parallel to x;
mu2=((1.+LamFill*(mu_y-1.))*muo);
mu1=1./(LamFill/(mu_x*muo) + (1. - LamFill)/muo);
}
}
// Rats! The material is nonlinear.
else{
double muiron;
if(LamType==0){
biron=sqrt(b1*b1+b2*b2);
if(biron<1.e-08) mu1=1./Re(slope[0]); //catch degenerate case
else mu1=biron/GetH(biron);
mu2=mu1;
}
if(LamType==1){
biron=sqrt((b1/LamFill)*(b1/LamFill) + b2*b2);
if(biron<1.e-08) muiron=1./Re(slope[0]);
else muiron=biron/GetH(biron);
mu1=muiron*LamFill;
mu2=1./(LamFill/muiron + (1. - LamFill)/muo);
}
if(LamType==2){
biron=sqrt((b2/LamFill)*(b2/LamFill) + b1*b1);
if(biron<1.e-08) muiron=1./Re(slope[0]);
else muiron=biron/GetH(biron);
mu2=muiron*LamFill;
mu1=1./(LamFill/muiron + (1. - LamFill)/muo);
}
}
// convert to relative permeability
mu1/=muo;
mu2/=muo;
return;
}
// get incremental permeability of a nonlinear material for use in
// incremental permeability formulation about DC offset
void CMaterialProp::IncrementalPermeability(double B, CComplex &mu1, CComplex &mu2)
{
// B == flux density in Tesla
// w == frequency in rad/s
double muinc,murel;
CComplex k;
double mu,w;
w=Frequency*2.*PI;
// get incremental permeability of the DC material
// (i.e. incremental permeability at the offset)
muinc=1./(muo*Re(GetdHdB(B)));
if (B==0) murel = (1./(muo*Re(slope[0])));
else murel=B/(muo*GetH(B));
// if material is not laminated, just apply hysteresis lag...
if ((Lam_d==0) || (LamFill==0))
{
mu1=muinc*exp(-I*Theta_hn*DEG*muinc/MuMax);
mu2=murel*exp(-I*Theta_hn*DEG*murel/MuMax);
return;
}
// crap. Need to make an equivalent permeability that rolls in the effects of laminated
// eddy currents, using the incremental permeability as the basis for creating the impedance.
// this can get annoying because we need to back out the iron portion of the permeability
// in the lamfill<1 case...
if (Cduct!=0)
{
CComplex deg45; deg45=1+I;
CComplex K,halflag;
double ds;
// incremental permeability direction
mu = (muinc - (1.-LamFill))/LamFill;
halflag=exp(-I*Theta_hn*DEG*mu/(2.*MuMax));
ds=sqrt(2./(0.4*PI*w*Cduct*mu));
K=halflag*deg45*Lam_d*0.001/(2.*ds);
mu1=(LamFill*mu*tanh(K)/K + (1.- LamFill));
// normal permeability direction
mu = (murel - (1.-LamFill))/LamFill;
halflag=exp(-I*Theta_hn*DEG*mu/(2.*MuMax));
ds=sqrt(2./(0.4*PI*w*Cduct*mu));
K=halflag*deg45*Lam_d*0.001/(2.*ds);
mu2=(LamFill*mu*tanh(K)/K + (1.- LamFill));
return;
}
else{
// incremental permeability direction
mu = (muinc - (1.-LamFill))/LamFill;
mu1=(mu*exp(-I*Theta_hn*DEG*mu/MuMax)*LamFill + (1.-LamFill));
// normal permeability direction
mu = (murel - (1.-LamFill))/LamFill;
mu2=(mu*exp(-I*Theta_hn*DEG*mu/MuMax)*LamFill + (1.-LamFill));
return;
}
}
// get incremental permeability of a nonlinear material for use in
// incremental permeability formulation about DC offset
void CMaterialProp::IncrementalPermeability(double B, double &mu1, double &mu2)
{
// B == flux density in Tesla
double muinc, murel;
// get incremental permeability of the DC material
// (i.e. incremental permeability at the offset)
muinc = 1. / (muo*Re(GetdHdB(B)));
if (B == 0) murel = (1. / (muo*Re(slope[0])));
else murel = B / (muo*GetH(B));
// if material is not laminated, just return
if ((Lam_d == 0) || (LamFill == 0)) {
mu1 = muinc;
mu2 = murel;
return;
}
// incremental permeability direction
mu1 = (muinc*LamFill + (1. - LamFill));
// normal permeability direction
mu2 = (murel*LamFill + (1. - LamFill));
return;
}
CBoundaryProp::CBoundaryProp()
{
BdryName="New Boundary";
BdryFormat=0; // type of boundary condition we are applying
// 0 = constant value of A
// 1 = Small skin depth eddy current BC
// 2 = Mixed BC
A0=0.; A1=0.;
A2=0.; phi=0.; // set value of A for BdryFormat=0;
Mu=0.; Sig=0.; // material properties necessary to apply
// eddy current BC
c0=0.; c1=0.; // coefficients for mixed BC
}
CPointProp::CPointProp()
{
PointName="New Point Property";
Jr=0.; Ji=0.; // applied point current, A
Ar=0.; Ai=0.; // prescribed nodal value;
}
CCircuit::CCircuit()
{
CircName="New Circuit";
CircType=0;
Amps=0.;
}