4955 lines
127 KiB
C++
4955 lines
127 KiB
C++
// femmviewDoc.cpp : implementation of the CFemmviewDoc class
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include <afx.h>
|
|
#include <afxtempl.h>
|
|
#include "problem.h"
|
|
#include "femm.h"
|
|
#include "xyplot.h"
|
|
#include "femmviewDoc.h"
|
|
#include "femmviewView.h"
|
|
#include "lua.h"
|
|
|
|
extern lua_State * lua;
|
|
extern void *pFemmviewdoc;
|
|
extern CLuaConsoleDlg *LuaConsole;
|
|
extern BOOL bLinehook;
|
|
|
|
extern void lua_baselibopen (lua_State *L);
|
|
extern void lua_iolibopen (lua_State *L);
|
|
extern void lua_strlibopen (lua_State *L);
|
|
extern void lua_mathlibopen (lua_State *L);
|
|
extern void lua_dblibopen (lua_State *L);
|
|
|
|
char *ParseDbl(char *t, double *f);
|
|
char *ParseString(char *t, CString *s);
|
|
char *ParseInt(char *t, int *f);
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CFemmviewDoc
|
|
|
|
IMPLEMENT_DYNCREATE(CFemmviewDoc, CDocument)
|
|
|
|
BEGIN_MESSAGE_MAP(CFemmviewDoc, CDocument)
|
|
//{{AFX_MSG_MAP(CFemmviewDoc)
|
|
//}}AFX_MSG_MAP
|
|
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CFemmviewDoc construction/destruction
|
|
|
|
double sqr(double x)
|
|
{
|
|
return x*x;
|
|
}
|
|
|
|
CFemmviewDoc::CFemmviewDoc()
|
|
{
|
|
// set some default values for problem definition
|
|
d_LineIntegralPoints=400;
|
|
d_ShiftH=TRUE;
|
|
d_WeightingScheme=0;
|
|
Frequency=0.;
|
|
Depth=1/0.0254;
|
|
LengthUnits=0;
|
|
ProblemType=FALSE;
|
|
ProblemNote="Add comments here.";
|
|
PrevSoln="";
|
|
PrevType = 0;
|
|
bIncremental=FALSE;
|
|
FirstDraw=-1;
|
|
A_High=0.;
|
|
A_Low=0.;
|
|
A_lb=0.;
|
|
A_ub=0.;
|
|
extRo=extRi=extZo=0;
|
|
Smooth=TRUE;
|
|
NumList=NULL;
|
|
ConList=NULL;
|
|
WeightingScheme=0;
|
|
bHasMask=FALSE;
|
|
LengthConv=(double *)calloc(6,sizeof(double));
|
|
LengthConv[0]=0.0254; //inches
|
|
LengthConv[1]=0.001; //millimeters
|
|
LengthConv[2]=0.01; //centimeters
|
|
LengthConv[3]=1.; //meters
|
|
LengthConv[4]=2.54e-05; //mils
|
|
LengthConv[5]=1.e-06; //micrometers
|
|
Coords=FALSE;
|
|
|
|
for(int i=0;i<9;i++)
|
|
d_PlotBounds[i][0]=d_PlotBounds[i][1]=
|
|
PlotBounds[i][0]=PlotBounds[i][1]=0;
|
|
|
|
// determine path to bin directory
|
|
BinDir=((CFemmApp *)AfxGetApp())->GetExecutablePath();
|
|
|
|
ScanPreferences();
|
|
|
|
WeightingScheme = d_WeightingScheme;
|
|
|
|
// lua initialization stuff
|
|
initalise_lua();
|
|
}
|
|
|
|
CFemmviewDoc::~CFemmviewDoc()
|
|
{
|
|
int i;
|
|
free(LengthConv);
|
|
for(i=0;i<meshnode.GetSize();i++)
|
|
if(ConList[i]!=NULL) free(ConList[i]);
|
|
free(ConList);
|
|
free(NumList);
|
|
if (pFemmviewdoc==this) pFemmviewdoc=NULL;
|
|
|
|
for(i=0;i<agelist.GetSize();i++)
|
|
{
|
|
if (agelist[i].qp!=NULL) free(agelist[i].qp); // list boundary nodes & weights
|
|
if (agelist[i].btc!=NULL) free(agelist[i].btc);
|
|
if (agelist[i].bts!=NULL) free(agelist[i].bts);
|
|
if (agelist[i].brc!=NULL) free(agelist[i].brc);
|
|
if (agelist[i].brs!=NULL) free(agelist[i].brs);
|
|
if (agelist[i].nh!=NULL) free(agelist[i].nh);
|
|
if (agelist[i].btcPrev!=NULL) free(agelist[i].btcPrev);
|
|
if (agelist[i].btsPrev!=NULL) free(agelist[i].btsPrev);
|
|
if (agelist[i].brcPrev!=NULL) free(agelist[i].brcPrev);
|
|
if (agelist[i].brsPrev!=NULL) free(agelist[i].brsPrev);
|
|
|
|
if (agelist[i].brPrev!=NULL) free(agelist[i].brPrev);
|
|
if (agelist[i].btPrev!=NULL) free(agelist[i].btPrev);
|
|
if (agelist[i].br!=NULL) free(agelist[i].br);
|
|
if (agelist[i].bt!=NULL) free(agelist[i].bt);
|
|
}
|
|
}
|
|
|
|
BOOL CFemmviewDoc::OnNewDocument()
|
|
{
|
|
if (!CDocument::OnNewDocument())
|
|
return FALSE;
|
|
|
|
// TODO: add reinitialization code here
|
|
// (SDI documents will reuse this document)
|
|
int i;
|
|
|
|
// clear out all current lines, nodes, and block labels
|
|
if(NumList!=NULL)
|
|
{
|
|
for(i=0;i<meshnode.GetSize();i++)
|
|
if(ConList[i]!=NULL) free(ConList[i]);
|
|
free(ConList); ConList=NULL;
|
|
free(NumList); NumList=NULL;
|
|
}
|
|
nodelist.RemoveAll();
|
|
linelist.RemoveAll();
|
|
blocklist.RemoveAll();
|
|
arclist.RemoveAll();
|
|
nodeproplist.RemoveAll();
|
|
lineproplist.RemoveAll();
|
|
blockproplist.RemoveAll();
|
|
circproplist.RemoveAll();
|
|
meshnode.RemoveAll();
|
|
meshelem.RemoveAll();
|
|
contour.RemoveAll();
|
|
|
|
for(i=0;i<agelist.GetSize();i++)
|
|
{
|
|
if (agelist[i].qp!=NULL) free(agelist[i].qp); // list of nod
|
|
if (agelist[i].btc!=NULL) free(agelist[i].btc);
|
|
if (agelist[i].bts!=NULL) free(agelist[i].bts);
|
|
if (agelist[i].brc!=NULL) free(agelist[i].brc);
|
|
if (agelist[i].brs!=NULL) free(agelist[i].brs);
|
|
if (agelist[i].nh!=NULL) free(agelist[i].nh);
|
|
if (agelist[i].btcPrev!=NULL) free(agelist[i].btcPrev);
|
|
if (agelist[i].btsPrev!=NULL) free(agelist[i].btsPrev);
|
|
if (agelist[i].brcPrev!=NULL) free(agelist[i].brcPrev);
|
|
if (agelist[i].brsPrev!=NULL) free(agelist[i].brsPrev);
|
|
|
|
if (agelist[i].brPrev!=NULL) free(agelist[i].brPrev);
|
|
if (agelist[i].btPrev!=NULL) free(agelist[i].btPrev);
|
|
if (agelist[i].br!=NULL) free(agelist[i].br);
|
|
if (agelist[i].bt!=NULL) free(agelist[i].bt);
|
|
}
|
|
agelist.RemoveAll();
|
|
|
|
// set problem attributes to generic ones;
|
|
Frequency=0.;
|
|
LengthUnits=0;
|
|
ProblemType=FALSE;
|
|
ProblemNote="Add comments here.";
|
|
bHasMask=FALSE;
|
|
extRo=extRi=extZo=0;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CFemmviewDoc serialization
|
|
|
|
void CFemmviewDoc::Serialize(CArchive& ar)
|
|
{
|
|
if (ar.IsStoring())
|
|
{
|
|
// TODO: add storing code here
|
|
}
|
|
else
|
|
{
|
|
// TODO: add loading code here
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CFemmviewDoc diagnostics
|
|
|
|
#ifdef _DEBUG
|
|
void CFemmviewDoc::AssertValid() const
|
|
{
|
|
CDocument::AssertValid();
|
|
}
|
|
|
|
void CFemmviewDoc::Dump(CDumpContext& dc) const
|
|
{
|
|
CDocument::Dump(dc);
|
|
}
|
|
#endif //_DEBUG
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CFemmviewDoc commands
|
|
|
|
BOOL CFemmviewDoc::OnOpenDocument(LPCTSTR lpszPathName)
|
|
{
|
|
if (!CDocument::OnOpenDocument(lpszPathName))
|
|
return FALSE;
|
|
|
|
FILE *fp;
|
|
int i,j,k,t;
|
|
char s[1024],q[1024];
|
|
char *v;
|
|
double b,bi,br;
|
|
double zr,zi;
|
|
BOOL flag=FALSE;
|
|
CPointProp PProp;
|
|
CBoundaryProp BProp;
|
|
CMaterialProp MProp;
|
|
CCircuit CProp;
|
|
CNode node;
|
|
CSegment segm;
|
|
CArcSegment asegm;
|
|
CElement elm;
|
|
CBlockLabel blk;
|
|
CMeshNode mnode;
|
|
CPoint mline;
|
|
|
|
// make sure old document is cleared out...
|
|
if(NumList!=NULL){
|
|
for(i=0;i<meshnode.GetSize();i++)
|
|
if(ConList[i]!=NULL) free(ConList[i]);
|
|
free(ConList); ConList=NULL;
|
|
free(NumList); NumList=NULL;
|
|
}
|
|
nodelist.RemoveAll();
|
|
linelist.RemoveAll();
|
|
blocklist.RemoveAll();
|
|
arclist.RemoveAll();
|
|
nodeproplist.RemoveAll();
|
|
lineproplist.RemoveAll();
|
|
blockproplist.RemoveAll();
|
|
circproplist.RemoveAll();
|
|
meshnode.RemoveAll();
|
|
meshelem.RemoveAll();
|
|
contour.RemoveAll();
|
|
|
|
if ((fp=fopen(lpszPathName,"rt"))==NULL){
|
|
MsgBox("Couldn't read from specified .poly file");
|
|
return FALSE;
|
|
}
|
|
|
|
// define some defaults
|
|
Frequency=0.;
|
|
ProblemType=0;
|
|
Coords=0;
|
|
ProblemNote="";
|
|
bHasMask=FALSE;
|
|
Depth=-1;
|
|
|
|
// parse the file
|
|
while (flag==FALSE)
|
|
{
|
|
fgets(s,1024,fp);
|
|
sscanf(s,"%s",q);
|
|
|
|
// Deal with flag for file format version
|
|
if( _strnicmp(q,"[format]",8)==0 ){
|
|
double vers;
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&vers); vers = 10.*vers + 0.5;
|
|
if( ((int) vers)!=40 ){
|
|
MsgBox("This file is from a different version of FEMM\nRe-analyze the problem using the current version.");
|
|
fclose(fp);
|
|
return FALSE;
|
|
}
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Frequency of the problem
|
|
if( _strnicmp(q,"[frequency]",11)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&Frequency);
|
|
Frequency=fabs(Frequency);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Frequency of the problem
|
|
if( _strnicmp(q,"[depth]",7)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&Depth);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
|
|
// Units of length used by the problem
|
|
if( _strnicmp(q,"[lengthunits]",13)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%s",q);
|
|
if( _strnicmp(q,"inches",6)==0) LengthUnits=0;
|
|
else if( _strnicmp(q,"millimeters",11)==0) LengthUnits=1;
|
|
else if( _strnicmp(q,"centimeters",1)==0) LengthUnits=2;
|
|
else if( _strnicmp(q,"mils",4)==0) LengthUnits=4;
|
|
else if( _strnicmp(q,"microns",6)==0) LengthUnits=5;
|
|
else if( _strnicmp(q,"meters",6)==0) LengthUnits=3;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Problem Type (planar or axisymmetric)
|
|
if( _strnicmp(q,"[problemtype]",13)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%s",q);
|
|
if( _strnicmp(q,"planar",6)==0) ProblemType=0;
|
|
if( _strnicmp(q,"axisymmetric",3)==0) ProblemType=1;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Coordinates (cartesian or polar)
|
|
if( _strnicmp(q,"[coordinates]",13)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%s",q);
|
|
if ( _strnicmp(q,"cartesian",4)==0) Coords=0;
|
|
if ( _strnicmp(q,"polar",5)==0) Coords=1;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Comments
|
|
if (_strnicmp(q,"[comment]",9)==0){
|
|
v=StripKey(s);
|
|
// put in carriage returns;
|
|
k=(int) strlen(v);
|
|
for(i=0;i<k;i++)
|
|
if((v[i]=='\\') && (v[i+1]=='n')){
|
|
v[i]=13;
|
|
v[i+1]=10;
|
|
}
|
|
|
|
for(i=0;i<k;i++)
|
|
if(v[i]=='\"'){
|
|
v=v+i+1;
|
|
i=k;
|
|
}
|
|
k=(int) strlen(v);
|
|
if(k>0) for(i=k-1;i>=0;i--){
|
|
if(v[i]=='\"'){
|
|
v[i]=0;
|
|
i=-1;
|
|
}
|
|
}
|
|
ProblemNote=v;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// properties for axisymmetric external region
|
|
if( _strnicmp(q,"[extzo]",7)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&extZo);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"[extro]",7)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&extRo);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"[extri]",7)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&extRi);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// name of previous solution file for AC incremental permeability solution
|
|
// Previous Solution File
|
|
if( _strnicmp(q,"[prevsoln]",10)==0){
|
|
int i;
|
|
v=StripKey(s);
|
|
|
|
// have to do this carefully to accept a filename with spaces
|
|
k=(int) strlen(v);
|
|
for(i=0;i<k;i++)
|
|
if(v[i]=='\"'){
|
|
v=v+i+1;
|
|
i=k;
|
|
}
|
|
|
|
k=(int) strlen(v);
|
|
if(k>0) for(i=k-1;i>=0;i--){
|
|
if(v[i]=='\"'){
|
|
v[i]=0;
|
|
i=-1;
|
|
}
|
|
}
|
|
|
|
PrevSoln=v;
|
|
if(PrevSoln.GetLength()>0) bIncremental=PrevType;
|
|
else bIncremental=FALSE;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if (_strnicmp(q, "[prevtype]", 10) == 0) {
|
|
v = StripKey(s);
|
|
sscanf(v, "%i", &PrevType);
|
|
q[0] = NULL;
|
|
// 0 == None
|
|
// 1 == Incremental
|
|
// 2 == Frozen
|
|
}
|
|
|
|
// Point Properties
|
|
if( _strnicmp(q,"<beginpoint>",11)==0){
|
|
PProp.PointName="New Point Property";
|
|
PProp.Jr=0.;
|
|
PProp.Ji=0.;
|
|
PProp.Ar=0.;
|
|
PProp.Ai=0.;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<pointname>",11)==0){
|
|
v=StripKey(s);
|
|
k=(int) strlen(v);
|
|
for(i=0;i<k;i++)
|
|
if(v[i]=='\"'){
|
|
v=v+i+1;
|
|
i=k;
|
|
}
|
|
k=(int) strlen(v);
|
|
if(k>0) for(i=k-1;i>=0;i--){
|
|
if(v[i]=='\"'){
|
|
v[i]=0;
|
|
i=-1;
|
|
}
|
|
}
|
|
PProp.PointName=v;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<A_re>",6)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&PProp.Ar);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<A_im>",6)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&PProp.Ai);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<I_re>",6)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&PProp.Jr);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<I_im>",6)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&PProp.Ji);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<endpoint>",9)==0){
|
|
nodeproplist.Add(PProp);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Boundary Properties;
|
|
if( _strnicmp(q,"<beginbdry>",11)==0){
|
|
BProp.BdryName="New Boundary";
|
|
BProp.BdryFormat=0;
|
|
BProp.A0=0.;
|
|
BProp.A1=0.;
|
|
BProp.A2=0.;
|
|
BProp.phi=0.;
|
|
BProp.Mu=0.;
|
|
BProp.Sig=0.;
|
|
BProp.c0=0.;
|
|
BProp.c1=0.;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<bdryname>",10)==0){
|
|
v=StripKey(s);
|
|
k=(int) strlen(v);
|
|
for(i=0;i<k;i++)
|
|
if(v[i]=='\"'){
|
|
v=v+i+1;
|
|
i=k;
|
|
}
|
|
k=(int) strlen(v);
|
|
if(k>0) for(i=k-1;i>=0;i--){
|
|
if(v[i]=='\"'){
|
|
v[i]=0;
|
|
i=-1;
|
|
}
|
|
}
|
|
BProp.BdryName=v;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<bdrytype>",10)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&BProp.BdryFormat);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<mu_ssd>",8)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.Mu);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<sigma_ssd>",11)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.Sig);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<A_0>",5)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.A0);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<A_1>",5)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.A1);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<A_2>",5)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.A2);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<phi>",5)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.phi);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<c0>",4)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.c0.re);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<c1>",4)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.c1.re);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<c0i>",5)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.c0.im);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<c1i>",5)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.c1.im);
|
|
q[0]=NULL;
|
|
}
|
|
if( _strnicmp(q,"<endbdry>",9)==0){
|
|
lineproplist.Add(BProp);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
|
|
// Block Properties;
|
|
if( _strnicmp(q,"<beginblock>",12)==0){
|
|
MProp.BlockName="New Material";
|
|
MProp.mu_x=1.;
|
|
MProp.mu_y=1.; // permeabilities, relative
|
|
MProp.H_c=0.; // magnetization, A/m
|
|
MProp.Jr=0.;
|
|
MProp.Ji=0.; // applied current density, MA/m^2
|
|
MProp.Cduct=0.; // conductivity of the material, MS/m
|
|
MProp.Lam_d=0.; // lamination thickness, mm
|
|
MProp.Theta_hn=0.; // hysteresis angle, degrees
|
|
MProp.Theta_hx=0.; // hysteresis angle, degrees
|
|
MProp.Theta_hy=0.; // hysteresis angle, degrees
|
|
MProp.NStrands=0;
|
|
MProp.WireD=0;
|
|
MProp.LamFill=1.; // lamination fill factor;
|
|
MProp.LamType=0; // type of lamination;
|
|
MProp.BHpoints=0;
|
|
MProp.MuMax=0;
|
|
MProp.Frequency=Frequency;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<blockname>",10)==0){
|
|
v=StripKey(s);
|
|
k=(int) strlen(v);
|
|
for(i=0;i<k;i++)
|
|
if(v[i]=='\"'){
|
|
v=v+i+1;
|
|
i=k;
|
|
}
|
|
k=(int) strlen(v);
|
|
if(k>0) for(i=k-1;i>=0;i--){
|
|
if(v[i]=='\"'){
|
|
v[i]=0;
|
|
i=-1;
|
|
}
|
|
}
|
|
MProp.BlockName=v;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<mu_x>",6)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.mu_x);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<mu_y>",6)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.mu_y);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<H_c>",5)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.H_c);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<J_re>",6)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.Jr);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<J_im>",6)==0){
|
|
v=StripKey(s);
|
|
if (Frequency!=0) sscanf(v,"%lf",&MProp.Ji);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<sigma>",7)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.Cduct);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<phi_h>",7)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.Theta_hn);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<phi_hx>",8)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.Theta_hx);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<phi_hy>",8)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.Theta_hy);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<d_lam>",7)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.Lam_d);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<LamFill>",8)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.LamFill);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<LamType>",9)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&MProp.LamType);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<NStrands>",10)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&MProp.NStrands);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<WireD>",7)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.WireD);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<BHPoints>",10)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&MProp.BHpoints);
|
|
if (MProp.BHpoints>0)
|
|
{
|
|
MProp.Hdata=(CComplex *)calloc(MProp.BHpoints,sizeof(CComplex));
|
|
MProp.Bdata=(double *)calloc(MProp.BHpoints,sizeof(double));
|
|
for(j=0;j<MProp.BHpoints;j++){
|
|
fgets(s,1024,fp);
|
|
MProp.Hdata[j]=0;
|
|
sscanf(s,"%lf %lf",&MProp.Bdata[j],&MProp.Hdata[j].re);
|
|
}
|
|
}
|
|
q[0]=NULL;
|
|
|
|
}
|
|
|
|
if( _strnicmp(q,"<endblock>",9)==0){
|
|
if (MProp.BHpoints>0)
|
|
{
|
|
if (bIncremental!=0){
|
|
// first time through was just to get MuMax from AC curve...
|
|
CComplex *tmpHdata=(CComplex *)calloc(MProp.BHpoints,sizeof(CComplex));
|
|
double *tmpBdata=(double *)calloc(MProp.BHpoints,sizeof(double));
|
|
for(i=0;i<MProp.BHpoints;i++)
|
|
{
|
|
tmpHdata[i]=MProp.Hdata[i];
|
|
tmpBdata[i]=MProp.Bdata[i];
|
|
}
|
|
MProp.GetSlopes(Frequency*2.*PI);
|
|
for(i=0;i<MProp.BHpoints;i++)
|
|
{
|
|
MProp.Hdata[i]=tmpHdata[i];
|
|
MProp.Bdata[i]=tmpBdata[i];
|
|
}
|
|
free(tmpHdata);
|
|
free(tmpBdata);
|
|
free(MProp.slope);
|
|
MProp.slope=NULL;
|
|
|
|
// set a flag for DC incremental permeability problems
|
|
if ((bIncremental == TRUE) && (Frequency==0)) MProp.MuMax = 1;
|
|
|
|
// second time through is to get the DC curve
|
|
MProp.GetSlopes(0);
|
|
}
|
|
else{
|
|
MProp.GetSlopes(Frequency*2.*PI);
|
|
MProp.MuMax=0; // this is the hint to the materials prop that this is _not_ incremental
|
|
}
|
|
}
|
|
blockproplist.Add(MProp);
|
|
MProp.BHpoints=0;
|
|
MProp.Bdata=NULL;
|
|
MProp.Hdata=NULL;
|
|
MProp.slope=NULL;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Circuit Properties
|
|
if( _strnicmp(q,"<begincircuit>",14)==0){
|
|
CProp.CircName="New Circuit";
|
|
CProp.CircType=0;
|
|
CProp.Amps=0;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<circuitname>",13)==0){
|
|
v=StripKey(s);
|
|
k=(int) strlen(v);
|
|
for(i=0;i<k;i++)
|
|
if(v[i]=='\"'){
|
|
v=v+i+1;
|
|
i=k;
|
|
}
|
|
k=(int) strlen(v);
|
|
if(k>0) for(i=k-1;i>=0;i--){
|
|
if(v[i]=='\"'){
|
|
v[i]=0;
|
|
i=-1;
|
|
}
|
|
}
|
|
CProp.CircName=v;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<totalamps_re>",14)==0){
|
|
double inval;
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&inval);
|
|
CProp.Amps+=inval;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<totalamps_im>",14)==0){
|
|
double inval;
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&inval);
|
|
if (Frequency!=0) CProp.Amps+=(I*inval);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<circuittype>",13)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&CProp.CircType);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<endcircuit>",12)==0){
|
|
circproplist.Add(CProp);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Points list;
|
|
if(_strnicmp(q,"[numpoints]",11)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&k);
|
|
for(i=0;i<k;i++)
|
|
{
|
|
fgets(s,1024,fp);
|
|
sscanf(s,"%lf %lf %i\n",&node.x,&node.y,&t);
|
|
node.BoundaryMarker=t-1;
|
|
nodelist.Add(node);
|
|
}
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// read in segment list
|
|
if(_strnicmp(q,"[numsegments]",13)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&k);
|
|
for(i=0;i<k;i++)
|
|
{
|
|
fgets(s,1024,fp);
|
|
sscanf(s,"%i %i %lf %i %i %i\n",&segm.n0,&segm.n1,&segm.MaxSideLength,&t,&segm.Hidden,&segm.InGroup);
|
|
segm.BoundaryMarker=t-1;
|
|
linelist.Add(segm);
|
|
}
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// read in arc segment list
|
|
if(_strnicmp(q,"[numarcsegments]",13)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&k);
|
|
for(i=0;i<k;i++)
|
|
{
|
|
fgets(s,1024,fp);
|
|
sscanf(s,"%i %i %lf %lf %i %i %i %lf\n",&asegm.n0,&asegm.n1,
|
|
&asegm.ArcLength,&asegm.MaxSideLength,&t,&asegm.Hidden,&asegm.InGroup,&b);
|
|
asegm.BoundaryMarker=t-1;
|
|
if (b>0) asegm.MaxSideLength=b; // use as-meshed max side length for display purposes
|
|
arclist.Add(asegm);
|
|
}
|
|
q[0]=NULL;
|
|
}
|
|
|
|
|
|
// read in list of holes;
|
|
if(_strnicmp(q,"[numholes]",13)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&k);
|
|
if(k>0)
|
|
{
|
|
blk.BlockType=-1;
|
|
blk.MaxArea=0;
|
|
for(i=0;i<k;i++)
|
|
{
|
|
fgets(s,1024,fp);
|
|
sscanf(s,"%lf %lf\n",&blk.x,&blk.y);
|
|
// blocklist.Add(blk);
|
|
// don't add holes to the list
|
|
// of block labels because it messes up the
|
|
// number of block labels.
|
|
}
|
|
}
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// read in regional attributes
|
|
if(_strnicmp(q,"[numblocklabels]",13)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&k);
|
|
for(i=0;i<k;i++)
|
|
{
|
|
fgets(s,1024,fp);
|
|
|
|
//some defaults
|
|
blk.MaxArea=0.;
|
|
blk.MagDir=0.;
|
|
blk.MagDirFctn.Empty();
|
|
blk.Turns=1;
|
|
blk.InCircuit=0;
|
|
blk.InGroup=0;
|
|
blk.IsExternal=0;
|
|
blk.IsDefault=0;
|
|
|
|
// scan in data
|
|
v=ParseDbl(s,&blk.x);
|
|
v=ParseDbl(v,&blk.y);
|
|
v=ParseInt(v,&blk.BlockType);
|
|
v=ParseDbl(v,&blk.MaxArea);
|
|
v=ParseInt(v,&blk.InCircuit);
|
|
v=ParseDbl(v,&blk.MagDir);
|
|
v=ParseInt(v,&blk.InGroup);
|
|
v=ParseInt(v,&blk.Turns);
|
|
v=ParseInt(v,&blk.IsExternal);
|
|
blk.IsDefault = blk.IsExternal & 2;
|
|
blk.IsExternal = blk.IsExternal & 1;
|
|
v=ParseString(v,&blk.MagDirFctn);
|
|
|
|
if (blk.MaxArea<0) blk.MaxArea=0;
|
|
else blk.MaxArea=PI*blk.MaxArea*blk.MaxArea/4.;
|
|
blk.BlockType-=1;
|
|
blk.InCircuit-=1;
|
|
blocklist.Add(blk);
|
|
}
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if(_strnicmp(q,"[solution]",10)==0){
|
|
flag=TRUE;
|
|
q[0]=NULL;
|
|
}
|
|
}
|
|
|
|
// read in meshnodes;
|
|
fscanf(fp,"%i\n",&k);
|
|
meshnode.SetSize(k);
|
|
for(i=0;i<k;i++)
|
|
{
|
|
fgets(s,1024,fp);
|
|
if (Frequency!=0)
|
|
{
|
|
int bc;
|
|
|
|
if (!bIncremental)
|
|
sscanf(s,"%lf %lf %lf %lf",&mnode.x,&mnode.y,&mnode.A.re,&mnode.A.im);
|
|
else
|
|
sscanf(s,"%lf %lf %lf %lf %i %lf",&mnode.x,&mnode.y,&mnode.A.re,&mnode.A.im,&bc,&mnode.Aprev);
|
|
}
|
|
else{
|
|
int bc;
|
|
|
|
if (!bIncremental)
|
|
sscanf(s,"%lf %lf %lf",&mnode.x,&mnode.y,&mnode.A.re);
|
|
else
|
|
sscanf(s, "%lf %lf %lf %i %lf", &mnode.x, &mnode.y, &mnode.A.re, &bc, &mnode.Aprev);
|
|
mnode.A.im=0;
|
|
}
|
|
meshnode.SetAt(i,mnode);
|
|
}
|
|
|
|
// read in elements;
|
|
fscanf(fp,"%i\n",&k);
|
|
meshelem.SetSize(k);
|
|
for(i=0;i<k;i++)
|
|
{
|
|
fgets(s,1024,fp);
|
|
if (!bIncremental)
|
|
sscanf(s,"%i %i %i %i",&elm.p[0],&elm.p[1],&elm.p[2],&elm.lbl);
|
|
else
|
|
sscanf(s,"%i %i %i %i %lf",&elm.p[0],&elm.p[1],&elm.p[2],&elm.lbl,&elm.Jp);
|
|
elm.blk=blocklist[elm.lbl].BlockType;
|
|
meshelem.SetAt(i,elm);
|
|
}
|
|
|
|
// read in circuit data;
|
|
fscanf(fp,"%i\n",&k);
|
|
for(i=0;i<k;i++){
|
|
fgets(s,1024,fp);
|
|
if (Frequency==0){
|
|
sscanf(s,"%i %lf",&j,&zr);
|
|
blocklist[i].Case=j;
|
|
if (j==0) blocklist[i].dVolts=zr;
|
|
else blocklist[i].J=zr;
|
|
}
|
|
else{
|
|
sscanf(s,"%i %lf %lf",&j,&zr,&zi);
|
|
blocklist[i].Case=j;
|
|
if (j==0) blocklist[i].dVolts=zr + I*zi;
|
|
else blocklist[i].J=zr + I*zi;
|
|
}
|
|
}
|
|
|
|
// femmview doesn't actively use PBC data, but it needs to read it to get to the
|
|
// air gap element data beyond
|
|
if (fgets(s,1024,fp)!=NULL)
|
|
{
|
|
sscanf(s,"%i",&k);
|
|
for(i=0;i<k;i++)
|
|
fgets(s,1024,fp);
|
|
}
|
|
|
|
// Read in Air Gap Element information
|
|
fgets(s,1024,fp); sscanf(s,"%i",&k);
|
|
for(i=0;i<k;i++){
|
|
CAirGapElement age;
|
|
|
|
fgets(s,1024,fp);
|
|
age.BdryName=s; age.BdryName.Replace("\"",""); age.BdryName.Replace("\n","");
|
|
fgets(s,1024,fp);
|
|
sscanf(s,"%i %lf %lf %lf %lf %lf %lf %lf %i %lf %lf",
|
|
&age.BdryFormat,&age.InnerAngle,&age.OuterAngle,
|
|
&age.ri,&age.ro,&age.totalArcLength,
|
|
&age.agc.re,&age.agc.im,&age.totalArcElements,
|
|
&age.InnerShift,&age.OuterShift);
|
|
|
|
age.ri*=LengthConv[LengthUnits];
|
|
age.ro*=LengthConv[LengthUnits];
|
|
|
|
// allocate space
|
|
if (age.totalArcElements>0)
|
|
{
|
|
j=age.totalArcElements+1;
|
|
age.qp=(CQuadPoint *)calloc(j,sizeof(CQuadPoint)); // list of nodes on inner radius
|
|
}
|
|
|
|
for(j=0;j<=age.totalArcElements;j++){
|
|
CQuadPoint q;
|
|
|
|
fgets(s,1024,fp);
|
|
sscanf(s,"%i %lf %i %lf %i %lf %i %lf",
|
|
&q.n0, &q.w0,
|
|
&q.n1, &q.w1,
|
|
&q.n2, &q.w2,
|
|
&q.n3, &q.w3);
|
|
age.qp[j]=q;
|
|
}
|
|
if (age.totalArcElements>0) agelist.Add(age);
|
|
}
|
|
|
|
fclose(fp);
|
|
|
|
// figure out amplitudes of harmonics for AGE boundary conditions
|
|
for (i=0;i<agelist.GetSize();i++)
|
|
{
|
|
int m;
|
|
double tta,R,dr,ri,ro,n,dt;
|
|
CComplex brc,brs,btc,bts;
|
|
double brcPrev,brsPrev,btcPrev,btsPrev;
|
|
|
|
R=(agelist[i].ri + agelist[i].ro)/2.;
|
|
dr=(agelist[i].ro - agelist[i].ri);
|
|
ri=agelist[i].ri/R;
|
|
ro=agelist[i].ro/R;
|
|
dt=(PI/180.)*agelist[i].totalArcLength/((double) agelist[i].totalArcElements);
|
|
|
|
if (agelist[i].BdryFormat==0)
|
|
{
|
|
agelist[i].nn=(agelist[i].totalArcElements/2)+1; // periodic AGE
|
|
m = (int) round(360./agelist[i].totalArcLength);
|
|
}
|
|
else
|
|
{
|
|
agelist[i].nn=(agelist[i].totalArcElements+1)/2; // antiperiodic AGE
|
|
m = (int) round(180./agelist[i].totalArcLength);
|
|
}
|
|
|
|
// for present solution
|
|
agelist[i].brc=(CComplex *)calloc(agelist[i].nn,sizeof(CComplex));
|
|
agelist[i].brs=(CComplex *)calloc(agelist[i].nn,sizeof(CComplex));
|
|
agelist[i].btc=(CComplex *)calloc(agelist[i].nn,sizeof(CComplex));
|
|
agelist[i].bts=(CComplex *)calloc(agelist[i].nn,sizeof(CComplex));
|
|
agelist[i].br=(CComplex *)calloc(agelist[i].totalArcElements,sizeof(CComplex));
|
|
agelist[i].bt=(CComplex *)calloc(agelist[i].totalArcElements,sizeof(CComplex));
|
|
agelist[i].nh=(int *)calloc(agelist[i].nn,sizeof(int));
|
|
|
|
// for previous solution;
|
|
if (!bIncremental)
|
|
{
|
|
agelist[i].brcPrev=NULL;
|
|
agelist[i].brsPrev=NULL;
|
|
agelist[i].btcPrev=NULL;
|
|
agelist[i].btsPrev=NULL;
|
|
agelist[i].brPrev=NULL;
|
|
agelist[i].btPrev=NULL;
|
|
}
|
|
else{
|
|
agelist[i].brcPrev=(double *)calloc(agelist[i].nn,sizeof(double));
|
|
agelist[i].brsPrev=(double *)calloc(agelist[i].nn,sizeof(double));
|
|
agelist[i].btcPrev=(double *)calloc(agelist[i].nn,sizeof(double));
|
|
agelist[i].btsPrev=(double *)calloc(agelist[i].nn,sizeof(double));
|
|
agelist[i].brPrev=(double *)calloc(agelist[i].totalArcElements,sizeof(double));
|
|
agelist[i].btPrev=(double *)calloc(agelist[i].totalArcElements,sizeof(double));
|
|
}
|
|
|
|
// compute A and B at center of each gap element
|
|
agelist[i].aco=0;
|
|
for(k=0;k<agelist[i].totalArcElements;k++)
|
|
{
|
|
int nn[10];
|
|
double ww[10];
|
|
int kk;
|
|
CComplex a[10];
|
|
CComplex ac;
|
|
|
|
double ci=agelist[i].InnerShift;
|
|
double co=agelist[i].OuterShift;
|
|
|
|
|
|
// inner nodes
|
|
if ((k-1)<0){
|
|
nn[0]=agelist[i].qp[agelist[i].totalArcElements-1].n0;
|
|
ww[0]=agelist[i].qp[agelist[i].totalArcElements-1].w0;
|
|
}
|
|
else{
|
|
nn[0]=agelist[i].qp[k-1].n0;
|
|
ww[0]=agelist[i].qp[k-1].w0;
|
|
}
|
|
|
|
nn[1]=agelist[i].qp[k].n0;
|
|
nn[2]=agelist[i].qp[k].n1;
|
|
nn[3]=agelist[i].qp[k+1].n1;
|
|
ww[1]=agelist[i].qp[k].w0;
|
|
ww[2]=agelist[i].qp[k].w1;
|
|
ww[3]=agelist[i].qp[k+1].w1;
|
|
|
|
if((k+2)>agelist[i].totalArcElements){
|
|
nn[4]=agelist[i].qp[1].n1;
|
|
ww[4]=agelist[i].qp[1].w1;
|
|
}
|
|
else{
|
|
nn[4]=agelist[i].qp[k+2].n1;
|
|
ww[4]=agelist[i].qp[k+2].w1;
|
|
}
|
|
|
|
// outer nodes
|
|
if ((k-1)<0){
|
|
nn[5]=agelist[i].qp[agelist[i].totalArcElements-1].n2;
|
|
ww[5]=agelist[i].qp[agelist[i].totalArcElements-1].w2;
|
|
}
|
|
else{
|
|
nn[5]=agelist[i].qp[k-1].n2;
|
|
ww[5]=agelist[i].qp[k-1].w2;
|
|
}
|
|
|
|
nn[6]=agelist[i].qp[k].n2;
|
|
nn[7]=agelist[i].qp[k].n3;
|
|
nn[8]=agelist[i].qp[k+1].n3;
|
|
ww[6]=agelist[i].qp[k].w2;
|
|
ww[7]=agelist[i].qp[k].w3;
|
|
ww[8]=agelist[i].qp[k+1].w3;
|
|
|
|
if((k+2)>agelist[i].totalArcElements){
|
|
nn[9]=agelist[i].qp[1].n3;
|
|
ww[9]=agelist[i].qp[1].w3;
|
|
}
|
|
else{
|
|
nn[9]=agelist[i].qp[k+2].n3;
|
|
ww[9]=agelist[i].qp[k+2].w3;
|
|
}
|
|
|
|
// fix antiperiodic weights...
|
|
if ((k==0) && (agelist[i].BdryFormat==1))
|
|
{
|
|
ww[0]=-ww[0];
|
|
ww[5]=-ww[5];
|
|
}
|
|
if (((k+1)==agelist[i].totalArcElements) && (agelist[i].BdryFormat==1))
|
|
{
|
|
ww[4]=-ww[4];
|
|
ww[9]=-ww[9];
|
|
}
|
|
|
|
for(kk=0;kk<10;kk++)
|
|
a[kk]=meshnode[nn[kk]].A*ww[kk];
|
|
|
|
// A at the center of the element
|
|
if (agelist[i].BdryFormat==0)
|
|
{
|
|
ac = (2*a[2]+2*a[3]+2*a[7]+2*a[8]+a[1]*ci+(a[2]-a[3]-a[4])*ci-(a[0]-3*a[1]+a[2]+3*a[3]-2*a[4])*pow(ci,2)+(a[0]-2*a[1]+2*a[3]-a[4])*pow(ci,3)+(a[6]+a[7]-a[8]-a[9])*co-
|
|
(a[5]-3*a[6]+a[7]+3*a[8]-2*a[9])*pow(co,2)+(a[5]-2*a[6]+2*a[8]-a[9])*pow(co,3))/8.;
|
|
agelist[i].aco += ac /((double) agelist[i].totalArcElements);
|
|
}
|
|
|
|
// flux density for this element
|
|
agelist[i].br[k]=(-(ci*a[1])-2*a[2]+2*a[3]+ci*(a[2]+a[3]-a[4])-ci*ci*ci*(a[0]-4*a[1]+6*a[2]-4*a[3]+a[4])+ci*ci*(a[0]-5*a[1]+9*a[2]-7*a[3]+2*a[4])-2*a[7]+
|
|
2*a[8]+co*(-a[6]+a[7]+a[8]-a[9])-co*co*co*(a[5]-4*a[6]+6*a[7]-4*a[8]+a[9])+co*co*(a[5]-5*a[6]+9*a[7]-7*a[8]+2*a[9]))/(4*dt*R);
|
|
agelist[i].bt[k]=(ci*a[1]+2*a[2]+2*a[3]-ci*ci*(a[0]-3*a[1]+a[2]+3*a[3]-2*a[4])+ci*(a[2]-a[3]-a[4])+ci*ci*ci*(a[0]-2*a[1]+2*a[3]-a[4])-co*a[6]+
|
|
(-2+co)*(1+co)*a[7]-2*a[8]+co*(a[8]+co*(a[5]-3*a[6]+3*a[8]-2*a[9])+a[9]+co*co*(-a[5]+2*a[6]-2*a[8]+a[9])))/(4*dr);
|
|
if (bIncremental)
|
|
{
|
|
for(kk=0;kk<10;kk++)
|
|
a[kk]=meshnode[nn[kk]].Aprev*ww[kk];
|
|
agelist[i].brPrev[k]=Re((-(ci*a[1])-2*a[2]+2*a[3]+ci*(a[2]+a[3]-a[4])-ci*ci*ci*(a[0]-4*a[1]+6*a[2]-4*a[3]+a[4])+ci*ci*(a[0]-5*a[1]+9*a[2]-7*a[3]+2*a[4])-2*a[7]+
|
|
2*a[8]+co*(-a[6]+a[7]+a[8]-a[9])-co*co*co*(a[5]-4*a[6]+6*a[7]-4*a[8]+a[9])+co*co*(a[5]-5*a[6]+9*a[7]-7*a[8]+2*a[9]))/(4*dt*R));
|
|
agelist[i].btPrev[k]=Re((ci*a[1]+2*a[2]+2*a[3]-ci*ci*(a[0]-3*a[1]+a[2]+3*a[3]-2*a[4])+ci*(a[2]-a[3]-a[4])+ci*ci*ci*(a[0]-2*a[1]+2*a[3]-a[4])-co*a[6]+
|
|
(-2+co)*(1+co)*a[7]-2*a[8]+co*(a[8]+co*(a[5]-3*a[6]+3*a[8]-2*a[9])+a[9]+co*co*(-a[5]+2*a[6]-2*a[8]+a[9])))/(4*dr));
|
|
}
|
|
}
|
|
|
|
// Convolve with sines and cosines to get amplitudes of each harmonic
|
|
for(j=0;j<agelist[i].nn;j++)
|
|
{
|
|
if (agelist[i].BdryFormat==0) agelist[i].nh[j]=m*j;
|
|
else agelist[i].nh[j]=m*(2*j+1);
|
|
|
|
n=agelist[i].nh[j];
|
|
brc=0; brs=0; btc=0; bts=0;
|
|
brcPrev=0; brsPrev=0; btcPrev=0; btsPrev=0;
|
|
for(k=0;k<agelist[i].totalArcElements;k++)
|
|
{
|
|
tta=(((double) k) + 0.5)*dt;
|
|
tta*=n; // multiply times # of harmonic under consideration
|
|
|
|
brc += agelist[i].br[k] * cos(tta);
|
|
brs += agelist[i].br[k] * sin(tta);
|
|
btc += agelist[i].bt[k] * cos(tta);
|
|
bts += agelist[i].bt[k] * sin(tta);
|
|
|
|
if (bIncremental)
|
|
{
|
|
brcPrev += agelist[i].brPrev[k] * cos(tta);
|
|
brsPrev += agelist[i].brPrev[k] * sin(tta);
|
|
btcPrev += agelist[i].btPrev[k] * cos(tta);
|
|
btsPrev += agelist[i].btPrev[k] * sin(tta);
|
|
}
|
|
}
|
|
|
|
if ((agelist[i].nh[j] == 0) ||
|
|
(((j==(agelist[i].nn-1)) && (agelist[i].BdryFormat==0)) && ((agelist[i].totalArcElements%2)==0)))
|
|
{
|
|
brc /= agelist[i].totalArcElements;
|
|
brs /= agelist[i].totalArcElements;
|
|
btc /= agelist[i].totalArcElements;
|
|
bts /= agelist[i].totalArcElements;
|
|
brcPrev /= agelist[i].totalArcElements;
|
|
brsPrev /= agelist[i].totalArcElements;
|
|
btcPrev /= agelist[i].totalArcElements;
|
|
btsPrev /= agelist[i].totalArcElements;
|
|
}
|
|
else{
|
|
brc /= ((double) agelist[i].totalArcElements)/2.;
|
|
brs /= ((double) agelist[i].totalArcElements)/2.;
|
|
btc /= ((double) agelist[i].totalArcElements)/2.;
|
|
bts /= ((double) agelist[i].totalArcElements)/2.;
|
|
brcPrev /= ((double) agelist[i].totalArcElements)/2.;
|
|
brsPrev /= ((double) agelist[i].totalArcElements)/2.;
|
|
btcPrev /= ((double) agelist[i].totalArcElements)/2.;
|
|
btsPrev /= ((double) agelist[i].totalArcElements)/2.;
|
|
}
|
|
|
|
agelist[i].brc[j]=brc;
|
|
agelist[i].brs[j]=brs;
|
|
agelist[i].btc[j]=btc;
|
|
agelist[i].bts[j]=bts;
|
|
|
|
if (bIncremental)
|
|
{
|
|
agelist[i].brcPrev[j]=brcPrev;
|
|
agelist[i].brsPrev[j]=brsPrev;
|
|
agelist[i].btcPrev[j]=btcPrev;
|
|
agelist[i].btsPrev[j]=btsPrev;
|
|
}
|
|
}
|
|
}
|
|
|
|
// scale depth to meters for internal computations;
|
|
if(Depth==-1) Depth=1; else Depth*=LengthConv[LengthUnits];
|
|
|
|
// element centroids and radii;
|
|
for(i=0;i<meshelem.GetSize();i++)
|
|
{
|
|
meshelem[i].ctr=Ctr(i);
|
|
for(j=0,meshelem[i].rsqr=0;j<3;j++)
|
|
{
|
|
b=sqr(meshnode[meshelem[i].p[j]].x-meshelem[i].ctr.re)+
|
|
sqr(meshnode[meshelem[i].p[j]].y-meshelem[i].ctr.im);
|
|
if(b>meshelem[i].rsqr) meshelem[i].rsqr=b;
|
|
}
|
|
}
|
|
|
|
// Compute magnetization direction in each element
|
|
lua_State *LocalLua = lua_open(4096);
|
|
lua_baselibopen(LocalLua);
|
|
lua_strlibopen(LocalLua);
|
|
lua_mathlibopen(LocalLua);
|
|
for(i=0;i<meshelem.GetSize();i++){
|
|
if(blocklist[meshelem[i].lbl].MagDirFctn.GetLength()==0){
|
|
meshelem[i].magdir=blocklist[meshelem[i].lbl].MagDir;
|
|
}
|
|
else{
|
|
CString str;
|
|
CComplex X;
|
|
X=meshelem[i].ctr;
|
|
str.Format("x=%.17g\ny=%.17g\nr=x\nz=y\ntheta=%.17g\nR=%.17g\nreturn %s",
|
|
X.re,X.im,arg(X)*180/PI,abs(X),blocklist[meshelem[i].lbl].MagDirFctn);
|
|
lua_dostring(LocalLua,str);
|
|
meshelem[i].magdir=Re(lua_tonumber(LocalLua,-1));
|
|
lua_pop(LocalLua, 1);
|
|
}
|
|
}
|
|
lua_close(LocalLua);
|
|
|
|
// Find flux density in each element;
|
|
for(i=0;i<meshelem.GetSize();i++) GetElementB(meshelem[i]);
|
|
|
|
// Find extreme values of A;
|
|
A_Low=meshnode[0].A.re; A_High=meshnode[0].A.re;
|
|
for(i=1;i<meshnode.GetSize();i++)
|
|
{
|
|
if (meshnode[i].A.re>A_High) A_High=meshnode[i].A.re;
|
|
if (meshnode[i].A.re<A_Low) A_Low =meshnode[i].A.re;
|
|
|
|
if(Frequency!=0)
|
|
{
|
|
if (meshnode[i].A.im<A_Low) A_Low =meshnode[i].A.im;
|
|
if (meshnode[i].A.im>A_High) A_High=meshnode[i].A.im;
|
|
}
|
|
}
|
|
// save default values for extremes of A
|
|
A_lb=A_Low;
|
|
A_ub=A_High;
|
|
|
|
if(Frequency!=0){ // compute frequency-dependent permeabilities for linear blocks;
|
|
|
|
CComplex deg45; deg45=1+I;
|
|
CComplex K,halflag;
|
|
double ds;
|
|
double w=2.*PI*Frequency;
|
|
|
|
for(k=0;k<blockproplist.GetSize();k++){
|
|
if (blockproplist[k].LamType==0){
|
|
blockproplist[k].mu_fdx = blockproplist[k].mu_x*
|
|
exp(-I*blockproplist[k].Theta_hx*PI/180.);
|
|
blockproplist[k].mu_fdy = blockproplist[k].mu_y*
|
|
exp(-I*blockproplist[k].Theta_hy*PI/180.);
|
|
|
|
if(blockproplist[k].Lam_d!=0){
|
|
halflag=exp(-I*blockproplist[k].Theta_hx*PI/360.);
|
|
ds=sqrt(2./(0.4*PI*w*blockproplist[k].Cduct*blockproplist[k].mu_x));
|
|
K=halflag*deg45*blockproplist[k].Lam_d*0.001/(2.*ds);
|
|
if (blockproplist[k].Cduct!=0)
|
|
{
|
|
blockproplist[k].mu_fdx=(blockproplist[k].mu_fdx*tanh(K)/K)*
|
|
blockproplist[k].LamFill+(1.-blockproplist[k].LamFill);
|
|
}
|
|
else{
|
|
blockproplist[k].mu_fdx=(blockproplist[k].mu_fdx)*
|
|
blockproplist[k].LamFill+(1.-blockproplist[k].LamFill);
|
|
}
|
|
|
|
halflag=exp(-I*blockproplist[k].Theta_hy*PI/360.);
|
|
ds=sqrt(2./(0.4*PI*w*blockproplist[k].Cduct*blockproplist[k].mu_y));
|
|
K=halflag*deg45*blockproplist[k].Lam_d*0.001/(2.*ds);
|
|
if (blockproplist[k].Cduct!=0)
|
|
{
|
|
blockproplist[k].mu_fdy=(blockproplist[k].mu_fdy*tanh(K)/K)*
|
|
blockproplist[k].LamFill+(1.-blockproplist[k].LamFill);
|
|
}
|
|
else{
|
|
blockproplist[k].mu_fdy=(blockproplist[k].mu_fdy)*
|
|
blockproplist[k].LamFill+(1.-blockproplist[k].LamFill);
|
|
}
|
|
}
|
|
}
|
|
|
|
}}
|
|
|
|
// compute fill factor associated with each block label
|
|
for(k=0;k<blocklist.GetSize();k++)
|
|
{
|
|
GetFillFactor(k);
|
|
}
|
|
|
|
// build list of elements connected to each node;
|
|
// allocate connections list;
|
|
NumList=(int *)calloc(meshnode.GetSize(),sizeof(int));
|
|
ConList=(int **)calloc(meshnode.GetSize(),sizeof(int *));
|
|
// find out number of connections to each node;
|
|
for(i=0;i<meshelem.GetSize();i++)
|
|
for(j=0;j<3;j++)
|
|
NumList[meshelem[i].p[j]]++;
|
|
// allocate space for connections lists;
|
|
for(i=0;i<meshnode.GetSize();i++)
|
|
ConList[i]=(int *)calloc(NumList[i],sizeof(int));
|
|
// build list;
|
|
for(i=0;i<meshnode.GetSize();i++) NumList[i]=0;
|
|
for(i=0;i<meshelem.GetSize();i++)
|
|
for(j=0;j<3;j++){
|
|
k=meshelem[i].p[j];
|
|
ConList[k][NumList[k]]=i;
|
|
NumList[k]++;
|
|
}
|
|
|
|
// find extreme values of J;
|
|
{
|
|
CComplex Jelm[3],Aelm[3];
|
|
|
|
double J_Low, J_High;
|
|
double Jr_Low, Jr_High;
|
|
double Ji_Low, Ji_High;
|
|
|
|
GetJA(0,Jelm,Aelm);
|
|
Jr_Low=fabs(Jelm[0].re);
|
|
Jr_High=Jr_Low;
|
|
Ji_Low=fabs(Jelm[0].im);
|
|
Ji_High=Ji_Low;
|
|
J_Low=abs(Jelm[0]);
|
|
J_High=J_Low;
|
|
for(i=0;i<meshelem.GetSize();i++)
|
|
{
|
|
GetJA(i,Jelm,Aelm);
|
|
for(j=0;j<3;j++){
|
|
br=fabs(Jelm[j].re);
|
|
bi=fabs(Jelm[j].im);
|
|
b=abs(Jelm[j]);
|
|
|
|
if(b>J_High) J_High=b; if(b<J_Low) J_Low=b;
|
|
if(br>Jr_High) Jr_High=br; if(br<Jr_Low) Jr_Low=br;
|
|
if(bi>Ji_High) Ji_High=bi; if(bi<Ji_Low) Ji_Low=bi;
|
|
}
|
|
}
|
|
|
|
J_Low*=1.e-6; J_High*=1e-6;
|
|
Jr_Low*=1.e-6; Jr_High*=1e-6;
|
|
Ji_Low*=1.e-6; Ji_High*=1e-6;
|
|
|
|
if (Frequency==0)
|
|
{
|
|
d_PlotBounds[2][0]=PlotBounds[2][0]=J_Low;
|
|
d_PlotBounds[2][1]=PlotBounds[2][1]=J_High;
|
|
}
|
|
else{
|
|
d_PlotBounds[6][0]=PlotBounds[6][0]=J_Low;
|
|
d_PlotBounds[6][1]=PlotBounds[6][1]=J_High;
|
|
d_PlotBounds[7][0]=PlotBounds[7][0]=Jr_Low;
|
|
d_PlotBounds[7][1]=PlotBounds[7][1]=Jr_High;
|
|
d_PlotBounds[8][0]=PlotBounds[8][0]=Ji_Low;
|
|
d_PlotBounds[8][1]=PlotBounds[8][1]=Ji_High;
|
|
}
|
|
}
|
|
|
|
// Find extreme values of B and H;
|
|
{
|
|
double Br_Low, Br_High;
|
|
double Bi_Low, Bi_High;
|
|
double H_Low;
|
|
double Hr_Low, Hr_High;
|
|
double Hi_Low, Hi_High;
|
|
double a0,a1;
|
|
CComplex h1,h2;
|
|
|
|
// Do a little bit of work to exclude external region from the extreme value calculation
|
|
// Otherwise, flux in the external regions can give a spurious indication of limits
|
|
short *isExt = (short *)calloc(meshelem.GetSize(),sizeof(short));
|
|
CString myBlockName;
|
|
for(i=0;i<meshelem.GetSize();i++)
|
|
{
|
|
if (blocklist[meshelem[i].lbl].IsExternal==TRUE) isExt[i]=TRUE;
|
|
myBlockName=blockproplist[meshelem[i].blk].BlockName;
|
|
if ((myBlockName[0]=='u') && (myBlockName.GetLength()>1))
|
|
{
|
|
for(k=1;k<10;k++)
|
|
{
|
|
if (myBlockName[1]==('0'+k)){
|
|
isExt[i]=TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
for(i=0;i<meshelem.GetSize();i++) if (isExt[i]==FALSE) break;
|
|
if (i==meshelem.GetSize()) i=0;
|
|
|
|
Br_Low=sqrt(sqr(meshelem[i].B1.re) + sqr(meshelem[i].B2.re));
|
|
Br_High=Br_Low;
|
|
Bi_Low=sqrt(sqr(meshelem[i].B1.im)+ sqr(meshelem[i].B2.im));
|
|
Bi_High=Bi_Low;
|
|
B_Low=sqrt(Br_Low*Br_Low + Bi_Low*Bi_Low);
|
|
B_High=B_Low;
|
|
a0=sqrt(meshelem[i].rsqr)*B_High*B_High;
|
|
|
|
if (Frequency!=0)
|
|
GetH(meshelem[i].B1,meshelem[i].B2,h1,h2,0);
|
|
else{
|
|
h1=0;h2=0;
|
|
GetH(meshelem[i].B1.re,meshelem[i].B2.re,h1.re,h2.re,0);
|
|
}
|
|
|
|
Hr_Low=sqrt(sqr(h1.re) + sqr(h2.re));
|
|
Hr_High=Hr_Low;
|
|
Hi_Low=sqrt(sqr(h1.im)+ sqr(h2.im));
|
|
Hi_High=Hi_Low;
|
|
H_Low=sqrt(Hr_Low*Hr_Low + Hi_Low*Hi_Low);
|
|
H_High=H_Low;
|
|
|
|
for(i=0;i<meshelem.GetSize();i++)
|
|
{
|
|
GetNodalB(meshelem[i].b1,meshelem[i].b2,meshelem[i]);
|
|
for(j=0;j<3;j++){
|
|
br=sqrt(sqr(meshelem[i].b1[j].re) +
|
|
sqr(meshelem[i].b2[j].re));
|
|
bi=sqrt(sqr(meshelem[i].b1[j].im) +
|
|
sqr(meshelem[i].b2[j].im));
|
|
b=sqrt(br*br+bi*bi);
|
|
|
|
// used to be: if(b>B_High) B_High=b;
|
|
// new form is a heuristic that discounts really small elements
|
|
// with really high flux density, which sometimes happens in corners.
|
|
a1=sqrt(meshelem[i].rsqr)*b*b;
|
|
if ((a1>a0) && (!isExt[i]))
|
|
{
|
|
B_High=b;
|
|
a0=a1;
|
|
}
|
|
|
|
if (!isExt[i]){
|
|
if(b<B_Low) B_Low=b;
|
|
if(br>Br_High) Br_High=br; if(br<Br_Low) Br_Low=br;
|
|
if(bi>Bi_High) Bi_High=bi; if(bi<Bi_Low) Bi_Low=bi;
|
|
}
|
|
}
|
|
|
|
// getting lazy--just consider element averages for H
|
|
if (Frequency!=0)
|
|
GetH(meshelem[i].B1,meshelem[i].B2,h1,h2,i);
|
|
else
|
|
GetH(meshelem[i].B1.re,meshelem[i].B2.re,h1.re,h2.re,i);
|
|
|
|
if (!isExt[i]){
|
|
br=sqrt(sqr(h1.re) + sqr(h2.re));
|
|
bi=sqrt(sqr(h1.im) + sqr(h2.im));
|
|
b=sqrt(br*br+bi*bi);
|
|
if(b>H_High) H_High=b; if(b<H_Low) H_Low=b;
|
|
if(br>Hr_High) Hr_High=br; if(br<Hr_Low) Hr_Low=br;
|
|
if(bi>Hi_High) Hi_High=bi; if(bi<Hi_Low) Hi_Low=bi;
|
|
}
|
|
|
|
}
|
|
free(isExt);
|
|
|
|
if (Frequency==0)
|
|
{
|
|
d_PlotBounds[0][0]=PlotBounds[0][0]=B_Low;
|
|
d_PlotBounds[0][1]=PlotBounds[0][1]=B_High;
|
|
d_PlotBounds[1][0]=PlotBounds[1][0]=H_Low;
|
|
d_PlotBounds[1][1]=PlotBounds[1][1]=H_High;
|
|
}
|
|
else{
|
|
d_PlotBounds[0][0]=PlotBounds[0][0]=B_Low;
|
|
d_PlotBounds[0][1]=PlotBounds[0][1]=B_High;
|
|
d_PlotBounds[1][0]=PlotBounds[1][0]=Br_Low;
|
|
d_PlotBounds[1][1]=PlotBounds[1][1]=Br_High;
|
|
d_PlotBounds[2][0]=PlotBounds[2][0]=Bi_Low;
|
|
d_PlotBounds[2][1]=PlotBounds[2][1]=Bi_High;
|
|
d_PlotBounds[3][0]=PlotBounds[3][0]=H_Low;
|
|
d_PlotBounds[3][1]=PlotBounds[3][1]=H_High;
|
|
d_PlotBounds[4][0]=PlotBounds[4][0]=Hr_Low;
|
|
d_PlotBounds[4][1]=PlotBounds[4][1]=Hr_High;
|
|
d_PlotBounds[5][0]=PlotBounds[5][0]=Hi_Low;
|
|
d_PlotBounds[5][1]=PlotBounds[5][1]=Hi_High;
|
|
}
|
|
}
|
|
|
|
// Choose bounds based on the type of contour plot
|
|
// currently in play
|
|
POSITION pos = GetFirstViewPosition();
|
|
CFemmviewView *theView=(CFemmviewView *)GetNextView(pos);
|
|
|
|
if(Frequency==0)
|
|
{
|
|
if (theView->DensityPlot==2) theView->DensityPlot=1;
|
|
if (theView->DensityPlot>1) theView->DensityPlot=0;
|
|
}
|
|
|
|
// compute total resulting current for circuits with an a priori defined
|
|
// voltage gradient; Need this to display circuit results & impedance.
|
|
for(i=0;i<circproplist.GetSize();i++)
|
|
{
|
|
CComplex Jelm[3],Aelm[3];
|
|
double a;
|
|
|
|
if(circproplist[i].CircType>1)
|
|
for(j=0,circproplist[i].Amps=0.;j<meshelem.GetSize();j++)
|
|
{
|
|
if(blocklist[meshelem[j].lbl].InCircuit==i)
|
|
{
|
|
GetJA(j,Jelm,Aelm);
|
|
a=ElmArea(j)*sqr(LengthConv[LengthUnits]);
|
|
for(k=0;k<3;k++) circproplist[i].Amps+=a*Jelm[k]/3;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Build adjacency information for each element.
|
|
FindBoundaryEdges();
|
|
|
|
// Check to see if any regions are multiply defined
|
|
// (i.e. tagged by more than one block label). If so,
|
|
// display an error message and mark the problem blocks.
|
|
for(k=0,bMultiplyDefinedLabels=FALSE;k<blocklist.GetSize();k++)
|
|
{
|
|
if((i=InTriangle(blocklist[k].x,blocklist[k].y))>=0)
|
|
{
|
|
if(meshelem[i].lbl!=k)
|
|
{
|
|
blocklist[meshelem[i].lbl].IsSelected=TRUE;
|
|
if (!bMultiplyDefinedLabels)
|
|
{
|
|
CString msg;
|
|
msg ="Some regions in the problem have been defined\n";
|
|
msg+="by more than one block label. These potentially\n";
|
|
msg+="problematic regions will appear as selected in\n";
|
|
msg+="the initial view.";
|
|
MsgBox(msg);
|
|
bMultiplyDefinedLabels=TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Get some information needed to compute energy stored in
|
|
// permanent magnets with a nonlinear demagnetization curve
|
|
if (Frequency==0)
|
|
{
|
|
for(k=0;k<blockproplist.GetSize();k++)
|
|
{
|
|
if ((blockproplist[k].H_c>0) && (blockproplist[k].BHpoints>0))
|
|
{
|
|
blockproplist[k].Nrg = blockproplist[k].GetCoEnergy(blockproplist[k].GetB(blockproplist[k].H_c));
|
|
}
|
|
}
|
|
}
|
|
|
|
FirstDraw=TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
int CFemmviewDoc::InTriangle(double x, double y)
|
|
{
|
|
static int k;
|
|
int j,hi,lo,sz;
|
|
double z;
|
|
|
|
sz=(int) meshelem.GetSize();
|
|
if((k<0) || (k>=sz)) k=0;
|
|
|
|
// In most applications, the triangle we're looking
|
|
// for is nearby the last one we found. Since the elements
|
|
// are ordered in a banded structure, we want to check the
|
|
// elements nearby the last one selected first.
|
|
if (InTriangleTest(x,y,k)) return k;
|
|
|
|
hi=k;lo=k;
|
|
|
|
for(j=0;j<sz;j+=2)
|
|
{
|
|
hi++; if(hi>=sz) hi=0;
|
|
lo--; if(lo<0) lo=sz-1;
|
|
|
|
z=(meshelem[hi].ctr.re-x)*(meshelem[hi].ctr.re-x) +
|
|
(meshelem[hi].ctr.im-y)*(meshelem[hi].ctr.im-y);
|
|
if(z<=meshelem[hi].rsqr)
|
|
{
|
|
if(InTriangleTest(x,y,hi))
|
|
{
|
|
k=hi;
|
|
return k;
|
|
}
|
|
}
|
|
|
|
z=(meshelem[lo].ctr.re-x)*(meshelem[lo].ctr.re-x) +
|
|
(meshelem[lo].ctr.im-y)*(meshelem[lo].ctr.im-y);
|
|
if(z<=meshelem[lo].rsqr)
|
|
{
|
|
if(InTriangleTest(x,y,lo))
|
|
{
|
|
k=lo;
|
|
return k;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return (-1);
|
|
}
|
|
|
|
BOOL CFemmviewDoc::GetPointValues(double x, double y, CPointVals &u)
|
|
{
|
|
int k;
|
|
k=InTriangle(x,y);
|
|
if (k<0) return FALSE;
|
|
GetPointValues(x,y,k,u);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CFemmviewDoc::GetPointValues(double x, double y, int k, CPointVals &u)
|
|
{
|
|
int i,j,n[3],lbl;
|
|
double a[3],b[3],c[3],da,ravg;
|
|
|
|
for(i=0;i<3;i++) n[i]=meshelem[k].p[i];
|
|
a[0]=meshnode[n[1]].x * meshnode[n[2]].y - meshnode[n[2]].x * meshnode[n[1]].y;
|
|
a[1]=meshnode[n[2]].x * meshnode[n[0]].y - meshnode[n[0]].x * meshnode[n[2]].y;
|
|
a[2]=meshnode[n[0]].x * meshnode[n[1]].y - meshnode[n[1]].x * meshnode[n[0]].y;
|
|
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]);
|
|
ravg=LengthConv[LengthUnits]*
|
|
(meshnode[n[0]].x + meshnode[n[1]].x + meshnode[n[2]].x)/3.;
|
|
|
|
GetPointB(x,y,u.B1,u.B2,meshelem[k]);
|
|
|
|
u.Hc=0;
|
|
u.mu12=0;
|
|
|
|
// if(blockproplist[meshelem[k].blk].LamType>2)
|
|
u.ff=blocklist[meshelem[k].lbl].FillFactor;
|
|
// else u.ff=-1;
|
|
|
|
if (Frequency==0){
|
|
u.A=0;
|
|
if(ProblemType==0){
|
|
for(i=0;i<3;i++)
|
|
u.A.re+=meshnode[n[i]].A.re*(a[i]+b[i]*x+c[i]*y)/(da);
|
|
}
|
|
else{
|
|
/* Old way that I interpolated potential in axi case:
|
|
// interpolation from A from nodal points.
|
|
// note that the potential that's actually stored
|
|
// for axisymmetric problems is 2*Pi*r*A, so divide
|
|
// by nodal r to get 2*Pi*A at the nodes. Linearly
|
|
// interpolate this, then multiply by r at the point
|
|
// of interest to get back to 2*Pi*r*A.
|
|
for(i=0,rp=0;i<3;i++){
|
|
r=meshnode[n[i]].x;
|
|
rp+=meshnode[n[i]].x*(a[i]+b[i]*x+c[i]*y)/da;
|
|
if (r>1.e-6) u.A.re+=meshnode[n[i]].A.re*
|
|
(a[i]+b[i]*x+c[i]*y)/(r*da);
|
|
}
|
|
u.A.re*=rp;
|
|
*/
|
|
|
|
|
|
// a ``smarter'' interpolation. One based on A can't
|
|
// represent constant flux density very well.
|
|
// This works, but I should re-write it in a more
|
|
// efficient form--it's doing a lot of the work
|
|
// twice, because the a-b-c stuff that's already
|
|
// been computed is ignored.
|
|
double v[6];
|
|
double R[3];
|
|
double Z[3];
|
|
double p,q;
|
|
|
|
for(i=0;i<3;i++){
|
|
R[i]=meshnode[n[i]].x;
|
|
Z[i]=meshnode[n[i]].y;
|
|
}
|
|
|
|
// corner nodes
|
|
v[0]=meshnode[n[0]].A.re;
|
|
v[2]=meshnode[n[1]].A.re;
|
|
v[4]=meshnode[n[2]].A.re;
|
|
|
|
// construct values for mid-side nodes;
|
|
if ((R[0]<1.e-06) && (R[1]<1.e-06))
|
|
v[1]=(v[0]+v[2])/2.;
|
|
else
|
|
v[1]=(R[1]*(3.*v[0] + v[2]) + R[0]*(v[0] + 3.*v[2]))/
|
|
(4.*(R[0] + R[1]));
|
|
|
|
if ((R[1]<1.e-06) && (R[2]<1.e-06))
|
|
v[3]=(v[2]+v[4])/2.;
|
|
else
|
|
v[3]=(R[2]*(3.*v[2] + v[4]) + R[1]*(v[2] + 3.*v[4]))/
|
|
(4.*(R[1] + R[2]));
|
|
|
|
if ((R[2]<1.e-06) && (R[0]<1.e-06))
|
|
v[5]=(v[4]+v[0])/2.;
|
|
else
|
|
v[5]=(R[0]*(3.*v[4] + v[0]) + R[2]*(v[4] + 3.*v[0]))/
|
|
(4.*(R[2] + R[0]));
|
|
|
|
// compute location in element transformed onto
|
|
// a unit triangle;
|
|
p=(b[1]*x+c[1]*y + a[1])/da;
|
|
q=(b[2]*x+c[2]*y + a[2])/da;
|
|
|
|
// now, interpolate to get potential...
|
|
u.A.re = v[0] - p*(3.*v[0] - 4.*v[1] + v[2]) +
|
|
2.*p*p*(v[0] - 2.*v[1] + v[2]) -
|
|
q*(3.*v[0] + v[4] - 4.*v[5]) +
|
|
2.*q*q*(v[0] + v[4] - 2.*v[5]) +
|
|
4.*p*q*(v[0] - v[1] + v[3] - v[5]);
|
|
|
|
/* // "simple" way to do it...
|
|
// problem is that this mucks up things
|
|
// near the centerline, where things ought
|
|
// to look pretty quadratic.
|
|
for(i=0;i<3;i++)
|
|
u.A.re+=meshnode[n[i]].A.re*(a[i]+b[i]*x+c[i]*y)/(da);
|
|
*/
|
|
}
|
|
|
|
// Need to catch bIncremental case here...
|
|
u.mu1.im = 0; u.mu2.im = 0; u.mu12 = 0;
|
|
if (!bIncremental) {
|
|
GetMu(u.B1.re, u.B2.re, u.mu1.re, u.mu2.re, k);
|
|
u.H1 = u.B1 / (Re(u.mu1)*muo);
|
|
u.H2 = u.B2 / (Re(u.mu2)*muo);
|
|
}
|
|
else {
|
|
double muinc, murel;
|
|
double B, B1p, B2p;
|
|
|
|
B1p = meshelem[k].B1p;
|
|
B2p = meshelem[k].B2p;
|
|
B = sqrt(B1p*B1p + B2p*B2p);
|
|
|
|
GetMu(B1p, B2p, muinc, murel, k);
|
|
if (B == 0)
|
|
{
|
|
// Catch the special case where B=0 to avoid a possible divide by zero
|
|
u.mu1 = muinc;
|
|
u.mu2 = muinc;
|
|
u.mu12 = 0;
|
|
}
|
|
else if(bIncremental==1)
|
|
{
|
|
// For "incremental" problem, permeability is linearized about the prevous soluiton.
|
|
u.mu1 = (B1p*B1p*muinc + B2p*B2p*murel) / (B*B);
|
|
u.mu12 = (B1p*B2p*(muinc - murel)) / (B*B);
|
|
u.mu2 = (B2p*B2p*muinc + B1p*B1p*murel) / (B*B);
|
|
}
|
|
else { //bIncremental==2
|
|
// For "frozen" permeability, same permeability as previous problem
|
|
u.mu1 = murel;
|
|
u.mu2 = murel;
|
|
u.mu12 = 0;
|
|
}
|
|
|
|
u.H1 = (u.B2*u.mu12 - u.B1*u.mu2) / (u.mu12*u.mu12 - u.mu1*u.mu2);
|
|
u.H2 = (u.B2*u.mu1 - u.B1*u.mu12) / (u.mu1*u.mu2 - u.mu12*u.mu12);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
u.Je=0;
|
|
u.Js=blockproplist[meshelem[k].blk].Jr;
|
|
lbl=meshelem[k].lbl;
|
|
j=blocklist[lbl].InCircuit;
|
|
if(j>=0){
|
|
if(blocklist[lbl].Case==0){
|
|
if (ProblemType==0)
|
|
u.Js-=Re(blocklist[meshelem[k].lbl].o)*
|
|
blocklist[lbl].dVolts;
|
|
else{
|
|
|
|
int tn;
|
|
double R[3];
|
|
for(tn=0;tn<3;tn++)
|
|
{
|
|
R[tn]=meshnode[n[tn]].x;
|
|
if (R[tn]<1.e-6) R[tn]=ravg;
|
|
else R[tn]*=LengthConv[LengthUnits];
|
|
}
|
|
for(ravg=0.,tn=0;tn<3;tn++)
|
|
ravg+=(1./R[tn])*(a[tn]+b[tn]*x+c[tn]*y)/(da);
|
|
u.Js-=Re(blocklist[meshelem[k].lbl].o)*
|
|
blocklist[lbl].dVolts*ravg;
|
|
}
|
|
}
|
|
else u.Js+=blocklist[lbl].J;
|
|
}
|
|
u.c=Re(blocklist[meshelem[k].lbl].o);
|
|
u.E=blockproplist[meshelem[k].blk].DoEnergy(u.B1.re,u.B2.re);
|
|
|
|
// correct H and energy stored in magnet for second-quadrant
|
|
// representation of a PM.
|
|
if (blockproplist[meshelem[k].blk].H_c!=0)
|
|
{
|
|
int bk=meshelem[k].blk;
|
|
|
|
u.Hc = blockproplist[bk].H_c*exp(I*PI*meshelem[k].magdir/180.);
|
|
u.H1=u.H1-Re(u.Hc);
|
|
u.H2=u.H2-Im(u.Hc);
|
|
|
|
// in the linear case:
|
|
if (blockproplist[bk].BHpoints==0)
|
|
u.E = 0.5*muo*(u.mu1.re*u.H1.re*u.H1.re + u.mu2.re*u.H2.re*u.H2.re);
|
|
else{
|
|
u.E = u.E + blockproplist[bk].Nrg
|
|
- blockproplist[bk].H_c*Re((u.B1.re+I*u.B2.re)/exp(I*PI*meshelem[k].magdir/180.));
|
|
}
|
|
|
|
// If considering the magnet as an equivalent coil, add Hc to the demagnetizing field
|
|
if (!d_ShiftH)
|
|
{
|
|
u.H1=u.H1+Re(u.Hc);
|
|
u.H2=u.H2+Im(u.Hc);
|
|
u.Hc=0;
|
|
}
|
|
}
|
|
|
|
// add in "local" stored energy for wound that would be subject to
|
|
// prox and skin effect for nonzero frequency cases.
|
|
if (blockproplist[meshelem[k].blk].LamType>2)
|
|
{
|
|
CComplex J;
|
|
J=u.Js*1.e6;
|
|
|
|
u.E+=Re(J*J)*blocklist[meshelem[i].lbl].LocalEnergy/2.;
|
|
}
|
|
|
|
u.Ph=0;
|
|
u.Pe=0;
|
|
return TRUE;
|
|
}
|
|
|
|
if(Frequency!=0){
|
|
u.A=0;
|
|
if(ProblemType==0)
|
|
{
|
|
for(i=0;i<3;i++)
|
|
u.A+=meshnode[n[i]].A*(a[i]+b[i]*x+c[i]*y)/(da);
|
|
}
|
|
else{
|
|
CComplex v[6];
|
|
double R[3];
|
|
double Z[3];
|
|
double p,q;
|
|
|
|
for(i=0;i<3;i++){
|
|
R[i]=meshnode[n[i]].x;
|
|
Z[i]=meshnode[n[i]].y;
|
|
}
|
|
|
|
// corner nodes
|
|
v[0]=meshnode[n[0]].A;
|
|
v[2]=meshnode[n[1]].A;
|
|
v[4]=meshnode[n[2]].A;
|
|
|
|
// construct values for mid-side nodes;
|
|
if ((R[0]<1.e-06) && (R[1]<1.e-06))
|
|
v[1]=(v[0]+v[2])/2.;
|
|
else
|
|
v[1]=(R[1]*(3.*v[0] + v[2]) + R[0]*(v[0] + 3.*v[2]))/
|
|
(4.*(R[0] + R[1]));
|
|
|
|
if ((R[1]<1.e-06) && (R[2]<1.e-06))
|
|
v[3]=(v[2]+v[4])/2.;
|
|
else
|
|
v[3]=(R[2]*(3.*v[2] + v[4]) + R[1]*(v[2] + 3.*v[4]))/
|
|
(4.*(R[1] + R[2]));
|
|
|
|
if ((R[2]<1.e-06) && (R[0]<1.e-06))
|
|
v[5]=(v[4]+v[0])/2.;
|
|
else
|
|
v[5]=(R[0]*(3.*v[4] + v[0]) + R[2]*(v[4] + 3.*v[0]))/
|
|
(4.*(R[2] + R[0]));
|
|
|
|
// compute location in element transformed onto
|
|
// a unit triangle;
|
|
p=(b[1]*x+c[1]*y + a[1])/da;
|
|
q=(b[2]*x+c[2]*y + a[2])/da;
|
|
|
|
// now, interpolate to get potential...
|
|
u.A = v[0] - p*(3.*v[0] - 4.*v[1] + v[2]) +
|
|
2.*p*p*(v[0] - 2.*v[1] + v[2]) -
|
|
q*(3.*v[0] + v[4] - 4.*v[5]) +
|
|
2.*q*q*(v[0] + v[4] - 2.*v[5]) +
|
|
4.*p*q*(v[0] - v[1] + v[3] - v[5]);
|
|
}
|
|
|
|
// if bIncremental, need to get permeability about the DC
|
|
// operating point, rather than usual DC permeability.
|
|
if (!bIncremental){
|
|
GetMu(u.B1,u.B2,u.mu1,u.mu2,k);
|
|
u.mu12=0;
|
|
u.H1 = u.B1/(u.mu1*muo);
|
|
u.H2 = u.B2/(u.mu2*muo);
|
|
}
|
|
else{
|
|
CComplex muinc,murel;
|
|
double B,B1p,B2p;
|
|
|
|
B1p=meshelem[k].B1p;
|
|
B2p=meshelem[k].B2p;
|
|
B=sqrt(B1p*B1p + B2p*B2p);
|
|
|
|
GetMu(B1p,B2p,muinc,murel,k);
|
|
if (B==0)
|
|
{
|
|
u.mu1=murel;
|
|
u.mu2=murel;
|
|
u.mu12 = 0;
|
|
}
|
|
else{
|
|
u.mu1 = (B1p*B1p*muinc + B2p*B2p*murel)/(B*B);
|
|
u.mu12 = (B1p*B2p*(muinc - murel))/(B*B);
|
|
u.mu2 = (B2p*B2p*muinc + B1p*B1p*murel)/(B*B);
|
|
}
|
|
|
|
u.H1 = (u.B2*u.mu12 - u.B1*u.mu2)/(u.mu12*u.mu12 - u.mu1*u.mu2);
|
|
u.H2 = (u.B2*u.mu1 - u.B1*u.mu12)/(u.mu1*u.mu2 - u.mu12*u.mu12);
|
|
}
|
|
|
|
u.Js=blockproplist[meshelem[k].blk].Jr +
|
|
I*blockproplist[meshelem[k].blk].Ji;
|
|
lbl=meshelem[k].lbl;
|
|
j=blocklist[lbl].InCircuit;
|
|
if(j>=0){
|
|
if(blocklist[lbl].Case==0){
|
|
if (ProblemType==0)
|
|
u.Js-=blocklist[meshelem[k].lbl].o*blocklist[lbl].dVolts;
|
|
else
|
|
{
|
|
|
|
int tn;
|
|
double R[3];
|
|
for(tn=0;tn<3;tn++)
|
|
{
|
|
R[tn]=meshnode[n[tn]].x;
|
|
if (R[tn]<1.e-6) R[tn]=ravg;
|
|
else R[tn]*=LengthConv[LengthUnits];
|
|
}
|
|
for(ravg=0.,tn=0;tn<3;tn++)
|
|
ravg+=(1./R[tn])*(a[tn]+b[tn]*x+c[tn]*y)/(da);
|
|
u.Js-=blocklist[meshelem[k].lbl].o*
|
|
blocklist[lbl].dVolts*ravg;
|
|
}
|
|
}
|
|
else u.Js+=blocklist[lbl].J;
|
|
}
|
|
|
|
// report just loss-related part of conductivity.
|
|
if (blockproplist[meshelem[k].blk].Cduct!=0)
|
|
u.c=1./Re(1./(blocklist[meshelem[k].lbl].o));
|
|
else u.c=0;
|
|
|
|
if (blockproplist[meshelem[k].blk].Lam_d!=0) u.c=0;
|
|
|
|
// only add in eddy currents if the region is solid
|
|
if (blocklist[meshelem[k].lbl].FillFactor<0)
|
|
u.Je=-I*Frequency*2.*PI*u.c*u.A;
|
|
|
|
if(ProblemType!=0){
|
|
if(x!=0)
|
|
u.Je/=(2.*PI*x*LengthConv[LengthUnits]);
|
|
else u.Je=0;
|
|
}
|
|
|
|
CComplex z;
|
|
z=(u.H1*u.B1.Conj()) + (u.H2*u.B2.Conj());
|
|
u.E=0.25*z.re;
|
|
|
|
// add in "local" stored energy for wound that would be subject to
|
|
// prox and skin effect for nonzero frequency cases.
|
|
if (blockproplist[meshelem[k].blk].LamType>2)
|
|
{
|
|
CComplex J;
|
|
J=u.Js*1.e6;
|
|
u.E += Re(J*conj(J))*blocklist[meshelem[k].lbl].LocalEnergy/4.;
|
|
}
|
|
|
|
u.Ph=Frequency*PI*z.im;
|
|
u.Pe=0;
|
|
if (u.c!=0)
|
|
{
|
|
z=u.Js + u.Je;
|
|
u.Pe=1.e06*(z.re*z.re + z.im*z.im)/(u.c*2.);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void CFemmviewDoc::GetPointB(double x, double y, CComplex &B1, CComplex &B2,
|
|
CElement &elm)
|
|
{
|
|
// elm is a reference to the element that contains the point of interest.
|
|
int i,n[3];
|
|
double da,a[3],b[3],c[3];
|
|
|
|
if(Smooth==FALSE){
|
|
B1=elm.B1;
|
|
B2=elm.B2;
|
|
return;
|
|
}
|
|
|
|
for(i=0;i<3;i++) n[i]=elm.p[i];
|
|
a[0]=meshnode[n[1]].x * meshnode[n[2]].y - meshnode[n[2]].x * meshnode[n[1]].y;
|
|
a[1]=meshnode[n[2]].x * meshnode[n[0]].y - meshnode[n[0]].x * meshnode[n[2]].y;
|
|
a[2]=meshnode[n[0]].x * meshnode[n[1]].y - meshnode[n[1]].x * meshnode[n[0]].y;
|
|
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]);
|
|
|
|
B1.Set(0,0);
|
|
B2.Set(0,0);
|
|
for(i=0;i<3;i++){
|
|
B1+=(elm.b1[i]*(a[i]+b[i]*x+c[i]*y)/da);
|
|
B2+=(elm.b2[i]*(a[i]+b[i]*x+c[i]*y)/da);
|
|
}
|
|
}
|
|
|
|
void CFemmviewDoc::GetNodalB(CComplex *b1, CComplex *b2,CElement &elm)
|
|
{
|
|
// elm is a reference to the element that contains the point of interest.
|
|
CComplex p;
|
|
CComplex tn,bn,bt,btu,btv,u1,u2,v1,v2;
|
|
int i,j,k,l,q,m,pt,nxt;
|
|
double r,R,z;
|
|
CElement *e;
|
|
int flag;
|
|
|
|
// find nodal values of flux density via a patch method.
|
|
for(i=0;i<3;i++){
|
|
|
|
k=elm.p[i];
|
|
p.Set(meshnode[k].x,meshnode[k].y);
|
|
b1[i].Set(0,0);
|
|
b2[i].Set(0,0);
|
|
for(j=0,m=0;j<NumList[k];j++)
|
|
if(elm.lbl==meshelem[ConList[k][j]].lbl) m++;
|
|
else{
|
|
if(Frequency==0){
|
|
if ((blockproplist[elm.blk].mu_x==
|
|
blockproplist[meshelem[ConList[k][j]].blk].mu_x) &&
|
|
(blockproplist[elm.blk].mu_y==
|
|
blockproplist[meshelem[ConList[k][j]].blk].mu_y) &&
|
|
(blockproplist[elm.blk].H_c==
|
|
blockproplist[meshelem[ConList[k][j]].blk].H_c) &&
|
|
(elm.magdir==meshelem[ConList[k][j]].magdir)) m++;
|
|
else if ((elm.blk==meshelem[ConList[k][j]].blk) &&
|
|
(elm.magdir==meshelem[ConList[k][j]].magdir)) m++;
|
|
}
|
|
else if ((blockproplist[elm.blk].mu_fdx==
|
|
blockproplist[meshelem[ConList[k][j]].blk].mu_fdx) &&
|
|
(blockproplist[elm.blk].mu_fdy==
|
|
blockproplist[meshelem[ConList[k][j]].blk].mu_fdy)) m++;
|
|
}
|
|
|
|
if(m==NumList[k]) // normal smoothing method for points
|
|
{ // away from any boundaries
|
|
for(j=0,R=0;j<NumList[k];j++)
|
|
{
|
|
m=ConList[k][j];
|
|
z=1./abs(p-Ctr(m));
|
|
R+=z;
|
|
b1[i]+=(z*meshelem[m].B1);
|
|
b2[i]+=(z*meshelem[m].B2);
|
|
}
|
|
b1[i]/=R;
|
|
b2[i]/=R;
|
|
}
|
|
|
|
else{
|
|
R=0; v1=0; v2=0;
|
|
|
|
//scan ccw for an interface...
|
|
e=&elm;
|
|
for(q=0;q<NumList[k];q++)
|
|
{
|
|
//find ccw side of the element;
|
|
for(j=0;j<3;j++) if(e->p[j]==k) pt=j;
|
|
pt--;
|
|
if(pt<0) pt=2;
|
|
pt=e->p[pt];
|
|
|
|
//scan to find element adjacent to this side;
|
|
for(j=0,nxt=-1;j<NumList[k];j++){
|
|
if(&meshelem[ConList[k][j]]!=e){
|
|
for(l=0;l<3;l++)
|
|
if(meshelem[ConList[k][j]].p[l]==pt)
|
|
nxt=ConList[k][j];
|
|
}
|
|
}
|
|
|
|
if(nxt==-1){
|
|
// a special-case punt
|
|
q=NumList[k];
|
|
b1[i]=(e->B1);
|
|
b2[i]=(e->B2);
|
|
v1=1;v2=1;
|
|
}
|
|
else if(elm.lbl!=meshelem[nxt].lbl){
|
|
// we have found two elements on either side of the interface
|
|
// now, we take contribution from B at the center of the
|
|
// interface side
|
|
tn.Set(meshnode[pt].x-meshnode[k].x,
|
|
meshnode[pt].y-meshnode[k].y);
|
|
r=(meshnode[pt].x+meshnode[k].x)*LengthConv[LengthUnits]/2.;
|
|
bn=(meshnode[pt].A-meshnode[k].A)/
|
|
(abs(tn)*LengthConv[LengthUnits]);
|
|
if(ProblemType==1){
|
|
bn/=(-2.*PI*r);
|
|
}
|
|
z=0.5/abs(tn);
|
|
tn/=abs(tn);
|
|
|
|
// for the moment, kludge with bt...
|
|
bt=e->B1*tn.re + e->B2*tn.im;
|
|
|
|
R+=z;
|
|
b1[i]+=(z*tn.re*bt);
|
|
b2[i]+=(z*tn.im*bt);
|
|
b1[i]+=(z*tn.im*bn);
|
|
b2[i]+=(-z*tn.re*bn);
|
|
v1=tn;
|
|
q=NumList[k];
|
|
}
|
|
else e=&meshelem[nxt];
|
|
}
|
|
|
|
//scan cw for an interface...
|
|
if(v2==0) // catches the "special-case punt" where we have
|
|
{ // already set nodal B values....
|
|
e=&elm;
|
|
for(q=0;q<NumList[k];q++)
|
|
{
|
|
//find cw side of the element;
|
|
for(j=0;j<3;j++) if(e->p[j]==k) pt=j;
|
|
pt++;
|
|
if(pt>2) pt=0;
|
|
pt=e->p[pt];
|
|
|
|
//scan to find element adjacent to this side;
|
|
for(j=0,nxt=-1;j<NumList[k];j++){
|
|
if(&meshelem[ConList[k][j]]!=e){
|
|
for(l=0;l<3;l++)
|
|
if(meshelem[ConList[k][j]].p[l]==pt)
|
|
nxt=ConList[k][j];
|
|
}
|
|
}
|
|
if (nxt==-1){
|
|
// a special-case punt
|
|
q=NumList[k];
|
|
b1[i]=(e->B1);
|
|
b2[i]=(e->B2);
|
|
v1=1;v2=1;
|
|
}
|
|
else if(elm.lbl!=meshelem[nxt].lbl){
|
|
// we have found two elements on either side of the interface
|
|
// now, we take contribution from B at the center of the
|
|
// interface side
|
|
tn.Set(meshnode[pt].x-meshnode[k].x,
|
|
meshnode[pt].y-meshnode[k].y);
|
|
r=(meshnode[pt].x+meshnode[k].x)*LengthConv[LengthUnits]/2.;
|
|
bn=(meshnode[pt].A-meshnode[k].A)/
|
|
(abs(tn)*LengthConv[LengthUnits]);
|
|
if(ProblemType==1){
|
|
bn/=(-2.*PI*r);
|
|
}
|
|
z=0.5/abs(tn);
|
|
tn/=abs(tn);
|
|
|
|
// for the moment, kludge with bt...
|
|
bt=e->B1*tn.re + e->B2*tn.im;
|
|
|
|
R+=z;
|
|
b1[i]+=(z*tn.re*bt);
|
|
b2[i]+=(z*tn.im*bt);
|
|
b1[i]+=(z*tn.im*bn);
|
|
b2[i]+=(-z*tn.re*bn);
|
|
v2=tn;
|
|
q=NumList[k];
|
|
}
|
|
else e=&meshelem[nxt];
|
|
}
|
|
b1[i]/=R;
|
|
b2[i]/=R;
|
|
}
|
|
|
|
// check to see if angle of corner is too sharp to apply
|
|
// this rule; really only does right if the interface is flat;
|
|
flag=FALSE;
|
|
// if there is only one edge, approx is ok;
|
|
if ((abs(v1)<0.9) || (abs(v2)<0.9)) flag=TRUE;
|
|
// if the interfaces make less than a 10 degree angle, things are ok;
|
|
if ( (-v1.re*v2.re-v1.im*v2.im) > 0.985) flag=TRUE;
|
|
|
|
// Otherwise, punt...
|
|
if(flag==FALSE){
|
|
bn=0;
|
|
k=elm.p[i];
|
|
for(j=0;j<NumList[k];j++)
|
|
{
|
|
if(elm.lbl==meshelem[ConList[k][j]].lbl){
|
|
m=ConList[k][j];
|
|
bt.re=sqrt(meshelem[m].B1.re*meshelem[m].B1.re +
|
|
meshelem[m].B2.re*meshelem[m].B2.re);
|
|
bt.im=sqrt(meshelem[m].B1.im*meshelem[m].B1.im +
|
|
meshelem[m].B2.im*meshelem[m].B2.im);
|
|
if(bt.re>bn.re) bn.re=bt.re;
|
|
if(bt.im>bn.im) bn.im=bt.im;
|
|
}
|
|
}
|
|
|
|
R=sqrt(elm.B1.re*elm.B1.re + elm.B2.re*elm.B2.re);
|
|
if(R!=0)
|
|
{
|
|
b1[i].re=bn.re/R * elm.B1.re;
|
|
b2[i].re=bn.re/R * elm.B2.re;
|
|
}
|
|
else{
|
|
b1[i].re=0;
|
|
b2[i].re=0;
|
|
}
|
|
|
|
R=sqrt(elm.B1.im*elm.B1.im + elm.B2.im*elm.B2.im);
|
|
if(R!=0)
|
|
{
|
|
b1[i].im=bn.im/R * elm.B1.im;
|
|
b2[i].im=bn.im/R * elm.B2.im;
|
|
}
|
|
else{
|
|
b1[i].im=0;
|
|
b2[i].im=0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// check to see if the point has a point current; if so, just
|
|
// use element average values;
|
|
if (nodeproplist.GetSize()!=0)
|
|
for(j=0;j<nodelist.GetSize();j++)
|
|
{
|
|
if (abs(p-(nodelist[j].x+nodelist[j].y*I))<1.e-08)
|
|
if(nodelist[j].BoundaryMarker>=0)
|
|
{
|
|
if ((nodeproplist[nodelist[j].BoundaryMarker].Jr!=0) ||
|
|
(nodeproplist[nodelist[j].BoundaryMarker].Ji!=0))
|
|
{
|
|
b1[i]=elm.B1;
|
|
b2[i]=elm.B2;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//check for special case of node on r=0 axisymmetric; set Br=0;
|
|
if ((fabs(p.re)<1.e-06) && (ProblemType==1)) b1[i].Set(0.,0);
|
|
}
|
|
}
|
|
|
|
void CFemmviewDoc::GetElementB(CElement &elm)
|
|
{
|
|
int i,n[3];
|
|
double b[3],c[3],da;
|
|
|
|
for(i=0;i<3;i++) n[i]=elm.p[i];
|
|
|
|
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]);
|
|
|
|
if (ProblemType==0){
|
|
elm.B1=0;
|
|
elm.B2=0;
|
|
elm.B1p=0;
|
|
elm.B2p=0;
|
|
for(i=0;i<3;i++)
|
|
{
|
|
elm.B1+=meshnode[n[i]].A*c[i]/(da*LengthConv[LengthUnits]);
|
|
elm.B2-=meshnode[n[i]].A*b[i]/(da*LengthConv[LengthUnits]);
|
|
}
|
|
|
|
if (bIncremental)
|
|
{
|
|
for(i=0;i<3;i++)
|
|
{
|
|
elm.B1p+=meshnode[n[i]].Aprev*c[i]/(da*LengthConv[LengthUnits]);
|
|
elm.B2p-=meshnode[n[i]].Aprev*b[i]/(da*LengthConv[LengthUnits]);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
else{
|
|
CComplex v[6],dp,dq;
|
|
double R[3],Z[3],r;
|
|
|
|
for(i=0,r=0;i<3;i++){
|
|
R[i]=meshnode[n[i]].x;
|
|
Z[i]=meshnode[n[i]].y;
|
|
r+=R[i]/3.;
|
|
}
|
|
|
|
// corner nodes
|
|
v[0]=meshnode[n[0]].A;
|
|
v[2]=meshnode[n[1]].A;
|
|
v[4]=meshnode[n[2]].A;
|
|
|
|
// construct values for mid-side nodes;
|
|
if ((R[0]<1.e-06) && (R[1]<1.e-06)) v[1]=(v[0]+v[2])/2.;
|
|
else v[1]=(R[1]*(3.*v[0] + v[2]) + R[0]*(v[0] + 3.*v[2]))/
|
|
(4.*(R[0] + R[1]));
|
|
|
|
if ((R[1]<1.e-06) && (R[2]<1.e-06)) v[3]=(v[2]+v[4])/2.;
|
|
else v[3]=(R[2]*(3.*v[2] + v[4]) + R[1]*(v[2] + 3.*v[4]))/
|
|
(4.*(R[1] + R[2]));
|
|
|
|
if ((R[2]<1.e-06) && (R[0]<1.e-06)) v[5]=(v[4]+v[0])/2.;
|
|
else v[5]=(R[0]*(3.*v[4] + v[0]) + R[2]*(v[4] + 3.*v[0]))/
|
|
(4.*(R[2] + R[0]));
|
|
|
|
// derivatives w.r.t. p and q:
|
|
dp=(-v[0] + v[2] + 4.*v[3] - 4.*v[5])/3.;
|
|
dq=(-v[0] - 4.*v[1] + 4.*v[3] + v[4])/3.;
|
|
|
|
// now, compute flux.
|
|
da*=2.*PI*r*LengthConv[LengthUnits]*LengthConv[LengthUnits];
|
|
elm.B1=-(c[1]*dp+c[2]*dq)/da;
|
|
elm.B2= (b[1]*dp+b[2]*dq)/da;
|
|
|
|
if (bIncremental)
|
|
{
|
|
// corner nodes
|
|
v[0]=meshnode[n[0]].Aprev;
|
|
v[2]=meshnode[n[1]].Aprev;
|
|
v[4]=meshnode[n[2]].Aprev;
|
|
|
|
// construct values for mid-side nodes;
|
|
if ((R[0]<1.e-06) && (R[1]<1.e-06)) v[1]=(v[0]+v[2])/2.;
|
|
else v[1]=(R[1]*(3.*v[0] + v[2]) + R[0]*(v[0] + 3.*v[2]))/
|
|
(4.*(R[0] + R[1]));
|
|
|
|
if ((R[1]<1.e-06) && (R[2]<1.e-06)) v[3]=(v[2]+v[4])/2.;
|
|
else v[3]=(R[2]*(3.*v[2] + v[4]) + R[1]*(v[2] + 3.*v[4]))/
|
|
(4.*(R[1] + R[2]));
|
|
|
|
if ((R[2]<1.e-06) && (R[0]<1.e-06)) v[5]=(v[4]+v[0])/2.;
|
|
else v[5]=(R[0]*(3.*v[4] + v[0]) + R[2]*(v[4] + 3.*v[0]))/
|
|
(4.*(R[2] + R[0]));
|
|
|
|
// derivatives w.r.t. p and q:
|
|
dp=(-v[0] + v[2] + 4.*v[3] - 4.*v[5])/3.;
|
|
dq=(-v[0] - 4.*v[1] + 4.*v[3] + v[4])/3.;
|
|
|
|
// now, compute flux.
|
|
da=(b[0]*c[1]-b[1]*c[0]);
|
|
da*=2.*PI*r*LengthConv[LengthUnits]*LengthConv[LengthUnits];
|
|
elm.B1p=Re(-(c[1]*dp+c[2]*dq)/da);
|
|
elm.B2p=Re( (b[1]*dp+b[2]*dq)/da);
|
|
}
|
|
else{
|
|
elm.B1p=0;
|
|
elm.B2p=0;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
void CFemmviewDoc::OnReload()
|
|
{
|
|
// TODO: Add your command handler code here
|
|
CString pname = GetPathName();
|
|
if(pname.GetLength()>0)
|
|
{
|
|
OnNewDocument();
|
|
SetPathName(pname,FALSE);
|
|
OnOpenDocument(pname);
|
|
}
|
|
}
|
|
|
|
int CFemmviewDoc::ClosestNode(double x, double y)
|
|
{
|
|
int i,j;
|
|
double d0,d1;
|
|
|
|
if(nodelist.GetSize()==0) return -1;
|
|
|
|
j=0;
|
|
d0=nodelist[0].GetDistance(x,y);
|
|
for(i=0;i<nodelist.GetSize();i++){
|
|
d1=nodelist[i].GetDistance(x,y);
|
|
if(d1<d0){
|
|
d0=d1;
|
|
j=i;
|
|
}
|
|
}
|
|
|
|
return j;
|
|
}
|
|
|
|
void CFemmviewDoc::GetLineValues(CXYPlot &p,int PlotType,int NumPlotPoints)
|
|
{
|
|
double *q,z,u,dz;
|
|
CComplex pt,n,t;
|
|
int i,j,k,m,elm;
|
|
CPointVals v;
|
|
BOOL flag;
|
|
|
|
q=(double *)calloc(contour.GetSize(),sizeof(double));
|
|
for(i=1,z=0.;i<contour.GetSize();i++)
|
|
{
|
|
z+=abs(contour[i]-contour[i-1]);
|
|
q[i]=z;
|
|
}
|
|
dz=z/(NumPlotPoints-1);
|
|
|
|
/*
|
|
m_XYPlotType.AddString("Potential");
|
|
m_XYPlotType.AddString("|B| (Magnitude of flux density)");
|
|
m_XYPlotType.AddString("B . n (Normal flux density)");
|
|
m_XYPlotType.AddString("B . t (Tangential flux density)");
|
|
m_XYPlotType.AddString("|H| (Magnitude of field intensity)");
|
|
m_XYPlotType.AddString("H . n (Normal field intensity)");
|
|
m_XYPlotType.AddString("H . t (Tangential field intensity)");
|
|
m_XYPlotType.AddString("J_eddy
|
|
*/
|
|
|
|
if(Frequency==0){
|
|
switch (PlotType)
|
|
{
|
|
case 0:
|
|
p.Create(NumPlotPoints,2);
|
|
if (ProblemType==0) strcpy(p.lbls[1],"Potential, Wb/m");
|
|
else strcpy(p.lbls[1],"Flux, Wb");
|
|
break;
|
|
case 1:
|
|
p.Create(NumPlotPoints,2);
|
|
strcpy(p.lbls[1],"|B|, Tesla");
|
|
break;
|
|
case 2:
|
|
p.Create(NumPlotPoints,2);
|
|
strcpy(p.lbls[1],"B.n, Tesla");
|
|
break;
|
|
case 3:
|
|
p.Create(NumPlotPoints,2);
|
|
strcpy(p.lbls[1],"B.t, Tesla");
|
|
break;
|
|
case 4:
|
|
p.Create(NumPlotPoints,2);
|
|
strcpy(p.lbls[1],"|H|, Amp/m");
|
|
break;
|
|
case 5:
|
|
p.Create(NumPlotPoints,2);
|
|
strcpy(p.lbls[1],"H.n, Amp/m");
|
|
break;
|
|
case 6:
|
|
p.Create(NumPlotPoints,2);
|
|
strcpy(p.lbls[1],"H.t, Amp/m");
|
|
break;
|
|
default:
|
|
p.Create(NumPlotPoints,2);
|
|
break;
|
|
}
|
|
}
|
|
else{
|
|
switch (PlotType)
|
|
{
|
|
case 0:
|
|
p.Create(NumPlotPoints,4);
|
|
if(ProblemType==0){
|
|
strcpy(p.lbls[1],"|A|, Wb/m");
|
|
strcpy(p.lbls[2],"Re[A], Wb/m");
|
|
strcpy(p.lbls[3],"Im[A], Wb/m");
|
|
}
|
|
else{
|
|
strcpy(p.lbls[1],"|Flux|, Wb");
|
|
strcpy(p.lbls[2],"Re[Flux], Wb");
|
|
strcpy(p.lbls[3],"Im[Flux], Wb");
|
|
}
|
|
break;
|
|
case 1:
|
|
p.Create(NumPlotPoints,2);
|
|
strcpy(p.lbls[1],"|B|, Tesla");
|
|
break;
|
|
case 2:
|
|
p.Create(NumPlotPoints,4);
|
|
strcpy(p.lbls[1],"|B.n|, Tesla");
|
|
strcpy(p.lbls[2],"Re[B.n], Tesla");
|
|
strcpy(p.lbls[3],"Im[B.n], Tesla");
|
|
break;
|
|
case 3:
|
|
p.Create(NumPlotPoints,4);
|
|
strcpy(p.lbls[1],"|B.t|, Tesla");
|
|
strcpy(p.lbls[2],"Re[B.t], Tesla");
|
|
strcpy(p.lbls[3],"Im[B.t], Tesla");
|
|
break;
|
|
case 4:
|
|
p.Create(NumPlotPoints,2);
|
|
strcpy(p.lbls[1],"|H|, Amp/m");
|
|
break;
|
|
case 5:
|
|
p.Create(NumPlotPoints,4);
|
|
if(ProblemType==0){
|
|
strcpy(p.lbls[1],"|H.n|, Amp/m");
|
|
strcpy(p.lbls[2],"Re[H.n], Amp/m");
|
|
strcpy(p.lbls[3],"Im[H.n], Amp/m");
|
|
}
|
|
break;
|
|
case 6:
|
|
p.Create(NumPlotPoints,4);
|
|
strcpy(p.lbls[1],"|H.t|, Amp/m");
|
|
strcpy(p.lbls[2],"Re[H.t], Amp/m");
|
|
strcpy(p.lbls[3],"Im[H.t], Amp/m");
|
|
break;
|
|
case 7:
|
|
p.Create(NumPlotPoints,4);
|
|
strcpy(p.lbls[1],"|Je|, MA/m^2");
|
|
strcpy(p.lbls[2],"Re[Je], MA/m^2");
|
|
strcpy(p.lbls[3],"Im[Je], MA/m^2");
|
|
break;
|
|
case 8:
|
|
p.Create(NumPlotPoints,4);
|
|
strcpy(p.lbls[1],"|Js+Je|, MA/m^2");
|
|
strcpy(p.lbls[2],"Re[Js+Je], MA/m^2");
|
|
strcpy(p.lbls[3],"Im[Js+Je], MA/m^2");
|
|
break;
|
|
default:
|
|
p.Create(NumPlotPoints,2);
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch(LengthUnits){
|
|
case 1:
|
|
strcpy(p.lbls[0],"Length, mm");
|
|
break;
|
|
case 2:
|
|
strcpy(p.lbls[0],"Length, cm");
|
|
break;
|
|
case 3:
|
|
strcpy(p.lbls[0],"Length, m");
|
|
break;
|
|
case 4:
|
|
strcpy(p.lbls[0],"Length, mils");
|
|
break;
|
|
case 5:
|
|
strcpy(p.lbls[0],"Length, um");
|
|
break;
|
|
default:
|
|
strcpy(p.lbls[0],"Length, inches");
|
|
break;
|
|
}
|
|
|
|
for(i=0,k=1,z=0,elm=-1;i<NumPlotPoints;i++,z+=dz)
|
|
{
|
|
while((z>q[k]) && (k<(contour.GetSize()-1))) k++;
|
|
u=(z-q[k-1])/(q[k]-q[k-1]);
|
|
pt=contour[k-1]+u*(contour[k]-contour[k-1]);
|
|
t=contour[k]-contour[k-1];
|
|
t/=abs(t);
|
|
n = I*t;
|
|
pt+=(n*1.e-06);
|
|
|
|
if (elm<0) elm=InTriangle(pt.re,pt.im);
|
|
else if (InTriangleTest(pt.re,pt.im,elm)==FALSE)
|
|
{
|
|
flag=FALSE;
|
|
for(j=0;j<3;j++)
|
|
for(m=0;m<NumList[meshelem[elm].p[j]];m++)
|
|
{
|
|
elm=ConList[meshelem[elm].p[j]][m];
|
|
if (InTriangleTest(pt.re,pt.im,elm)==TRUE)
|
|
{
|
|
flag=TRUE;
|
|
m=100;
|
|
j=3;
|
|
}
|
|
}
|
|
if (flag==FALSE) elm=InTriangle(pt.re,pt.im);
|
|
}
|
|
if(elm>=0)
|
|
flag=GetPointValues(pt.re,pt.im,elm,v);
|
|
else flag=FALSE;
|
|
|
|
p.M[i][0]=z;
|
|
if ((Frequency==0) && (flag!=FALSE)){
|
|
switch (PlotType){
|
|
case 0:
|
|
p.M[i][1]=v.A.re;
|
|
break;
|
|
case 1:
|
|
p.M[i][1]=sqrt(v.B1.Abs()*v.B1.Abs() + v.B2.Abs()*v.B2.Abs());
|
|
break;
|
|
case 2:
|
|
p.M[i][1]= n.re*v.B1.re + n.im*v.B2.re;
|
|
break;
|
|
case 3:
|
|
p.M[i][1]= t.re*v.B1.re + t.im*v.B2.re;
|
|
break;
|
|
case 4:
|
|
p.M[i][1]=sqrt(v.H1.Abs()*v.H1.Abs() + v.H2.Abs()*v.H2.Abs());
|
|
break;
|
|
case 5:
|
|
p.M[i][1]= n.re*v.H1.re + n.im*v.H2.re;
|
|
break;
|
|
case 6:
|
|
p.M[i][1]= t.re*v.H1.re + t.im*v.H2.re;
|
|
break;
|
|
default:
|
|
p.M[i][1]=0;
|
|
break;
|
|
}
|
|
}
|
|
else if (flag!=FALSE){
|
|
switch (PlotType){
|
|
case 0:
|
|
p.M[i][1]=v.A.Abs();
|
|
p.M[i][2]=v.A.re;
|
|
p.M[i][3]=v.A.im;
|
|
break;
|
|
case 1:
|
|
p.M[i][1]=sqrt(v.B1.Abs()*v.B1.Abs() + v.B2.Abs()*v.B2.Abs());
|
|
break;
|
|
case 2:
|
|
p.M[i][2]= n.re*v.B1.re + n.im*v.B2.re;
|
|
p.M[i][3]= n.re*v.B1.im + n.im*v.B2.im;
|
|
p.M[i][1]=sqrt(p.M[i][2]*p.M[i][2] +
|
|
p.M[i][3]*p.M[i][3]);
|
|
break;
|
|
case 3:
|
|
p.M[i][2]= t.re*v.B1.re + t.im*v.B2.re;
|
|
p.M[i][3]= t.re*v.B1.im + t.im*v.B2.im;
|
|
p.M[i][1]=sqrt(p.M[i][2]*p.M[i][2] +
|
|
p.M[i][3]*p.M[i][3]);
|
|
break;
|
|
case 4:
|
|
p.M[i][1]=sqrt(v.H1.Abs()*v.H1.Abs() + v.H2.Abs()*v.H2.Abs());
|
|
break;
|
|
case 5:
|
|
p.M[i][2]= n.re*v.H1.re + n.im*v.H2.re;
|
|
p.M[i][3]= n.re*v.H1.im + n.im*v.H2.im;
|
|
p.M[i][1]=sqrt(p.M[i][2]*p.M[i][2] +
|
|
p.M[i][3]*p.M[i][3]);
|
|
break;
|
|
case 6:
|
|
p.M[i][2]= t.re*v.H1.re + t.im*v.H2.re;
|
|
p.M[i][3]= t.re*v.H1.im + t.im*v.H2.im;
|
|
p.M[i][1]=sqrt(p.M[i][2]*p.M[i][2] +
|
|
p.M[i][3]*p.M[i][3]);
|
|
break;
|
|
case 7:
|
|
p.M[i][2]= v.Je.re;
|
|
p.M[i][3]= v.Je.im;
|
|
p.M[i][1]= abs(v.Je);
|
|
break;
|
|
case 8:
|
|
p.M[i][2]= v.Je.re+v.Js.re;
|
|
p.M[i][3]= v.Je.im+v.Js.im;
|
|
p.M[i][1]= abs(v.Je+v.Js);
|
|
break;
|
|
default:
|
|
p.M[i][1]=0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
free(q);
|
|
}
|
|
|
|
BOOL CFemmviewDoc::InTriangleTest(double x, double y, int i)
|
|
{
|
|
if ((i<0) || (i>=meshelem.GetSize())) return FALSE;
|
|
|
|
int j,k;
|
|
double z;
|
|
|
|
for(j=0;j<3;j++)
|
|
{
|
|
k=j+1; if(k==3) k=0;
|
|
// Case 1: p[k]>p[j]
|
|
if (meshelem[i].p[k] > meshelem[i].p[j])
|
|
{
|
|
z=(meshnode[meshelem[i].p[k]].x-meshnode[meshelem[i].p[j]].x)*
|
|
(y-meshnode[meshelem[i].p[j]].y) -
|
|
(meshnode[meshelem[i].p[k]].y-meshnode[meshelem[i].p[j]].y)*
|
|
(x-meshnode[meshelem[i].p[j]].x);
|
|
if(z<0) return FALSE;
|
|
}
|
|
//Case 2: p[k]<p[j]
|
|
else{
|
|
z=(meshnode[meshelem[i].p[j]].x-meshnode[meshelem[i].p[k]].x)*
|
|
(y-meshnode[meshelem[i].p[k]].y) -
|
|
(meshnode[meshelem[i].p[j]].y-meshnode[meshelem[i].p[k]].y)*
|
|
(x-meshnode[meshelem[i].p[k]].x);
|
|
if(z>0) return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
CPointVals::CPointVals()
|
|
{
|
|
A=0; // vector potential
|
|
B1=0; B2=0; // flux density
|
|
mu1=1; mu2=1; // permeability
|
|
H1=0; H2=0; // field intensity
|
|
Je=0; Js=0; // eddy current and source current densities
|
|
c=0; // conductivity
|
|
E=0; // energy stored in the magnetic field
|
|
Ph=0; // power dissipated by hysteresis
|
|
Pe=0;
|
|
ff=1;
|
|
}
|
|
|
|
CComplex CFemmviewDoc::Ctr(int i)
|
|
{
|
|
CComplex p,c;
|
|
int j;
|
|
|
|
for(j=0,c=0;j<3;j++){
|
|
p.Set(meshnode[meshelem[i].p[j]].x/3.,meshnode[meshelem[i].p[j]].y/3.);
|
|
c+=p;
|
|
}
|
|
|
|
return c;
|
|
}
|
|
|
|
double CFemmviewDoc::ElmArea(int i)
|
|
{
|
|
int j,n[3];
|
|
double b0,b1,c0,c1;
|
|
|
|
for(j=0;j<3;j++) n[j]=meshelem[i].p[j];
|
|
|
|
b0=meshnode[n[1]].y - meshnode[n[2]].y;
|
|
b1=meshnode[n[2]].y - meshnode[n[0]].y;
|
|
c0=meshnode[n[2]].x - meshnode[n[1]].x;
|
|
c1=meshnode[n[0]].x - meshnode[n[2]].x;
|
|
return (b0*c1-b1*c0)/2.;
|
|
|
|
}
|
|
|
|
double CFemmviewDoc::ElmArea(CElement *elm)
|
|
{
|
|
int j,n[3];
|
|
double b0,b1,c0,c1;
|
|
|
|
for(j=0;j<3;j++) n[j]=elm->p[j];
|
|
|
|
b0=meshnode[n[1]].y - meshnode[n[2]].y;
|
|
b1=meshnode[n[2]].y - meshnode[n[0]].y;
|
|
c0=meshnode[n[2]].x - meshnode[n[1]].x;
|
|
c1=meshnode[n[0]].x - meshnode[n[2]].x;
|
|
return (b0*c1-b1*c0)/2.;
|
|
|
|
}
|
|
|
|
CComplex CFemmviewDoc::GetJA(int k,CComplex *J,CComplex *A)
|
|
{
|
|
// returns current density with contribution from all sources in
|
|
// units of MA/m^2
|
|
|
|
int i,blk,lbl,crc;
|
|
double r,c,rn;
|
|
CComplex Javg;
|
|
|
|
blk=meshelem[k].blk;
|
|
lbl=meshelem[k].lbl;
|
|
crc=blocklist[lbl].InCircuit;
|
|
|
|
// first, get A
|
|
for(i=0;i<3;i++){
|
|
if(ProblemType==0) A[i]=(meshnode[meshelem[k].p[i]].A);
|
|
else{
|
|
rn=meshnode[meshelem[k].p[i]].x*LengthConv[LengthUnits];
|
|
if(fabs(rn/LengthConv[LengthUnits])<1.e-06) A[i]=0;
|
|
else A[i]=(meshnode[meshelem[k].p[i]].A)/(2.*PI*rn);
|
|
}
|
|
}
|
|
|
|
if(ProblemType==1) r = Re(Ctr(k))*LengthConv[LengthUnits];
|
|
|
|
// contribution from explicitly specified J
|
|
for(i=0;i<3;i++) J[i]=blockproplist[blk].Jr+I*blockproplist[blk].Ji;
|
|
Javg=blockproplist[blk].Jr+I*blockproplist[blk].Ji;
|
|
|
|
c=blockproplist[blk].Cduct;
|
|
if ((blockproplist[blk].Lam_d!=0) && (blockproplist[blk].LamType==0)) c=0;
|
|
if (blocklist[lbl].FillFactor>0) c=0;
|
|
|
|
|
|
// contribution from eddy currents;
|
|
if(Frequency!=0)
|
|
for(i=0;i<3;i++)
|
|
{
|
|
J[i]-=I*Frequency*2.*PI*c*A[i];
|
|
Javg-=I*Frequency*2.*PI*c*A[i]/3.;
|
|
}
|
|
|
|
|
|
// contribution from circuit currents //
|
|
if(crc>=0)
|
|
{
|
|
if(blocklist[lbl].Case==0){ // specified voltage
|
|
if(ProblemType==0){
|
|
for(i=0;i<3;i++)
|
|
J[i]-=c*blocklist[lbl].dVolts;
|
|
Javg-=c*blocklist[lbl].dVolts;
|
|
}
|
|
else{
|
|
for(i=0;i<3;i++){
|
|
rn=meshnode[meshelem[k].p[i]].x;
|
|
if(fabs(rn/LengthConv[LengthUnits])<1.e-06)
|
|
J[i]-=c*blocklist[lbl].dVolts/r;
|
|
else
|
|
J[i]-=c*blocklist[lbl].dVolts/(rn*LengthConv[LengthUnits]);
|
|
|
|
}
|
|
Javg-=c*blocklist[lbl].dVolts/r;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(i=0;i<3;i++) J[i]+=blocklist[lbl].J; // specified current
|
|
Javg+=blocklist[lbl].J;
|
|
}
|
|
|
|
}
|
|
|
|
// convert results to A/m^2
|
|
for(i=0;i<3;i++) J[i]*=1.e06;
|
|
|
|
return (Javg*1.e06);
|
|
}
|
|
|
|
CComplex CFemmviewDoc::PlnInt(double a, CComplex *u, CComplex *v)
|
|
{
|
|
int i;
|
|
CComplex z[3],x;
|
|
|
|
z[0]=2.*u[0]+u[1]+u[2];
|
|
z[1]=u[0]+2.*u[1]+u[2];
|
|
z[2]=u[0]+u[1]+2.*u[2];
|
|
|
|
for(i=0,x=0;i<3;i++) x+=v[i]*z[i];
|
|
return a*x/12.;
|
|
}
|
|
|
|
CComplex CFemmviewDoc::AxiInt(double a, CComplex *u, CComplex *v,double *r)
|
|
{
|
|
int i;
|
|
static CComplex M[3][3];
|
|
CComplex x, z[3];
|
|
|
|
M[0][0]=6.*r[0]+2.*r[1]+2.*r[2];
|
|
M[0][1]=2.*r[0]+2.*r[1]+1.*r[2];
|
|
M[0][2]=2.*r[0]+1.*r[1]+2.*r[2];
|
|
M[1][1]=2.*r[0]+6.*r[1]+2.*r[2];
|
|
M[1][2]=1.*r[0]+2.*r[1]+2.*r[2];
|
|
M[2][2]=2.*r[0]+2.*r[1]+6.*r[2];
|
|
M[1][0]=M[0][1];
|
|
M[2][0]=M[0][2];
|
|
M[2][1]=M[1][2];
|
|
|
|
for(i=0;i<3;i++) z[i]=M[i][0]*u[0]+M[i][1]*u[1]+M[i][2]*u[2];
|
|
for(i=0,x=0;i<3;i++) x+=v[i]*z[i];
|
|
return PI*a*x/30.;
|
|
}
|
|
|
|
CComplex CFemmviewDoc::HenrotteVector(int k)
|
|
{
|
|
int i,n[3];
|
|
double b[3],c[3],da;
|
|
CComplex v;
|
|
|
|
for(i=0;i<3;i++) n[i]=meshelem[k].p[i];
|
|
|
|
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]);
|
|
|
|
for(i=0,v=0;i<3;i++)
|
|
v-=meshnode[n[i]].msk*(b[i]+I*c[i])/(da*LengthConv[LengthUnits]); // grad
|
|
|
|
return v;
|
|
}
|
|
|
|
CComplex CFemmviewDoc::BlockIntegral(int inttype)
|
|
{
|
|
int i,k;
|
|
CComplex c,y,z,J,mu1,mu2,B1,B2,H1,H2,F1,F2;
|
|
CComplex A[3],Jn[3],U[3],V[3];
|
|
double a,sig,R,B1p,B2p,Jp;
|
|
double r[3];
|
|
|
|
// make weighted stress tensor mask for integrals where it's needed
|
|
#define WEIGHTED_INTEGRALS 9
|
|
int mm[WEIGHTED_INTEGRALS] = {18,19,20,21,22,23,25,26,27};
|
|
BOOL bMaskIntegral=FALSE;
|
|
for (k=0;k<WEIGHTED_INTEGRALS;k++)
|
|
{
|
|
if (mm[k]==inttype)
|
|
{
|
|
MakeMask();
|
|
bMaskIntegral=TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
z=0; for(i=0;i<3;i++) U[i]=1.;
|
|
|
|
if(inttype==6) z= BlockIntegral(3) + BlockIntegral(4); //total losses
|
|
else for(i=0;i<meshelem.GetSize();i++)
|
|
{
|
|
// Integrals performed only over the selected region (as opposed to Mask Integrals),
|
|
// which are performed over the entire solution domain using the mask to weight the contribution
|
|
// of the various elements)
|
|
if((blocklist[meshelem[i].lbl].IsSelected==TRUE) && (!bMaskIntegral))
|
|
{
|
|
|
|
// compute some useful quantities employed by most integrals...
|
|
J=GetJA(i,Jn,A);
|
|
a=ElmArea(i)*pow(LengthConv[LengthUnits],2.);
|
|
if(ProblemType==1){
|
|
for(k=0;k<3;k++)
|
|
r[k]=meshnode[meshelem[i].p[k]].x*LengthConv[LengthUnits];
|
|
R=(r[0]+r[1]+r[2])/3.;
|
|
}
|
|
|
|
// now, compute the desired integral;
|
|
switch(inttype)
|
|
{
|
|
case 0: // A.J
|
|
for(k=0;k<3;k++) V[k]=Jn[k].Conj();
|
|
if(ProblemType==0)
|
|
y=PlnInt(a,A,V)*Depth;
|
|
else
|
|
y=AxiInt(a,A,V,r);
|
|
z+=y;
|
|
|
|
break;
|
|
|
|
case 11: // x (or r) direction Lorentz force, SS part.
|
|
B2=meshelem[i].B2;
|
|
y= -(B2.re*J.re + B2.im*J.im);
|
|
if (ProblemType==1) y=0; else y*=Depth;
|
|
if(Frequency!=0) y*=0.5;
|
|
z+=(a*y);
|
|
break;
|
|
|
|
case 12: // y (or z) direction Lorentz force, SS part.
|
|
for(k=0;k<3;k++) V[k]=Re(meshelem[i].B1*Jn[k].Conj());
|
|
if(ProblemType==0)
|
|
y=PlnInt(a,U,V)*Depth;
|
|
else
|
|
y=AxiInt(-a,U,V,r);
|
|
if(Frequency!=0) y*=0.5;
|
|
z+=y;
|
|
|
|
break;
|
|
|
|
case 13: // x (or r) direction Lorentz force, 2x part.
|
|
if((Frequency!=0) && (ProblemType==0))
|
|
{
|
|
B2=meshelem[i].B2;
|
|
y= -(B2.re*J.re - B2.im*J.im) - I*(B2.re*J.im+B2.im*J.re);
|
|
z+=0.5*(a*y*Depth);
|
|
}
|
|
break;
|
|
|
|
case 14: // y (or z) direction Lorentz force, 2x part.
|
|
if (Frequency!=0)
|
|
{
|
|
B1=meshelem[i].B1;
|
|
B2=meshelem[i].B2;
|
|
y= (B1.re*J.re - B1.im*J.im) + I*(B1.re*J.im+B1.im*J.re);
|
|
if(ProblemType==1) y=(-y*2.*PI*R); else y*=Depth;
|
|
z+=(a*y)/2.;
|
|
}
|
|
break;
|
|
|
|
case 16: // Lorentz Torque, 2x
|
|
if ((Frequency!=0) && (ProblemType==0))
|
|
{
|
|
B1=meshelem[i].B1;
|
|
B2=meshelem[i].B2;
|
|
c=Ctr(i)*LengthConv[LengthUnits];
|
|
y= c.re*((B1.re*J.re - B1.im*J.im) + I*(B1.re*J.im+B1.im*J.re))
|
|
+c.im*((B2.re*J.re - B2.im*J.im) + I*(B2.re*J.im+B2.im*J.re));
|
|
z+=0.5*(a*y*Depth);
|
|
}
|
|
break;
|
|
|
|
case 15: // Lorentz Torque, SS part.
|
|
if(ProblemType==0)
|
|
{
|
|
B1=meshelem[i].B1;
|
|
B2=meshelem[i].B2;
|
|
c=Ctr(i)*LengthConv[LengthUnits];
|
|
y= c.im*(B2.re*J.re + B2.im*J.im) + c.re*(B1.re*J.re + B1.im*J.im);
|
|
if(Frequency!=0) y*=0.5;
|
|
z+=(a*y*Depth);
|
|
}
|
|
break;
|
|
|
|
case 1: // integrate A over the element;
|
|
if(ProblemType==1)
|
|
y=AxiInt(a,U,A,r);
|
|
else
|
|
for(k=0,y=0;k<3;k++) y+=a*Depth*A[k]/3.;
|
|
|
|
z+=y;
|
|
break;
|
|
|
|
case 2: // stored energy
|
|
if(ProblemType==1) a*=(2.*PI*R); else a*=Depth;
|
|
B1=meshelem[i].B1;
|
|
B2=meshelem[i].B2;
|
|
if(Frequency!=0){
|
|
// have to compute the energy stored in a special way for
|
|
// wound regions subject to prox and skin effects
|
|
if (blockproplist[meshelem[i].blk].LamType>2)
|
|
{
|
|
CComplex mu;
|
|
mu=muo*blocklist[meshelem[i].lbl].mu;
|
|
double u=blocklist[meshelem[i].lbl].LocalEnergy;
|
|
y=a*Re(B1*conj(B1)+B2*conj(B2))*Re(1./mu)/4.;
|
|
y+=a*Re(J*conj(J))*u/4.;
|
|
}
|
|
else y=a*blockproplist[meshelem[i].blk].DoEnergy(B1,B2);
|
|
}
|
|
else
|
|
{
|
|
// correct H and energy stored in magnet for second-quadrant
|
|
// representation of a PM.
|
|
if (blockproplist[meshelem[i].blk].H_c!=0)
|
|
{
|
|
int bk=meshelem[i].blk;
|
|
|
|
// in the linear case:
|
|
if (blockproplist[bk].BHpoints==0)
|
|
{
|
|
CComplex Hc;
|
|
mu1=blockproplist[bk].mu_x;
|
|
mu2=blockproplist[bk].mu_y;
|
|
H1=B1/(mu1*muo);
|
|
H2=B2/(mu2*muo);
|
|
Hc = blockproplist[bk].H_c*exp(I*PI*meshelem[i].magdir/180.);
|
|
H1=H1-Re(Hc);
|
|
H2=H2-Im(Hc);
|
|
y = a*0.5*muo*(mu1.re*H1.re*H1.re + mu2.re*H2.re*H2.re);
|
|
}
|
|
else{ // the material is nonlinear
|
|
y=blockproplist[bk].DoEnergy(B1.re,B2.re);
|
|
y = y + blockproplist[bk].Nrg
|
|
- blockproplist[bk].H_c*Re((B1.re+I*B2.re)/exp(I*PI*meshelem[i].magdir/180.));
|
|
y*=a;
|
|
}
|
|
}
|
|
else y=a*blockproplist[meshelem[i].blk].DoEnergy(B1.re,B2.re);
|
|
|
|
// add in "local" stored energy for wound that would be subject to
|
|
// prox and skin effect for nonzero frequency cases.
|
|
if (blockproplist[meshelem[i].blk].LamType>2)
|
|
{
|
|
double u=blocklist[meshelem[i].lbl].LocalEnergy;
|
|
y+=a*Re(J*J)*u/2.;
|
|
}
|
|
}
|
|
y*=AECF(i); // correction for axisymmetric external region;
|
|
|
|
z+=y;
|
|
break;
|
|
|
|
case 3: // Hysteresis & Laminated eddy current losses
|
|
if(Frequency!=0){
|
|
if(ProblemType==1) a*=(2.*PI*R); else a*=Depth;
|
|
B1=meshelem[i].B1;
|
|
B2=meshelem[i].B2;
|
|
GetMu(B1,B2,mu1,mu2,i);
|
|
H1=B1/(mu1*muo);
|
|
H2=B2/(mu2*muo);
|
|
|
|
y=a*PI*Frequency*Im(H1*B1.Conj() + H2*B2.Conj());
|
|
z+=y;
|
|
}
|
|
break;
|
|
|
|
case 4: // Resistive Losses
|
|
if (abs(blocklist[meshelem[i].lbl].o)==0) sig=0;
|
|
else sig=1.e06/Re(1./blocklist[meshelem[i].lbl].o);
|
|
if((blockproplist[meshelem[i].blk].Lam_d!=0) &&
|
|
(blockproplist[meshelem[i].blk].LamType==0)) sig=0;
|
|
if(sig!=0){
|
|
|
|
if (ProblemType==0){
|
|
for(k=0;k<3;k++) V[k]=Jn[k].Conj()/sig;
|
|
y=PlnInt(a,Jn,V)*Depth;
|
|
}
|
|
|
|
if(ProblemType==1)
|
|
y=2.*PI*R*a*J*conj(J)/sig;
|
|
|
|
if(Frequency!=0) y/=2.;
|
|
z+=y;
|
|
}
|
|
break;
|
|
|
|
case 5: // cross-section area
|
|
z+=a;
|
|
break;
|
|
|
|
case 10: // volume
|
|
if(ProblemType==1) a*=(2.*PI*R); else a*=Depth;
|
|
z+=a;
|
|
break;
|
|
|
|
case 7: // total current in block;
|
|
z+=a*J;
|
|
|
|
break;
|
|
|
|
case 8: // integrate x or r part of b over the block
|
|
if(ProblemType==1) a*=(2.*PI*R); else a*=Depth;
|
|
z+=(a*meshelem[i].B1);
|
|
break;
|
|
|
|
case 9: // integrate y or z part of b over the block
|
|
if(ProblemType==1) a*=(2.*PI*R); else a*=Depth;
|
|
z+=(a*meshelem[i].B2);
|
|
break;
|
|
|
|
case 17: // Coenergy
|
|
if(ProblemType==1) a*=(2.*PI*R); else a*=Depth;
|
|
B1=meshelem[i].B1;
|
|
B2=meshelem[i].B2;
|
|
if(Frequency!=0){
|
|
// have to compute the energy stored in a special way for
|
|
// wound regions subject to prox and skin effects
|
|
if (blockproplist[meshelem[i].blk].LamType>2)
|
|
{
|
|
CComplex mu;
|
|
mu=muo*blocklist[meshelem[i].lbl].mu;
|
|
double u=blocklist[meshelem[i].lbl].LocalEnergy;
|
|
y=a*Re(B1*conj(B1)+B2*conj(B2))*Re(1./mu)/4.;
|
|
y+=a*Re(J*conj(J))*u/4.;
|
|
}
|
|
else y=a*blockproplist[meshelem[i].blk].DoCoEnergy(B1,B2);
|
|
}
|
|
else
|
|
{
|
|
y=a*blockproplist[meshelem[i].blk].DoCoEnergy(B1.re,B2.re);
|
|
|
|
// add in "local" stored energy for wound that would be subject to
|
|
// prox and skin effect for nonzero frequency cases.
|
|
if (blockproplist[meshelem[i].blk].LamType>2)
|
|
{
|
|
double u=blocklist[meshelem[i].lbl].LocalEnergy;
|
|
y+=a*Re(J*J)*u/2.;
|
|
}
|
|
}
|
|
y*=AECF(i); // correction for axisymmetric external region;
|
|
|
|
z+=y;
|
|
break;
|
|
|
|
case 24: // Moment of Inertia-like integral
|
|
|
|
// For axisymmetric problems, compute the moment
|
|
// of inertia about the r=0 axis.
|
|
if(ProblemType==1){
|
|
for(k=0;k<3;k++) V[k]=r[k];
|
|
y=AxiInt(a,V,V,r);
|
|
}
|
|
|
|
// For planar problems, compute the moment of
|
|
// inertia about the z=axis.
|
|
else{
|
|
for(k=0;k<3;k++)
|
|
{
|
|
U[k]=meshnode[meshelem[i].p[k]].x*LengthConv[LengthUnits];
|
|
V[k]=meshnode[meshelem[i].p[k]].y*LengthConv[LengthUnits];
|
|
}
|
|
y =U[0]*U[0] + U[1]*U[1] + U[2]*U[2];
|
|
y+=U[0]*U[1] + U[0]*U[2] + U[1]*U[2];
|
|
y+=V[0]*V[0] + V[1]*V[1] + V[2]*V[2];
|
|
y+=V[0]*V[1] + V[0]*V[2] + V[1]*V[2];
|
|
y*=(a*Depth/6.);
|
|
}
|
|
|
|
z+=y;
|
|
break;
|
|
|
|
case 28: // x (or r) direction Lorentz force, 1X part for incremental AC problems
|
|
B2=meshelem[i].B2;
|
|
B2p=meshelem[i].B2p;
|
|
Jp=meshelem[i].Jp;
|
|
y= -(B2p*J + B2*Jp);
|
|
if (ProblemType==1) y=0; else y*=Depth;
|
|
z+=(a*y);
|
|
break;
|
|
|
|
case 29: // y (or z) direction Lorentz force, 1X part for incremental AC problems
|
|
B1=meshelem[i].B1;
|
|
B1p=meshelem[i].B1p;
|
|
Jp=meshelem[i].Jp;
|
|
for(k=0;k<3;k++)
|
|
{
|
|
U[k] = 1;
|
|
V[k] = (B1p*J + B1*Jp);
|
|
}
|
|
if(ProblemType==0)
|
|
y=PlnInt(a,U,V)*Depth;
|
|
else
|
|
y=AxiInt(-a,U,V,r);
|
|
|
|
z+=y;
|
|
|
|
break;
|
|
|
|
case 30: // Lorentz Torque, 1X part for incremental AC problems
|
|
if(ProblemType==0)
|
|
{
|
|
B1=meshelem[i].B1;
|
|
B2=meshelem[i].B2;
|
|
B1p=meshelem[i].B1p;
|
|
B2p=meshelem[i].B2p;
|
|
Jp=meshelem[i].Jp;
|
|
c=Ctr(i)*LengthConv[LengthUnits];
|
|
y= c.im*(B2*Jp + B2p*J) + c.re*(B1*Jp + B1p*J);
|
|
z+=(a*y*Depth);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// integrals that need to be evaluated over all elements,
|
|
// regardless of which elements are actually selected.
|
|
if(bMaskIntegral)
|
|
{
|
|
a=ElmArea(i)*pow(LengthConv[LengthUnits],2.);
|
|
if(ProblemType==1){
|
|
for(k=0;k<3;k++)
|
|
r[k]=meshnode[meshelem[i].p[k]].x*LengthConv[LengthUnits];
|
|
R=(r[0]+r[1]+r[2])/3.;
|
|
a*=(2.*PI*R);
|
|
}
|
|
else a*=Depth;
|
|
|
|
switch(inttype){
|
|
|
|
case 18: // x (or r) direction Henrotte force, SS part.
|
|
if(ProblemType!=0) break;
|
|
|
|
B1=meshelem[i].B1;
|
|
B2=meshelem[i].B2;
|
|
c=HenrotteVector(i);
|
|
y=(((B1*conj(B1)) - (B2*conj(B2)))*Re(c) + 2.*Re(B1*conj(B2))*Im(c))/(2.*muo);
|
|
if(Frequency!=0) y/=2.;
|
|
|
|
y*=AECF(i); // correction for axisymmetric external region;
|
|
|
|
z+=(a*y);
|
|
break;
|
|
|
|
case 19: // y (or z) direction Henrotte force, SS part.
|
|
|
|
B1=meshelem[i].B1;
|
|
B2=meshelem[i].B2;
|
|
c=HenrotteVector(i);
|
|
|
|
y=(((B2*conj(B2)) - (B1*conj(B1)))*Im(c) + 2.*Re(B1*conj(B2))*Re(c))/(2.*muo);
|
|
|
|
y*=AECF(i); // correction for axisymmetric external region;
|
|
|
|
if(Frequency!=0) y/=2.;
|
|
z+=(a*y);
|
|
|
|
break;
|
|
|
|
case 20: // x (or r) direction Henrotte force, 2x part.
|
|
|
|
if(ProblemType!=0) break;
|
|
B1=meshelem[i].B1;
|
|
B2=meshelem[i].B2;
|
|
c=HenrotteVector(i);
|
|
z+=a*((((B1*B1) - (B2*B2))*Re(c) + 2.*B1*B2*Im(c))/(4.*muo)) * AECF(i);
|
|
|
|
break;
|
|
|
|
case 21: // y (or z) direction Henrotte force, 2x part.
|
|
|
|
B1=meshelem[i].B1;
|
|
B2=meshelem[i].B2;
|
|
c=HenrotteVector(i);
|
|
z+= a*((((B2*B2) - (B1*B1))*Im(c) + 2.*B1*B2*Re(c))/(4.*muo)) * AECF(i);
|
|
|
|
break;
|
|
|
|
case 22: // Henrotte torque, SS part.
|
|
if(ProblemType!=0) break;
|
|
B1=meshelem[i].B1;
|
|
B2=meshelem[i].B2;
|
|
c=HenrotteVector(i);
|
|
|
|
F1 = (((B1*conj(B1)) - (B2*conj(B2)))*Re(c) +
|
|
2.*Re(B1*conj(B2))*Im(c))/(2.*muo);
|
|
F2 = (((B2*conj(B2)) - (B1*conj(B1)))*Im(c) +
|
|
2.*Re(B1*conj(B2))*Re(c))/(2.*muo);
|
|
|
|
for(c=0,k=0;k<3;k++)
|
|
c+=meshnode[meshelem[i].p[k]].CC()*LengthConv[LengthUnits]/3.;
|
|
|
|
y=Re(c)*F2 -Im(c)*F1;
|
|
if(Frequency!=0) y/=2.;
|
|
y*=AECF(i);
|
|
z+=(a*y);
|
|
|
|
break;
|
|
|
|
case 23: // Henrotte torque, 2x part.
|
|
|
|
if(ProblemType!=0) break;
|
|
B1=meshelem[i].B1;
|
|
B2=meshelem[i].B2;
|
|
c=HenrotteVector(i);
|
|
F1 = (((B1*B1) - (B2*B2))*Re(c) + 2.*B1*B2*Im(c))/(4.*muo);
|
|
F2 = (((B2*B2) - (B1*B1))*Im(c) + 2.*B1*B2*Re(c))/(4.*muo);
|
|
|
|
for(c=0,k=0;k<3;k++)
|
|
c+=meshnode[meshelem[i].p[k]].CC()*LengthConv[LengthUnits]/3;
|
|
|
|
z+=a*(Re(c)*F2 -Im(c)*F1)*AECF(i);
|
|
|
|
break;
|
|
|
|
case 25: // x (or r) direction Henrotte force, 1x part for incremental AC problems
|
|
|
|
if(ProblemType!=0) break;
|
|
B1=meshelem[i].B1;
|
|
B2=meshelem[i].B2;
|
|
B1p=meshelem[i].B1p;
|
|
B2p=meshelem[i].B2p;
|
|
c=HenrotteVector(i);
|
|
z+=a*((B1*B1p - B2*B2p)*Re(c) + (B1p*B2 + B1*B2p)*Im(c))/muo * AECF(i);
|
|
|
|
break;
|
|
|
|
case 26: // y (or z) direction Henrotte force, 1x part for incremental AC problems
|
|
|
|
B1=meshelem[i].B1;
|
|
B2=meshelem[i].B2;
|
|
B1p=meshelem[i].B1p;
|
|
B2p=meshelem[i].B2p;
|
|
c=HenrotteVector(i);
|
|
z+=a*((B1p*B2 + B1*B2p)*Re(c) + (-(B1*B1p) + B2*B2p)*Im(c))/muo * AECF(i);
|
|
|
|
break;
|
|
|
|
case 27: // Henrotte torque, 1x part for incremental AC problems
|
|
|
|
if(ProblemType!=0) break;
|
|
B1=meshelem[i].B1;
|
|
B2=meshelem[i].B2;
|
|
B1p=meshelem[i].B1p;
|
|
B2p=meshelem[i].B2p;
|
|
c=HenrotteVector(i);
|
|
F1 = ((B1*B1p - B2*B2p)*Re(c) + (B1p*B2 + B1*B2p)*Im(c))/muo;
|
|
F2 = ((B1p*B2 + B1*B2p)*Re(c) + (-(B1*B1p) + B2*B2p)*Im(c))/muo;
|
|
|
|
for(c=0,k=0;k<3;k++)
|
|
c+=meshnode[meshelem[i].p[k]].CC()*LengthConv[LengthUnits]/3;
|
|
|
|
z+=a*(Re(c)*F2 -Im(c)*F1)*AECF(i);
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return z;
|
|
}
|
|
|
|
void CFemmviewDoc::LineIntegral(int inttype, CComplex *z)
|
|
{
|
|
// inttype Integral
|
|
// 0 B.n
|
|
// 1 H.t
|
|
// 2 Contour length
|
|
// 3 Stress Tensor Force
|
|
// 4 Stress Tensor Torque
|
|
// 5 (B.n)^2
|
|
|
|
// inttype==0 => B.n
|
|
if(inttype==0){
|
|
CComplex a0,a1;
|
|
CPointVals u;
|
|
double l;
|
|
int i,k;
|
|
|
|
k=(int) contour.GetSize();
|
|
GetPointValues(contour[0].re,contour[0].im, u);
|
|
a0=u.A;
|
|
GetPointValues(contour[k-1].re,contour[k-1].im,u);
|
|
a1=u.A;
|
|
if(ProblemType==0){
|
|
for(i=0,l=0;i<k-1;i++)
|
|
l+=abs(contour[i+1]-contour[i]);
|
|
l*=LengthConv[LengthUnits];
|
|
z[0] = (a0-a1)*Depth;
|
|
if(l!=0) z[1]= z[0]/(l*Depth);
|
|
}
|
|
else{
|
|
for(i=0,l=0;i<k-1;i++)
|
|
l+=(PI*(contour[i].re+contour[i+1].re)*
|
|
abs(contour[i+1]-contour[i]));
|
|
l*=pow(LengthConv[LengthUnits],2.);
|
|
z[0]= a1-a0;
|
|
if(l!=0) z[1]= z[0]/l;
|
|
}
|
|
}
|
|
|
|
// inttype==1 => H.t
|
|
if(inttype==1){
|
|
CComplex n,t,pt,Ht;
|
|
CPointVals v;
|
|
double dz,u,l;
|
|
int i,j,k,m,elm;
|
|
int NumPlotPoints=d_LineIntegralPoints;
|
|
BOOL flag;
|
|
|
|
z[0]=0;
|
|
for(k=1;k<contour.GetSize();k++)
|
|
{
|
|
dz=abs(contour[k]-contour[k-1])/((double) NumPlotPoints);
|
|
for(i=0,elm=-1;i<NumPlotPoints;i++)
|
|
{
|
|
u=(((double) i)+0.5)/((double) NumPlotPoints);
|
|
pt=contour[k-1] + u*(contour[k] - contour[k-1]);
|
|
t=contour[k]-contour[k-1];
|
|
t/=abs(t);
|
|
n=I*t;
|
|
pt+=n*1.e-06;
|
|
|
|
if (elm<0) elm=InTriangle(pt.re,pt.im);
|
|
else if (InTriangleTest(pt.re,pt.im,elm)==FALSE)
|
|
{
|
|
flag=FALSE;
|
|
for(j=0;j<3;j++)
|
|
for(m=0;m<NumList[meshelem[elm].p[j]];m++)
|
|
{
|
|
elm=ConList[meshelem[elm].p[j]][m];
|
|
if (InTriangleTest(pt.re,pt.im,elm)==TRUE)
|
|
{
|
|
flag=TRUE;
|
|
m=100;
|
|
j=3;
|
|
}
|
|
}
|
|
if (flag==FALSE) elm=InTriangle(pt.re,pt.im);
|
|
}
|
|
if(elm>=0)
|
|
flag=GetPointValues(pt.re,pt.im,elm,v);
|
|
else flag=FALSE;
|
|
|
|
if(flag==TRUE){
|
|
Ht = t.re*v.H1 + t.im*v.H2;
|
|
z[0]+=(Ht*dz*LengthConv[LengthUnits]);
|
|
}
|
|
}
|
|
|
|
|
|
for(i=0,l=0;i<contour.GetSize()-1;i++)
|
|
l+=abs(contour[i+1]-contour[i]);
|
|
l*=LengthConv[LengthUnits];
|
|
if(l!=0) z[1]=z[0]/l;
|
|
}
|
|
}
|
|
|
|
// inttype==2 => Contour Length
|
|
if(inttype==2){
|
|
int i,k;
|
|
k=(int) contour.GetSize();
|
|
for(i=0,z[0].re=0;i<k-1;i++)
|
|
z[0].re+=abs(contour[i+1]-contour[i]);
|
|
z[0].re*=LengthConv[LengthUnits];
|
|
|
|
if(ProblemType==1){
|
|
for(i=0,z[0].im=0;i<k-1;i++)
|
|
z[0].im+=(PI*(contour[i].re+contour[i+1].re)*
|
|
abs(contour[i+1]-contour[i]));
|
|
z[0].im*=pow(LengthConv[LengthUnits],2.);
|
|
}
|
|
else{
|
|
z[0].im=z[0].re*Depth;
|
|
}
|
|
}
|
|
|
|
// inttype==3 => Stress Tensor Force
|
|
if(inttype==3){
|
|
CComplex n,t,pt,Hn,Bn,BH,dF1,dF2;
|
|
CPointVals v;
|
|
double dz,dza,u;
|
|
int i,j,k,m,elm;
|
|
int NumPlotPoints=d_LineIntegralPoints;
|
|
BOOL flag;
|
|
|
|
for(i=0;i<4;i++) z[i]=0;
|
|
|
|
for(k=1;k<contour.GetSize();k++)
|
|
{
|
|
dz=abs(contour[k]-contour[k-1])/((double) NumPlotPoints);
|
|
for(i=0,elm=-1;i<NumPlotPoints;i++)
|
|
{
|
|
u=(((double) i)+0.5)/((double) NumPlotPoints);
|
|
pt=contour[k-1] + u*(contour[k] - contour[k-1]);
|
|
t=contour[k]-contour[k-1];
|
|
t/=abs(t);
|
|
n=I*t;
|
|
pt+=n*1.e-06;
|
|
|
|
if (elm<0) elm=InTriangle(pt.re,pt.im);
|
|
else if (InTriangleTest(pt.re,pt.im,elm)==FALSE)
|
|
{
|
|
flag=FALSE;
|
|
for(j=0;j<3;j++)
|
|
for(m=0;m<NumList[meshelem[elm].p[j]];m++)
|
|
{
|
|
elm=ConList[meshelem[elm].p[j]][m];
|
|
if (InTriangleTest(pt.re,pt.im,elm)==TRUE)
|
|
{
|
|
flag=TRUE;
|
|
m=100;
|
|
j=3;
|
|
}
|
|
}
|
|
if (flag==FALSE) elm=InTriangle(pt.re,pt.im);
|
|
}
|
|
if(elm>=0)
|
|
flag=GetPointValues(pt.re,pt.im,elm,v);
|
|
else flag=FALSE;
|
|
|
|
if(flag==TRUE)
|
|
if(Frequency==0){
|
|
Hn= n.re*v.H1 + n.im*v.H2;
|
|
Bn= n.re*v.B1 + n.im*v.B2;
|
|
BH= v.B1*v.H1 + v.B2*v.H2;
|
|
dF1=v.H1*Bn + v.B1*Hn - n.re*BH;
|
|
dF2=v.H2*Bn + v.B2*Hn - n.im*BH;
|
|
|
|
dza=dz*LengthConv[LengthUnits];
|
|
if(ProblemType==1){
|
|
dza*=2.*PI*pt.re*LengthConv[LengthUnits];
|
|
dF1=0;
|
|
}
|
|
else dza*=Depth;
|
|
|
|
z[0]+=(dF1*dza/2.);
|
|
z[1]+=(dF2*dza/2.);
|
|
}
|
|
else{
|
|
Hn=n.re*v.H1 + n.im*v.H2;
|
|
Bn=n.re*v.B1 + n.im*v.B2;
|
|
BH = v.B1*v.H1 + v.B2*v.H2;
|
|
dF1 = v.H1*Bn + v.B1*Hn - n.re*BH;
|
|
dF2 = v.H2*Bn + v.B2*Hn - n.im*BH;
|
|
|
|
dza=dz*LengthConv[LengthUnits];
|
|
if(ProblemType==1){
|
|
dza*=2.*PI*pt.re*LengthConv[LengthUnits];
|
|
dF1=0;
|
|
}
|
|
else dza*=Depth;
|
|
|
|
z[0]+=(dF1*dza/4.);
|
|
z[1]+=(dF2*dza/4.);
|
|
|
|
BH = v.B1*v.H1.Conj() +v.B2*v.H2.Conj();
|
|
|
|
if (ProblemType!=1)
|
|
dF1 = v.H1*Bn.Conj() + v.B1*Hn.Conj() - n.re*BH;
|
|
dF2= v.H2*Bn.Conj() + v.B2*Hn.Conj() - n.im*BH;
|
|
|
|
|
|
z[2]+=(dF1*dza/4.);
|
|
z[3]+=(dF2*dza/4.);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// inttype==4 => Stress Tensor Torque
|
|
if(inttype==4){
|
|
CComplex n,t,pt,Hn,Bn,BH,dF1,dF2,dT;
|
|
CPointVals v;
|
|
double dz,dza,u;
|
|
int i,j,k,m,elm;
|
|
int NumPlotPoints=d_LineIntegralPoints;
|
|
BOOL flag;
|
|
|
|
for(i=0;i<2;i++) z[i].Set(0,0);
|
|
|
|
for(k=1;k<contour.GetSize();k++)
|
|
{
|
|
dz=abs(contour[k]-contour[k-1])/((double) NumPlotPoints);
|
|
for(i=0,elm=-1;i<NumPlotPoints;i++)
|
|
{
|
|
u=(((double) i)+0.5)/((double) NumPlotPoints);
|
|
pt=contour[k-1]+ u*(contour[k] - contour[k-1]);
|
|
t=contour[k]-contour[k-1];
|
|
t/=abs(t);
|
|
n=I*t;
|
|
pt+=n*1.e-6;
|
|
|
|
if (elm<0) elm=InTriangle(pt.re,pt.im);
|
|
else if (InTriangleTest(pt.re,pt.im,elm)==FALSE)
|
|
{
|
|
flag=FALSE;
|
|
for(j=0;j<3;j++)
|
|
for(m=0;m<NumList[meshelem[elm].p[j]];m++)
|
|
{
|
|
elm=ConList[meshelem[elm].p[j]][m];
|
|
if (InTriangleTest(pt.re,pt.im,elm)==TRUE)
|
|
{
|
|
flag=TRUE;
|
|
m=100;
|
|
j=3;
|
|
}
|
|
}
|
|
if (flag==FALSE) elm=InTriangle(pt.re,pt.im);
|
|
}
|
|
if(elm>=0)
|
|
flag=GetPointValues(pt.re,pt.im,elm,v);
|
|
else flag=FALSE;
|
|
|
|
if(flag==TRUE)
|
|
if(Frequency==0){
|
|
Hn= n.re*v.H1 + n.im*v.H2;
|
|
Bn= n.re*v.B1 + n.im*v.B2;
|
|
BH= v.B1*v.H1 + v.B2*v.H2;
|
|
dF1=v.H1*Bn + v.B1*Hn - n.re*BH;
|
|
dF2=v.H2*Bn + v.B2*Hn - n.im*BH;
|
|
dT= pt.re*dF2 - dF1*pt.im;
|
|
dza=dz*LengthConv[LengthUnits]*LengthConv[LengthUnits];
|
|
|
|
z[0]+=(dT*dza*Depth/2.);
|
|
}
|
|
else{
|
|
Hn=n.re*v.H1 + n.im*v.H2;
|
|
Bn=n.re*v.B1 + n.im*v.B2;
|
|
BH = v.B1*v.H1 + v.B2*v.H2;
|
|
dF1 = v.H1*Bn + v.B1*Hn - n.re*BH;
|
|
dF2 = v.H2*Bn + v.B2*Hn - n.im*BH;
|
|
dT=pt.re*dF2 - dF1*pt.im;
|
|
dza=dz*LengthConv[LengthUnits]*LengthConv[LengthUnits];
|
|
|
|
z[0]+=(dT*dza*Depth/4.);
|
|
|
|
BH = v.B1*v.H1.Conj() +v.B2*v.H2.Conj();
|
|
dF1 = v.H1*Bn.Conj() + v.B1*Hn.Conj() - n.re*BH;
|
|
dF2= v.H2*Bn.Conj() + v.B2*Hn.Conj() - n.im*BH;
|
|
dT= pt.re*dF2 - dF1*pt.im ;
|
|
|
|
z[1]+=(dT*dza*Depth/4.);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// inttype==5 => (B.n)^2
|
|
if(inttype==5){
|
|
CComplex n,t,pt,Ht;
|
|
CPointVals v;
|
|
double dz,u,l;
|
|
int i,j,k,m,elm;
|
|
int NumPlotPoints=d_LineIntegralPoints;
|
|
BOOL flag;
|
|
|
|
z[0]=0;
|
|
for(k=1;k<contour.GetSize();k++)
|
|
{
|
|
dz=abs(contour[k]-contour[k-1])/((double) NumPlotPoints);
|
|
for(i=0,elm=-1;i<NumPlotPoints;i++)
|
|
{
|
|
u=(((double) i)+0.5)/((double) NumPlotPoints);
|
|
pt=contour[k-1] + u*(contour[k] - contour[k-1]);
|
|
t=contour[k]-contour[k-1];
|
|
t/=abs(t);
|
|
n=I*t;
|
|
pt+=n*1.e-06;
|
|
|
|
if (elm<0) elm=InTriangle(pt.re,pt.im);
|
|
else if (InTriangleTest(pt.re,pt.im,elm)==FALSE)
|
|
{
|
|
flag=FALSE;
|
|
for(j=0;j<3;j++)
|
|
for(m=0;m<NumList[meshelem[elm].p[j]];m++)
|
|
{
|
|
elm=ConList[meshelem[elm].p[j]][m];
|
|
if (InTriangleTest(pt.re,pt.im,elm)==TRUE)
|
|
{
|
|
flag=TRUE;
|
|
m=100;
|
|
j=3;
|
|
}
|
|
}
|
|
if (flag==FALSE) elm=InTriangle(pt.re,pt.im);
|
|
}
|
|
if(elm>=0)
|
|
flag=GetPointValues(pt.re,pt.im,elm,v);
|
|
else flag=FALSE;
|
|
|
|
if(flag==TRUE){
|
|
Ht = n.re*v.B1 + n.im*v.B2;
|
|
z[0]+=(Ht*Ht.Conj()*dz*LengthConv[LengthUnits]);
|
|
}
|
|
}
|
|
|
|
|
|
for(i=0,l=0;i<contour.GetSize()-1;i++)
|
|
l+=abs(contour[i+1]-contour[i]);
|
|
l*=LengthConv[LengthUnits];
|
|
if(l!=0) z[1]=z[0]/l;
|
|
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
int CFemmviewDoc::ClosestArcSegment(double x, double y)
|
|
{
|
|
double d0,d1;
|
|
int i,j;
|
|
|
|
if(arclist.GetSize()==0) return -1;
|
|
|
|
j=0;
|
|
d0=ShortestDistanceFromArc(CComplex(x,y),arclist[0]);
|
|
for(i=0;i<arclist.GetSize();i++){
|
|
d1=ShortestDistanceFromArc(CComplex(x,y),arclist[i]);
|
|
if(d1<d0){
|
|
d0=d1;
|
|
j=i;
|
|
}
|
|
}
|
|
|
|
return j;
|
|
}
|
|
|
|
void CFemmviewDoc::GetCircle(CArcSegment &arc,CComplex &c, double &R)
|
|
{
|
|
CComplex a0,a1,t;
|
|
double d,tta;
|
|
|
|
a0.Set(nodelist[arc.n0].x,nodelist[arc.n0].y);
|
|
a1.Set(nodelist[arc.n1].x,nodelist[arc.n1].y);
|
|
d=abs(a1-a0); // distance between arc endpoints
|
|
|
|
// figure out what the radius of the circle is...
|
|
t=(a1-a0)/d;
|
|
tta=arc.ArcLength*PI/180.;
|
|
R=d/(2.*sin(tta/2.));
|
|
c=a0 + (d/2. + I*sqrt(R*R-d*d/4.))*t; // center of the arc segment's circle...
|
|
}
|
|
|
|
double CFemmviewDoc::ShortestDistanceFromArc(CComplex p, CArcSegment &arc)
|
|
{
|
|
double R,d,l,z;
|
|
CComplex a0,a1,c,t;
|
|
|
|
a0.Set(nodelist[arc.n0].x,nodelist[arc.n0].y);
|
|
a1.Set(nodelist[arc.n1].x,nodelist[arc.n1].y);
|
|
GetCircle(arc,c,R);
|
|
d=abs(p-c);
|
|
|
|
if(d==0) return R;
|
|
|
|
t=(p-c)/d;
|
|
l=abs(p-c-R*t);
|
|
z=arg(t/(a0-c))*180/PI;
|
|
if ((z>0) && (z<arc.ArcLength)) return l;
|
|
|
|
z=abs(p-a0);
|
|
l=abs(p-a1);
|
|
if(z<l) return z;
|
|
return l;
|
|
}
|
|
|
|
double CFemmviewDoc::ShortestDistanceFromSegment(double p, double q, int segm)
|
|
{
|
|
double t,x[3],y[3];
|
|
|
|
x[0]=nodelist[linelist[segm].n0].x;
|
|
y[0]=nodelist[linelist[segm].n0].y;
|
|
x[1]=nodelist[linelist[segm].n1].x;
|
|
y[1]=nodelist[linelist[segm].n1].y;
|
|
|
|
t=((p-x[0])*(x[1]-x[0]) + (q-y[0])*(y[1]-y[0]))/
|
|
((x[1]-x[0])*(x[1]-x[0]) + (y[1]-y[0])*(y[1]-y[0]));
|
|
|
|
if (t>1.) t=1.;
|
|
if (t<0.) t=0.;
|
|
|
|
x[2]=x[0]+t*(x[1]-x[0]);
|
|
y[2]=y[0]+t*(y[1]-y[0]);
|
|
|
|
return sqrt((p-x[2])*(p-x[2]) + (q-y[2])*(q-y[2]));
|
|
}
|
|
|
|
BOOL CFemmviewDoc::ScanPreferences()
|
|
{
|
|
FILE *fp;
|
|
CString fname;
|
|
|
|
fname=BinDir+"femmview.cfg";
|
|
|
|
fp=fopen(fname,"rt");
|
|
if (fp!=NULL)
|
|
{
|
|
BOOL flag=FALSE;
|
|
char s[1024];
|
|
char q[1024];
|
|
char *v;
|
|
|
|
// parse the file
|
|
while (fgets(s,1024,fp)!=NULL)
|
|
{
|
|
sscanf(s,"%s",q);
|
|
|
|
if( _strnicmp(q,"<LineIntegralPoints>",20)==0)
|
|
{
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&d_LineIntegralPoints);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<WeightingScheme>",12)==0)
|
|
{
|
|
v=StripKey(s);
|
|
int lastd_WeightingScheme=d_WeightingScheme;
|
|
sscanf(v,"%i",&d_WeightingScheme);
|
|
// update weighting scheme if the weighting scheme was changed in the prefs dialog.
|
|
if (lastd_WeightingScheme!=d_WeightingScheme)
|
|
{
|
|
WeightingScheme=d_WeightingScheme;
|
|
bHasMask=FALSE;
|
|
}
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<ShiftH>",8)==0)
|
|
{
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&d_ShiftH);
|
|
q[0]=NULL;
|
|
}
|
|
}
|
|
fclose(fp);
|
|
}
|
|
else return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void CFemmviewDoc::BendContour(double angle, double anglestep)
|
|
{
|
|
if (angle==0) return;
|
|
if (anglestep==0) anglestep=1;
|
|
|
|
int k,n;
|
|
double d,tta,dtta,R;
|
|
CComplex c,a0,a1;
|
|
|
|
// check to see if there are at least enough
|
|
// points to have made one line;
|
|
k=(int) contour.GetSize()-1;
|
|
if (k<1) return;
|
|
|
|
// restrict the angle of the contour to 180 degrees;
|
|
if ((angle<-180.) || (angle>180.)) return;
|
|
n=(int) ceil(fabs(angle/anglestep));
|
|
tta=angle*PI/180.;
|
|
dtta=tta/((double) n);
|
|
|
|
// pop last point off of the contour;
|
|
a1=contour[k];
|
|
contour.RemoveAt(k);
|
|
a0=contour[k-1];
|
|
|
|
// compute location of arc center;
|
|
// and radius of the circle that the
|
|
// arc lives on.
|
|
d=abs(a1-a0);
|
|
R=d/(2.*sin(fabs(tta/2.)));
|
|
if(tta>0) c=a0 + (R/d)*(a1-a0)*exp(I*(PI-tta)/2.);
|
|
else c=a0+(R/d)*(a1-a0)*exp(-I*(PI+tta)/2.);
|
|
|
|
// add the points on the contour
|
|
for(k=1;k<=n;k++) contour.Add(c+(a0-c)*exp(k*I*dtta));
|
|
}
|
|
|
|
|
|
BOOL CFemmviewDoc::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
|
|
{
|
|
// TODO: Add your specialized code here and/or call the base class
|
|
if (bLinehook!=FALSE) return TRUE;
|
|
return CDocument::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
|
|
}
|
|
|
|
CComplex CFemmviewDoc::GetStrandedVoltageDrop(int lbl)
|
|
{
|
|
// Derive the voltage drop associated with a stranded and
|
|
// current-carrying region.
|
|
|
|
int i,k;
|
|
CComplex dVolts,rho;
|
|
CComplex A[3],J[3],U[3],V[3];
|
|
double a,atot;
|
|
double r[3];
|
|
|
|
U[0]=1; U[1]=1; U[2]=1;
|
|
|
|
for(i=0,dVolts=0,atot=0;i<meshelem.GetSize();i++)
|
|
{
|
|
if(meshelem[i].lbl==lbl)
|
|
{
|
|
rho=blocklist[meshelem[i].lbl].o*1.e6;
|
|
if(Frequency==0) rho=Re(rho);
|
|
if (rho!=0) rho=(1./rho);
|
|
|
|
GetJA(i,J,A);
|
|
a=ElmArea(i)*LengthConv[LengthUnits]*LengthConv[LengthUnits];
|
|
atot+=a;
|
|
|
|
if(ProblemType==AXISYMMETRIC){
|
|
for(k=0;k<3;k++)
|
|
r[k]=meshnode[meshelem[i].p[k]].x*LengthConv[LengthUnits];
|
|
}
|
|
|
|
for(k=0;k<3;k++) V[k]=(2.*PI*I*Frequency*A[k] + rho*J[k]);
|
|
if(ProblemType==PLANAR) dVolts+=PlnInt(a,V,U)*Depth;
|
|
else dVolts+=AxiInt(a,V,U,r);
|
|
}
|
|
}
|
|
dVolts*=( ((double) blocklist[lbl].Turns) / atot);
|
|
|
|
return dVolts;
|
|
}
|
|
|
|
|
|
void CFemmviewDoc::GetFillFactor(int lbl)
|
|
{
|
|
// Get the fill factor associated with a stranded and
|
|
// current-carrying region. For AC problems, also compute
|
|
// the apparent conductivity and permeability for use in
|
|
// post-processing the voltage.
|
|
|
|
CMaterialProp* bp= &blockproplist[blocklist[lbl].BlockType];
|
|
CBlockLabel* bl= &blocklist[lbl];
|
|
double lc=LengthConv[LengthUnits]*LengthConv[LengthUnits];
|
|
double atot,awire,w,d,o,fill,dd,W,R,c1,c2,c3,c4;
|
|
int i,wiretype;
|
|
CComplex ufd,ueff,ofd;
|
|
|
|
// default values
|
|
if (abs(bl->Turns)>1)
|
|
bl->FillFactor=1;
|
|
else
|
|
bl->FillFactor=-1;
|
|
bl->o=bp->Cduct;
|
|
bl->mu=0.;
|
|
|
|
if (blockproplist[blocklist[lbl].BlockType].LamType<3) return;
|
|
|
|
// compute total area of associated block
|
|
for(i=0,atot=0;i<meshelem.GetSize();i++)
|
|
if(meshelem[i].lbl==lbl) atot+=ElmArea(i)*lc;
|
|
if (atot==0) return;
|
|
|
|
wiretype=bp->LamType-3;
|
|
// wiretype = 0 for magnet wire
|
|
// wiretype = 1 for stranded but non-litz wire
|
|
// wiretype = 2 for litz wire
|
|
// wiretype = 3 for rectangular wire
|
|
// wiretype = 4 for 10% CCA
|
|
// wiretype = 5 for 15% CCA
|
|
|
|
if(wiretype==3) // rectangular wire
|
|
{
|
|
w=2.*PI*Frequency;
|
|
d=bp->WireD*0.001;
|
|
bl->FillFactor=fabs(d*d*((double) bl->Turns)/atot);
|
|
dd=d/sqrt(bl->FillFactor); // foil pitch
|
|
fill=d/dd; // fill for purposes of equivalent foil analysis
|
|
o=bp->Cduct*fill*1.e6; // effective foil conductivity in S/m
|
|
W=w*o*muo*d*d*fill/4.;
|
|
if((Frequency==0) || (bp->Cduct==0))
|
|
{
|
|
bl->o = bp->Cduct*bl->FillFactor;
|
|
bl->LocalEnergy = (dd-d)*dd*muo/6.;
|
|
bl->mu = 1;
|
|
return;
|
|
}
|
|
|
|
// effective permeability for the equivalent foil. Note that this is
|
|
// the same equation as effective permeability of a lamination...
|
|
ufd=muo*tanh(sqrt(I*W))/sqrt(I*W);
|
|
ueff=(fill*ufd+(1.-fill)*muo);
|
|
bl->o= 1./(muo/(fill*o*ufd) + I*dd*dd*(1.-fill)*muo*w/4. - I*dd*dd*ueff*w/12.);
|
|
bl->o*=1.e-6; // represent conductivity in units of MS/m for consistency with other parts of code.
|
|
bl->mu=ueff/muo;
|
|
|
|
// Treat local stored energy separately because it becomes ill-posed as frequency goes to zero.
|
|
// use an approximate expression at low frequency.
|
|
|
|
if (W > 0.1)
|
|
{
|
|
// normal higher-frequency regime
|
|
bl->LocalEnergy = (1.e-6)*Im(1/bl->o)/w;
|
|
}
|
|
else{
|
|
// low-frequency asymptotic expression from Mathematica series expansion
|
|
bl->LocalEnergy =muo*((dd-d)*dd/6. + (2./189.)*d*dd*W*W);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// procedure for round wires;
|
|
|
|
switch (wiretype)
|
|
{
|
|
// wiretype = 1 for stranded but non-litz wire
|
|
case 1:
|
|
R=bp->WireD*0.0005*sqrt((double) bp->NStrands);
|
|
awire=PI*R*R*((double) bl->Turns);
|
|
break;
|
|
|
|
// wiretype = 2 for magnet wire, litz wire, CCA
|
|
default:
|
|
R=bp->WireD*0.0005;
|
|
awire=PI*R*R*((double) bp->NStrands)*((double) bl->Turns);
|
|
break;
|
|
}
|
|
bl->FillFactor=fabs(awire/atot);
|
|
fill=bl->FillFactor;
|
|
|
|
// preliminary definitions
|
|
w=2.*PI*Frequency; // frequency in rad/s
|
|
o=bp->Cduct*1.e6; // conductivity in S/m
|
|
W=w*o*muo*R*R/2.; // non-dimensionalized frequency
|
|
dd=(1.6494541661869013*R)/sqrt(fill); // foil pitch in equivalent foil geometry
|
|
|
|
// curve fits to FEA data for frequency-dependent permeabilty and conductivity
|
|
switch (wiretype)
|
|
{
|
|
case 0: // magnet wire
|
|
case 1: // plain stranded
|
|
case 2: // litz
|
|
|
|
c1=0.7756067409818643 + fill*(0.6873854335408803 + fill*(0.06841584481674128 -0.07143732702512284*fill));
|
|
c2=1.5*fill/c1;
|
|
c3=0.8824642871525136+fill*(-0.008605512994838827+fill*(0.7223208744682307-0.2157183942377177*fill));
|
|
c4=log(1.5299240194394943/sqrt(fill))-c3/3.;
|
|
break;
|
|
|
|
case 4: // 10% CCA
|
|
c1=0.7270741505617485 + 0.8902950067721367*fill + 0.11894736885885195*fill*fill - 0.12247276254503957*fill*fill*fill;
|
|
c2=0.006784920229549677 + 1.8942880489198526*fill - 1.3631438759519217*fill*fill + 0.504431701685587*fill*fill*fill;
|
|
c3=0.7879151117538901 - 0.7216375417404758*fill + 2.266562622770727*fill*fill - 1.1349603497265566*fill*fill*fill;
|
|
c4=1.6190358786364027 - 3.967461431323324*fill + 4.068458362148543*fill*fill - 1.7975534375694646*fill*fill*fill;
|
|
break;
|
|
|
|
case 5: // 15% CCA
|
|
c1=0.7486913529860821 + 0.9042845510838825*fill + 0.1361040321433224*fill*fill - 0.10652380745682069*fill*fill*fill;
|
|
c2=0.006790468527313965 + 1.8945509985370095*fill - 1.3643501010185972*fill*fill + 0.5036765577982594*fill*fill*fill;
|
|
c3=0.7519323306379909 - 0.7184130853903536*fill + 2.2551599408130594*fill*fill - 1.1439852083597326*fill*fill*fill;
|
|
c4=1.6204876714534728 - 3.966250827502031*fill + 4.064413095233383*fill*fill - 1.7940297437703776*fill*fill*fill;
|
|
break;
|
|
}
|
|
|
|
// can punch out early if no eddy current effects
|
|
if ((Frequency==0) || (bp->Cduct==0))
|
|
{
|
|
bl->o = bp->Cduct*fill;
|
|
bl->LocalEnergy = muo*(2*(c3 + 3*c4)*R*R/fill - dd*dd)/12;
|
|
bl->mu = 1.; // relative permeability of the block.
|
|
return;
|
|
}
|
|
|
|
// fit for frequency-dependent conductivity....
|
|
ufd=c2*(tanh(sqrt(c1*I*W))/sqrt(c1*I*W))+(1.-c2); // relative frequency-dependent permeability
|
|
bl->mu=ufd;
|
|
ofd=o*fill/(I*c4*W+sqrt(I*c3*W)*(1./tanh(sqrt(I*c3*W)))); // fit to curves in Skin4.nb
|
|
ofd=1./(1./ofd-I*w*ufd*muo*dd*dd/12.); // don't double-book local stored energy;
|
|
bl->o=ofd*1.e-6; // return frequency-dependent conductivity in MS/m
|
|
|
|
// Treat local stored energy separately because it becomes ill-posed as frequency goes to zero.
|
|
// use an approximate expression at low frequency.
|
|
if (W > 0.1)
|
|
{
|
|
// normal higher-frequency regime
|
|
bl->LocalEnergy = (1.e-6)*Im(1/bl->o)/w;
|
|
}
|
|
else{
|
|
// low-frequency asymptotic expression from Mathematica series expansion
|
|
bl->LocalEnergy =(muo*(21*dd*dd*fill*(-15 + 2*c1*c1*c2*W*W) +
|
|
2*R*R*(315*(c3 + 3*c4) - 2*c3*c3*c3*W*W)))/(3780.*fill);
|
|
}
|
|
}
|
|
|
|
CComplex CFemmviewDoc::GetStrandedLinkage(int lbl)
|
|
{
|
|
// This is a routine for the special case of determining
|
|
// the flux linkage of a stranded conductor at zero frequency
|
|
// when the conductor is carrying zero current.
|
|
int i,k;
|
|
CComplex FluxLinkage;
|
|
CComplex A[3],J[3],U[3],V[3];
|
|
double a,atot;
|
|
double r[3];
|
|
|
|
U[0]=1; U[1]=1; U[2]=1;
|
|
|
|
for(i=0,FluxLinkage=0,atot=0;i<meshelem.GetSize();i++)
|
|
{
|
|
if(meshelem[i].lbl==lbl)
|
|
{
|
|
GetJA(i,J,A);
|
|
a=ElmArea(i)*LengthConv[LengthUnits]*LengthConv[LengthUnits];
|
|
atot+=a;
|
|
|
|
if(ProblemType==AXISYMMETRIC){
|
|
for(k=0;k<3;k++)
|
|
r[k]=meshnode[meshelem[i].p[k]].x*LengthConv[LengthUnits];
|
|
}
|
|
|
|
if(ProblemType==PLANAR) FluxLinkage+=PlnInt(a,A,U)*Depth;
|
|
else FluxLinkage+=AxiInt(a,A,U,r);
|
|
}
|
|
}
|
|
FluxLinkage*=( ((double) blocklist[lbl].Turns) / atot);
|
|
|
|
return FluxLinkage;
|
|
}
|
|
|
|
CComplex CFemmviewDoc::GetSolidAxisymmetricLinkage(int lbl)
|
|
{
|
|
// This is a routine for the special case of determining
|
|
// the flux linkage of a solid and axisymmetric conductor
|
|
// t zero frequency when the conductor is carrying zero
|
|
// current. The trick here is to take account of the distribution
|
|
// of the current that would be there, if there was any current.
|
|
// In solid axisymmetric regions, the inner radius of the
|
|
// region tends to carry a higher current density that the outer
|
|
// edges, because the length of conductor that the current has
|
|
// to traverse is smaller on the inner edge.
|
|
|
|
int i,k;
|
|
CComplex FluxLinkage;
|
|
CComplex Aa,A[3],J[3],U[3],V[3];
|
|
double a,atot,R;
|
|
double r[3];
|
|
|
|
U[0]=1; U[1]=1; U[2]=1;
|
|
|
|
for(i=0,FluxLinkage=0,atot=0;i<meshelem.GetSize();i++)
|
|
{
|
|
if(meshelem[i].lbl==lbl)
|
|
{
|
|
GetJA(i,J,A);
|
|
Aa=(A[0]+A[1]+A[2])/3.;
|
|
a=ElmArea(i)*LengthConv[LengthUnits]*LengthConv[LengthUnits];
|
|
|
|
for(k=0;k<3;k++)
|
|
r[k]=meshnode[meshelem[i].p[k]].x*LengthConv[LengthUnits];
|
|
R=(r[0]+r[1]+r[2])/3.;
|
|
|
|
atot+=a/R;
|
|
FluxLinkage+=2.*PI*R*a*(Aa/R);
|
|
}
|
|
}
|
|
FluxLinkage*=( ((double) blocklist[lbl].Turns) / atot);
|
|
|
|
return FluxLinkage;
|
|
}
|
|
|
|
CComplex CFemmviewDoc::GetParallelLinkage(int numcirc)
|
|
{
|
|
// routine for deducing the flux linkage of a "parallel-connected"
|
|
// "circuit" in the annoying special case in which the
|
|
// current carried in the circuit is zero and the frequency is zero.
|
|
// This routine takes care of the case in which the current is divvied
|
|
// up based on the conductivity and size of the various regions
|
|
|
|
int i,k;
|
|
CComplex FluxLinkage;
|
|
CComplex Aa,A[3],J[3],U[3],V[3];
|
|
double a,atot,R,c;
|
|
double r[3];
|
|
|
|
U[0]=1; U[1]=1; U[2]=1;
|
|
|
|
for(i=0,FluxLinkage=0,atot=0;i<meshelem.GetSize();i++)
|
|
{
|
|
if(blocklist[meshelem[i].lbl].InCircuit==numcirc)
|
|
{
|
|
c=blockproplist[meshelem[i].blk].Cduct;
|
|
GetJA(i,J,A);
|
|
a=ElmArea(i)*LengthConv[LengthUnits]*LengthConv[LengthUnits];
|
|
|
|
if(ProblemType==AXISYMMETRIC){
|
|
for(k=0;k<3;k++)
|
|
r[k]=meshnode[meshelem[i].p[k]].x*LengthConv[LengthUnits];
|
|
R=(r[0]+r[1]+r[2])/3.;
|
|
Aa=(A[0]+A[1]+A[2])/3.;
|
|
}
|
|
|
|
if(ProblemType==PLANAR){
|
|
FluxLinkage+=PlnInt(a,A,U)*Depth*c;
|
|
atot+=(a*c);
|
|
}
|
|
else
|
|
{
|
|
FluxLinkage+=2.*PI*R*c*(Aa/R);
|
|
atot+=(a*c/R);
|
|
}
|
|
}
|
|
}
|
|
FluxLinkage/=atot;
|
|
|
|
return FluxLinkage;
|
|
}
|
|
|
|
CComplex CFemmviewDoc::GetParallelLinkageAlt(int numcirc)
|
|
{
|
|
// routine for deducing the flux linkage of a "parallel-connected"
|
|
// "circuit" in the annoying special case in which the
|
|
// current carried in the circuit is zero and the frequency is zero.
|
|
// This routine takes care of the "punt" case in which all regions
|
|
// in the "circuit" have been assigned a zero conductivity.
|
|
// In this case, an even current density is applied to all regions
|
|
// that are marked with the circuit (for both axi and planar cases).
|
|
|
|
int i,k;
|
|
CComplex FluxLinkage;
|
|
CComplex Aa,A[3],J[3],U[3],V[3];
|
|
double a,atot,R,c;
|
|
double r[3];
|
|
|
|
U[0]=1; U[1]=1; U[2]=1;
|
|
|
|
for(i=0,FluxLinkage=0,atot=0;i<meshelem.GetSize();i++)
|
|
{
|
|
if(blocklist[meshelem[i].lbl].InCircuit==numcirc)
|
|
{
|
|
c=blockproplist[meshelem[i].blk].Cduct;
|
|
GetJA(i,J,A);
|
|
a=ElmArea(i)*LengthConv[LengthUnits]*LengthConv[LengthUnits];
|
|
atot+=a;
|
|
|
|
if(ProblemType==AXISYMMETRIC){
|
|
for(k=0;k<3;k++)
|
|
r[k]=meshnode[meshelem[i].p[k]].x*LengthConv[LengthUnits];
|
|
R=(r[0]+r[1]+r[2])/3.;
|
|
Aa=(A[0]+A[1]+A[2])/3.;
|
|
}
|
|
|
|
if(ProblemType==PLANAR) FluxLinkage+=PlnInt(a,A,U)*Depth;
|
|
else FluxLinkage+=AxiInt(a,A,U,r);
|
|
}
|
|
}
|
|
FluxLinkage/=atot;
|
|
|
|
return FluxLinkage;
|
|
}
|
|
|
|
CComplex CFemmviewDoc::GetVoltageDrop(int circnum)
|
|
{
|
|
int i;
|
|
CComplex Volts;
|
|
|
|
Volts=0;
|
|
|
|
// if the circuit is a "series" circuit...
|
|
if(circproplist[circnum].CircType==1)
|
|
{
|
|
for(i=0;i<blocklist.GetSize();i++)
|
|
{
|
|
if (blocklist[i].InCircuit==circnum)
|
|
{
|
|
// if this region is solid...
|
|
if (blocklist[i].Case==0)
|
|
{
|
|
// still need to multiply by turns, since it indicates
|
|
// the direction of the current;
|
|
if(ProblemType==AXISYMMETRIC)
|
|
Volts -= (2.*PI*blocklist[i].dVolts*blocklist[i].Turns);
|
|
else
|
|
Volts -= (Depth*blocklist[i].dVolts*blocklist[i].Turns);
|
|
}
|
|
// or if this region is stranded
|
|
else Volts+=GetStrandedVoltageDrop(i);
|
|
}
|
|
}
|
|
}
|
|
else if(circproplist[circnum].CircType==0)
|
|
{
|
|
// root through the block labels until
|
|
// we find one that gives us the voltage drop.
|
|
BOOL flag=FALSE;
|
|
for(i=0;i<blocklist.GetSize();i++)
|
|
{
|
|
if ((blocklist[i].InCircuit==circnum) && (blocklist[i].Case==0))
|
|
{
|
|
if(ProblemType==AXISYMMETRIC)
|
|
Volts -= (2.*PI*blocklist[i].dVolts);
|
|
else
|
|
Volts -= (Depth*blocklist[i].dVolts);
|
|
flag=TRUE;
|
|
i=(int) blocklist.GetSize();
|
|
}
|
|
}
|
|
|
|
// but perhaps no voltage was found. This could be a parallel circuit
|
|
// in which the conductivity in every block in the circuit is equal
|
|
// to zero. We can still have flux linkage and voltage drop here.
|
|
// have to root through things in a brute force way to get the voltage drop.
|
|
if(flag==FALSE)
|
|
{
|
|
int k;
|
|
CComplex FluxLinkage;
|
|
CComplex A[3],J[3],U[3];
|
|
double a,atot;
|
|
double r[3];
|
|
|
|
U[0]=1; U[1]=1; U[2]=1;
|
|
|
|
for(i=0,FluxLinkage=0,atot=0;i<meshelem.GetSize();i++)
|
|
{
|
|
if(blocklist[meshelem[i].lbl].InCircuit==circnum)
|
|
{
|
|
GetJA(i,J,A);
|
|
a=ElmArea(i)*LengthConv[LengthUnits]*LengthConv[LengthUnits];
|
|
atot+=a;
|
|
|
|
if(ProblemType==AXISYMMETRIC){
|
|
for(k=0;k<3;k++)
|
|
r[k]=meshnode[meshelem[i].p[k]].x*LengthConv[LengthUnits];
|
|
}
|
|
if(ProblemType==PLANAR)
|
|
FluxLinkage+=PlnInt(a,A,U)*Depth;
|
|
else FluxLinkage+=AxiInt(a,A,U,r);
|
|
}
|
|
}
|
|
Volts=(2.*PI*Frequency/atot)*FluxLinkage;
|
|
}
|
|
}
|
|
|
|
return Volts;
|
|
}
|
|
|
|
CComplex CFemmviewDoc::GetFluxLinkage(int circnum)
|
|
{
|
|
int i,k;
|
|
CComplex FluxLinkage;
|
|
CComplex A[3],J[3];
|
|
double a,r[3];
|
|
|
|
// in the "normal" case, we can just use Integral of A.J
|
|
// and divide through by i.conj to get the flux linkage.
|
|
if((circproplist[circnum].Amps.re!=0) || (circproplist[circnum].Amps.im!=0))
|
|
{
|
|
for(i=0,FluxLinkage=0;i<meshelem.GetSize();i++)
|
|
{
|
|
if(blocklist[meshelem[i].lbl].InCircuit==circnum)
|
|
{
|
|
GetJA(i,J,A);
|
|
a=ElmArea(i)*LengthConv[LengthUnits]*LengthConv[LengthUnits];
|
|
if(ProblemType==AXISYMMETRIC){
|
|
for(k=0;k<3;k++)
|
|
r[k]=meshnode[meshelem[i].p[k]].x*LengthConv[LengthUnits];
|
|
}
|
|
|
|
// for a multiturn region, there can be some "local" flux linkage due to the complex-valued
|
|
// part of the conductivity.
|
|
for(k=0;k<3;k++) A[k]+=J[k]*blocklist[meshelem[i].lbl].LocalEnergy;
|
|
|
|
for(k=0;k<3;k++) J[k]=J[k].Conj();
|
|
if(ProblemType==PLANAR) FluxLinkage+=PlnInt(a,A,J)*Depth;
|
|
else FluxLinkage+=AxiInt(a,A,J,r);
|
|
}
|
|
}
|
|
|
|
FluxLinkage/=conj(circproplist[circnum].Amps);
|
|
}
|
|
else{
|
|
// Rats! The circuit of interest is not carrying any current.
|
|
// However, the circuit can still have a non-zero flux linkage.
|
|
// due to mutual inductance. Now, we have to go through
|
|
// some annoying manipulations to back out the flux linkage.
|
|
|
|
// For a non-zero frequency, things aren't too bad. Any
|
|
// voltage that we have must be solely due to flux linkage.
|
|
// To get the flux linkage, just divide the voltage by the frequency.
|
|
if (Frequency!=0)
|
|
FluxLinkage=GetVoltageDrop(circnum)/(2.*I*PI*Frequency);
|
|
|
|
// The zero frequency case is the interesting one, because
|
|
// there are lots of annoying special cases.
|
|
else{
|
|
// First, deal with "series" circuits...
|
|
if(circproplist[circnum].CircType==1)
|
|
{
|
|
for(i=0,FluxLinkage=0;i<blocklist.GetSize();i++)
|
|
{
|
|
if(blocklist[i].InCircuit==circnum)
|
|
{
|
|
if((blocklist[i].Case==1) || (ProblemType==PLANAR))
|
|
FluxLinkage+=GetStrandedLinkage(i);
|
|
// in solid, axisymmetric case, the current distribution
|
|
// isn't even. We have to do some extra work to get
|
|
// the flux linkage in this case.
|
|
else FluxLinkage+=GetSolidAxisymmetricLinkage(i);
|
|
}
|
|
}
|
|
}
|
|
else{
|
|
BOOL flag;
|
|
|
|
// first, see whether some of the blocks have nonzero conductivity;
|
|
// flag=TRUE means that at least one of the blocks has a
|
|
// nonzero conductivity.
|
|
for(i=0,flag=FALSE;i<blocklist.GetSize();i++)
|
|
if((blocklist[i].Case==0) &&
|
|
(blocklist[i].InCircuit==circnum)) flag=TRUE;
|
|
|
|
// if there is at least one nonzero conductivity block, we can use
|
|
// the GetParallelLinkage routine, which is more or less driving
|
|
// all the blocks with a ficticious voltage gradient.
|
|
if (flag) FluxLinkage=GetParallelLinkage(i);
|
|
// otherwise, treat the "punt" case, where every part of the
|
|
// parallel "circuit" is just assumed to have the same applied
|
|
// current density;
|
|
else FluxLinkage=GetParallelLinkageAlt(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
return FluxLinkage;
|
|
}
|
|
|
|
void CFemmviewDoc::GetMagnetization(int n, CComplex &M1, CComplex &M2)
|
|
{
|
|
// Puts the piece-wise constant magnetization for an element into
|
|
// M1 and M2. The magnetization could be useful for some kinds of
|
|
// postprocessing, e.g. computation of field gradients by integrating
|
|
// gradient contributions from each non-air element;
|
|
|
|
CComplex mu1,mu2,Hc;
|
|
CComplex b1,b2;
|
|
|
|
b1=meshelem[n].B1;
|
|
b2=meshelem[n].B2;
|
|
Hc=0; mu1=0; mu2=0;
|
|
|
|
if(Frequency==0){
|
|
GetMu(Re(b1),Re(b2),mu1.re,mu2.re,n);
|
|
Hc=blockproplist[meshelem[n].blk].H_c*exp(I*meshelem[n].magdir*PI/180.);
|
|
}
|
|
else GetMu(b1,b2,mu1,mu2,n);
|
|
|
|
M1 = b1*(mu1-1)/(mu1*muo) + Re(Hc);
|
|
M2 = b2*(mu2-1)/(mu2*muo) + Im(Hc);
|
|
}
|
|
|
|
double CFemmviewDoc::AECF(int k)
|
|
{
|
|
// Computes the permeability correction factor for axisymmetric
|
|
// external regions. This is sort of a kludge, but it's the best
|
|
// way I could fit it in. The structure of the code wasn't really
|
|
// designed to have a permeability that varies with position in a
|
|
// continuous way.
|
|
|
|
if (!ProblemType) return 1.; // no correction for planar problems
|
|
if (!blocklist[meshelem[k].lbl].IsExternal) return 1; // only need to correct for external regions
|
|
|
|
double r=abs(meshelem[k].ctr-I*extZo);
|
|
return (r*r*extRi)/(extRo*extRo*extRo); // permeability gets divided by this factor;
|
|
}
|
|
|
|
// versions of GetMu that sort out whether or not the AECF should be applied,
|
|
// as well as the corrections required for wound regions.
|
|
void CFemmviewDoc::GetMu(CComplex b1, CComplex b2,CComplex &mu1, CComplex &mu2, int i)
|
|
{
|
|
if(blockproplist[meshelem[i].blk].LamType>2) // is a region subject to prox effects
|
|
{
|
|
mu1=blocklist[meshelem[i].lbl].mu;
|
|
mu2=mu1;
|
|
}
|
|
else blockproplist[meshelem[i].blk].GetMu(b1,b2,mu1,mu2);
|
|
|
|
double aecf=AECF(i); mu1/=aecf; mu2/=aecf;
|
|
}
|
|
|
|
void CFemmviewDoc::GetMu(double b1, double b2, double &mu1, double &mu2, int i)
|
|
{
|
|
blockproplist[meshelem[i].blk].GetMu(b1,b2,mu1,mu2);
|
|
double aecf=AECF(i); mu1/=aecf; mu2/=aecf;
|
|
}
|
|
|
|
void CFemmviewDoc::GetH(double b1, double b2, double &h1, double &h2, int k)
|
|
{
|
|
double mu1,mu2;
|
|
CComplex Hc;
|
|
|
|
GetMu(b1,b2,mu1,mu2,k);
|
|
h1 = b1/(mu1*muo);
|
|
h2 = b2/(mu2*muo);
|
|
if ((d_ShiftH) && (blockproplist[meshelem[k].blk].H_c!=0))
|
|
{
|
|
Hc = blockproplist[meshelem[k].blk].H_c*
|
|
exp(I*PI*meshelem[k].magdir/180.);
|
|
h1=h1-Re(Hc);
|
|
h2=h2-Im(Hc);
|
|
}
|
|
}
|
|
|
|
void CFemmviewDoc::GetH(CComplex b1, CComplex b2, CComplex &h1, CComplex &h2, int k)
|
|
{
|
|
CComplex mu1,mu2;
|
|
|
|
GetMu(b1,b2,mu1,mu2,k);
|
|
h1 = b1/(mu1*muo);
|
|
h2 = b2/(mu2*muo);
|
|
}
|
|
|
|
void CFemmviewDoc::FindBoundaryEdges()
|
|
{
|
|
int i, j;
|
|
static int plus1mod3[3] = {1, 2, 0};
|
|
static int minus1mod3[3] = {2, 0, 1};
|
|
|
|
// Init all elements' neigh to be unfinished.
|
|
for(i = 0; i < meshelem.GetSize(); i ++) {
|
|
for(j = 0; j < 3; j ++)
|
|
meshelem[i].n[j] = 0;
|
|
}
|
|
|
|
int orgi, desti;
|
|
int ei, ni;
|
|
BOOL done;
|
|
|
|
// Loop all elements, to find and set there neighs.
|
|
for(i = 0; i < meshelem.GetSize(); i ++) {
|
|
for(j = 0; j < 3; j ++) {
|
|
if(meshelem[i].n[j] == 0) {
|
|
// Get this edge's org and dest node index,
|
|
orgi = meshelem[i].p[plus1mod3[j]];
|
|
desti = meshelem[i].p[minus1mod3[j]];
|
|
done = FALSE;
|
|
// Find this edge's neigh from the org node's list
|
|
for(ni = 0; ni < NumList[orgi]; ni ++) {
|
|
// Find a Element around org node contained dest node of this edge.
|
|
ei = ConList[orgi][ni];
|
|
if(ei == i) continue; // Skip myself.
|
|
// Check this Element's 3 vert to see if there exist dest node.
|
|
if(meshelem[ei].p[0] == desti) {
|
|
done = TRUE;
|
|
break;
|
|
} else if(meshelem[ei].p[1] == desti) {
|
|
done = TRUE;
|
|
break;
|
|
} else if(meshelem[ei].p[2] == desti) {
|
|
done = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if(!done) {
|
|
// This edge must be a Boundary Edge.
|
|
meshelem[i].n[j] = 1;
|
|
}
|
|
} // Finish One Edge
|
|
} // End of One Element Loop
|
|
} // End of Main Loop
|
|
|
|
}
|
|
|
|
double CFemmviewDoc::ShortestDistance(double p, double q, int segm)
|
|
{
|
|
double t,x[3],y[3];
|
|
|
|
x[0]=nodelist[linelist[segm].n0].x;
|
|
y[0]=nodelist[linelist[segm].n0].y;
|
|
x[1]=nodelist[linelist[segm].n1].x;
|
|
y[1]=nodelist[linelist[segm].n1].y;
|
|
|
|
t=((p-x[0])*(x[1]-x[0]) + (q-y[0])*(y[1]-y[0]))/
|
|
((x[1]-x[0])*(x[1]-x[0]) + (y[1]-y[0])*(y[1]-y[0]));
|
|
|
|
if (t>1.) t=1.;
|
|
if (t<0.) t=0.;
|
|
|
|
x[2]=x[0]+t*(x[1]-x[0]);
|
|
y[2]=y[0]+t*(y[1]-y[0]);
|
|
|
|
return sqrt((p-x[2])*(p-x[2]) + (q-y[2])*(q-y[2]));
|
|
}
|
|
|
|
int CFemmviewDoc::ClosestSegment(double x, double y)
|
|
{
|
|
double d0,d1;
|
|
int i,j;
|
|
|
|
if(linelist.GetSize()==0) return -1;
|
|
|
|
j=0;
|
|
d0=ShortestDistance(x,y,0);
|
|
for(i=0;i<linelist.GetSize();i++){
|
|
d1=ShortestDistance(x,y,i);
|
|
if(d1<d0){
|
|
d0=d1;
|
|
j=i;
|
|
}
|
|
}
|
|
|
|
return j;
|
|
}
|
|
|
|
|
|
void CFemmviewDoc::GetGapValues(CXYPlot &p,int PlotType,int NumPlotPoints, int j)
|
|
{
|
|
double z,dz,tta,R;
|
|
CComplex br,bt,ac,hr,ht;
|
|
int i,k,n;
|
|
|
|
if(Frequency==0){
|
|
switch (PlotType)
|
|
{
|
|
case 0:
|
|
p.Create(NumPlotPoints,2);
|
|
if (ProblemType==0) strcpy(p.lbls[1],"Potential, Wb/m");
|
|
else strcpy(p.lbls[1],"Flux, Wb");
|
|
break;
|
|
case 1:
|
|
p.Create(NumPlotPoints,2);
|
|
strcpy(p.lbls[1],"|B|, Tesla");
|
|
break;
|
|
case 2:
|
|
p.Create(NumPlotPoints,2);
|
|
strcpy(p.lbls[1],"Br, Tesla");
|
|
break;
|
|
case 3:
|
|
p.Create(NumPlotPoints,2);
|
|
strcpy(p.lbls[1],"Bt, Tesla");
|
|
break;
|
|
case 4:
|
|
p.Create(NumPlotPoints,2);
|
|
strcpy(p.lbls[1],"|H|, Amp/m");
|
|
break;
|
|
case 5:
|
|
p.Create(NumPlotPoints,2);
|
|
strcpy(p.lbls[1],"Hr, Amp/m");
|
|
break;
|
|
case 6:
|
|
p.Create(NumPlotPoints,2);
|
|
strcpy(p.lbls[1],"Ht, Amp/m");
|
|
break;
|
|
default:
|
|
p.Create(NumPlotPoints,2);
|
|
break;
|
|
}
|
|
}
|
|
else{
|
|
switch (PlotType)
|
|
{
|
|
case 0:
|
|
p.Create(NumPlotPoints,4);
|
|
strcpy(p.lbls[1],"|A|, Wb/m");
|
|
strcpy(p.lbls[2],"Re[A], Wb/m");
|
|
strcpy(p.lbls[3],"Im[A], Wb/m");
|
|
break;
|
|
case 1:
|
|
p.Create(NumPlotPoints,2);
|
|
strcpy(p.lbls[1],"|B|, Tesla");
|
|
break;
|
|
case 2:
|
|
p.Create(NumPlotPoints,4);
|
|
strcpy(p.lbls[1],"|Br|, Tesla");
|
|
strcpy(p.lbls[2],"Re[Br], Tesla");
|
|
strcpy(p.lbls[3],"Im[Br], Tesla");
|
|
break;
|
|
case 3:
|
|
p.Create(NumPlotPoints,4);
|
|
strcpy(p.lbls[1],"|Bt|, Tesla");
|
|
strcpy(p.lbls[2],"Re[Bt], Tesla");
|
|
strcpy(p.lbls[3],"Im[Bt], Tesla");
|
|
break;
|
|
case 4:
|
|
p.Create(NumPlotPoints,2);
|
|
strcpy(p.lbls[1],"|H|, Amp/m");
|
|
break;
|
|
case 5:
|
|
p.Create(NumPlotPoints,4);
|
|
if(ProblemType==0){
|
|
strcpy(p.lbls[1],"|Hr|, Amp/m");
|
|
strcpy(p.lbls[2],"Re[Hr], Amp/m");
|
|
strcpy(p.lbls[3],"Im[Hr], Amp/m");
|
|
}
|
|
break;
|
|
case 6:
|
|
p.Create(NumPlotPoints,4);
|
|
strcpy(p.lbls[1],"|Ht|, Amp/m");
|
|
strcpy(p.lbls[2],"Re[Ht], Amp/m");
|
|
strcpy(p.lbls[3],"Im[Ht], Amp/m");
|
|
break;
|
|
default:
|
|
p.Create(NumPlotPoints,2);
|
|
break;
|
|
}
|
|
}
|
|
|
|
strcpy(p.lbls[0],"Angle, Degrees");
|
|
dz = 360./((double) (NumPlotPoints-1));
|
|
R = (agelist[j].ri + agelist[j].ro)/2.;
|
|
|
|
for(i=0,z=0;i<NumPlotPoints;i++,z+=dz)
|
|
{
|
|
p.M[i][0]=z;
|
|
|
|
tta=z*PI/180;
|
|
ac=0;
|
|
br=0;
|
|
bt=0;
|
|
for(k=0;k<agelist[j].nn;k++)
|
|
{
|
|
n=agelist[j].nh[k];
|
|
if (n>0)
|
|
{
|
|
ac+= R*(-agelist[j].brs[k]*cos(n*tta) + agelist[j].brc[k]*sin(n*tta))/((double) n);
|
|
}
|
|
else{
|
|
ac+=agelist[j].aco;
|
|
}
|
|
br += agelist[j].brc[k]*cos(n*tta) + agelist[j].brs[k]*sin(n*tta);
|
|
bt += agelist[j].btc[k]*cos(n*tta) + agelist[j].bts[k]*sin(n*tta);
|
|
}
|
|
hr=br/muo;
|
|
ht=bt/muo;
|
|
|
|
if (Frequency==0){
|
|
switch (PlotType){
|
|
case 0:
|
|
p.M[i][1]=Re(ac);
|
|
break;
|
|
case 1:
|
|
p.M[i][1]=Re(sqrt(br*conj(br) + bt*conj(bt)));
|
|
break;
|
|
case 2:
|
|
p.M[i][1]= Re(br);
|
|
break;
|
|
case 3:
|
|
p.M[i][1]= Re(bt);
|
|
break;
|
|
case 4:
|
|
p.M[i][1]=Re(sqrt(hr*conj(hr) + ht*conj(ht)));
|
|
break;
|
|
case 5:
|
|
p.M[i][1]= Re(hr);
|
|
break;
|
|
case 6:
|
|
p.M[i][1]= Re(ht);
|
|
break;
|
|
default:
|
|
p.M[i][1]=0;
|
|
break;
|
|
}
|
|
}
|
|
else{
|
|
switch (PlotType){
|
|
case 0:
|
|
p.M[i][1]=abs(ac);
|
|
p.M[i][2]=Re(ac);
|
|
p.M[i][3]=Im(ac);
|
|
break;
|
|
case 1:
|
|
p.M[i][1]=Re(sqrt(br*conj(br) + bt*conj(bt)));
|
|
break;
|
|
case 2:
|
|
p.M[i][2]=Re(br);
|
|
p.M[i][3]=Im(br);
|
|
p.M[i][1]=abs(br);
|
|
break;
|
|
case 3:
|
|
p.M[i][2]=Re(bt);
|
|
p.M[i][3]=Im(bt);
|
|
p.M[i][1]=abs(bt);
|
|
break;
|
|
case 4:
|
|
p.M[i][1]=Re(sqrt(hr*conj(hr) + ht*conj(ht)));
|
|
break;
|
|
case 5:
|
|
p.M[i][2]=Re(hr);
|
|
p.M[i][3]=Im(hr);
|
|
p.M[i][1]=abs(hr);
|
|
break;
|
|
case 6:
|
|
p.M[i][2]=Re(ht);
|
|
p.M[i][3]=Im(ht);
|
|
p.M[i][1]=abs(ht);
|
|
break;
|
|
default:
|
|
p.M[i][1]=0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} |