FEMM/fkn/femmedoccore.cpp

1489 lines
35 KiB
C++

// FemmeDocCore.cpp : implementation of the CFemmeDocCore class
//
#include <stdafx.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include "fkn.h"
#include "fknDlg.h"
#include "complex.h"
#include "mesh.h"
#include "spars.h"
#include "FemmeDocCore.h"
/////////////////////////////////////////////////////////////////////////////
// CFemmeDocCore construction/destruction
CFemmeDocCore::CFemmeDocCore()
{
TheView = NULL;
Frequency = NULL;
Precision = NULL;
Relax = NULL;
LengthUnits = NULL;
ProblemType = NULL;
Coords = NULL;
BandWidth = NULL;
NumNodes = NULL;
NumEls = NULL;
NumBlockProps = NULL;
NumPBCs = NULL;
NumLineProps = NULL;
NumPointProps = NULL;
NumCircProps = NULL;
NumBlockLabels = NULL;
NumCircPropsOrig = NULL;
NumAGEs = NULL;
meshnode = NULL;
meshele = NULL;
blockproplist = NULL;
lineproplist = NULL;
nodeproplist = NULL;
circproplist = NULL;
labellist = NULL;
pbclist = NULL;
PathName = NULL;
Aprev = NULL;
PrevType = 0;
extRo = extRi = extZo = NULL;
agelist = NULL;
}
CFemmeDocCore::~CFemmeDocCore()
{
// This space for rent.
}
void CFemmeDocCore::CleanUp()
{
int k;
if (meshnode!=NULL) free(meshnode);
if (meshele!=NULL) free(meshele);
if (blockproplist!=NULL){
for(k=0;k<NumBlockProps;k++)
{
if(blockproplist[k].Bdata!=NULL) free(blockproplist[k].Bdata);
if(blockproplist[k].Hdata!=NULL) free(blockproplist[k].Hdata);
if(blockproplist[k].slope!=NULL) free(blockproplist[k].slope);
}
free(blockproplist);
}
if (lineproplist!=NULL) free(lineproplist);
if (nodeproplist!=NULL) free(nodeproplist);
if (circproplist!=NULL) free(circproplist);
if (labellist!=NULL){
for(k=0;k<NumBlockLabels;k++)
if(labellist[k].MagDirFctn!=NULL) free(labellist[k].MagDirFctn);
free(labellist);
}
if (pbclist!=NULL) free(pbclist);
for (k=0;k<NumAGEs;k++) if (agelist[k].node!=NULL) free(agelist[k].node);
if (agelist!=NULL) free(agelist);
if (Aprev!=NULL) free(Aprev);
}
/////////////////////////////////////////////////////////////////////////////
// CFemmeDocCore commands
char* StripKey(char *c)
{
char *d;
int i,k;
k=(int) strlen(c);
for(i=0;i<k;i++){
if (c[i] == '='){
d=c+i+1;
return d;
}
}
return c+k;
}
char *ParseDbl(char *t, double *f)
{
if (t==NULL) return NULL;
int i,j,k,u,ws;
static char w[]="\t, \n";
char *v;
k=(int) strlen(t); if(k==0) return NULL;
for(i=0,u=0,v=NULL;i<k;i++){
for(j=0,ws=0;j<4;j++){
if (t[i]==w[j]){
ws=1;
if (u==1) u=2;
}
}
if ((ws==0) && (u==0)) u=1;
if ((ws==0) && (u==2)){
v=t+i;
break;
}
}
if (u==0) return NULL; //nothing left in the string;
if (v==NULL) v=t+k;
sscanf(t,"%lf",f);
return v;
}
char *ParseInt(char *t, int *f)
{
if (t==NULL) return NULL;
int i,j,k,u,ws;
static char w[]="\t, \n";
char *v;
k=(int) strlen(t); if(k==0) return NULL;
for(i=0,u=0,v=NULL;i<k;i++){
for(j=0,ws=0;j<4;j++){
if (t[i]==w[j]){
ws=1;
if (u==1) u=2;
}
}
if ((ws==0) && (u==0)) u=1;
if ((ws==0) && (u==2)){
v=t+i;
break;
}
}
if (u==0) return NULL; //nothing left in the string;
if (v==NULL) v=t+k;
sscanf(t,"%i",f);
return v;
}
char *ParseString(char *t, CString *s)
{
if (t==NULL) return NULL;
if (strlen(t)==0) return t;
int n1,n2,k;
// find first quote in the source string
for(k=0,n1=-1;k< (int) strlen(t);k++)
{
if (t[k]=='\"'){
n1=k;
break;
}
}
if (n1<0) return t;
// find second quote in the source string
for(k=n1+1,n2=-1;k< (int) strlen(t);k++)
{
if (t[k]=='\"'){
n2=k;
break;
}
}
if (n2<0) return t;
*s=t;
*s=s->Mid(n1+1,n2-n1-1);
return (t+n2+1);
}
BOOL CFemmeDocCore::LoadPrevA(CString myFile, double *V)
{
// _Just_ load Aprev. This is needed for the case where we are restarting
// from an old solution. However, rotor angle might be slightly different
// in this case, so we need to reload all the mesh info to get the right
// mapping for any AGEs. Only Aprev needs to be reloaded then.
if (myFile.GetLength()==0) return FALSE;
FILE *fp;
int i,k;
char s[1024],q[256];
char *v;
double prevFreq=0;
int prevNumNodes;
if ((fp=fopen(myFile,"rt"))==NULL){
// MsgBox("Couldn't read from specified previous solution\n");
return FALSE;
}
// parse the file
k=0;
while (fgets(s,1024,fp)!=NULL)
{
sscanf(s,"%s",q);
// Frequency of the problem
if( _strnicmp(q,"[frequency]",11)==0){
v=StripKey(s);
sscanf(v,"%lf",&prevFreq);
q[0]=NULL;
}
sscanf(s,"%s",q);
if( _strnicmp(q,"[solution]",11)==0){
k=1;
break;
}
}
// case where the solution is never found.
if (k==0)
{
fclose(fp);
// MsgBox("Couldn't read from specified previous solution\n");
return FALSE;
}
// case were previous solution is an AC problem.
// only DC previous solutions are presently supported
if (prevFreq!=0)
{
fclose(fp);
// MsgBox("Only DC previous solutions are presently supported\n");
return FALSE;
}
////////////////////////////
// read in the previous solution!!!
///////////////////////////
// read in nodes
fgets(s,1024,fp);
sscanf(s,"%i",&prevNumNodes);
if (prevNumNodes!=NumNodes)
{
fclose(fp);
// MsgBox("%i != %i\n",NumNodes,prevNumNodes);
return FALSE;
}
CNode node;
double c=PI*4.e-05;
for(i=0;i<NumNodes;i++){
fgets(s,1024,fp);
sscanf(s,"%lf %lf %lf %i\n",&node.x,&node.y,&V[i],&node.bc);
V[i]/=c;
}
return TRUE;
}
BOOL CFemmeDocCore::LoadPrev()
{
if (PrevSoln.GetLength()==0) return FALSE;
FILE *fp;
int i,k;
char s[1024],q[256];
char *v;
double prevFreq=0;
double c[]={2.54,0.1,1.,100.,0.00254,1.e-04};
if ((fp=fopen(PrevSoln,"rt"))==NULL){
MsgBox("Couldn't read from specified previous solution\n");
return FALSE;
}
// parse the file
k=0;
while (fgets(s,1024,fp)!=NULL)
{
sscanf(s,"%s",q);
// Frequency of the problem
if( _strnicmp(q,"[frequency]",11)==0){
v=StripKey(s);
sscanf(v,"%lf",&prevFreq);
q[0]=NULL;
}
sscanf(s,"%s",q);
if( _strnicmp(q,"[solution]",11)==0){
k=1;
break;
}
}
// case where the solution is never found.
if (k==0)
{
fclose(fp);
MsgBox("Couldn't read from specified previous solution\n");
return FALSE;
}
// case were previous solution is an AC problem.
// only DC previous solutions are presently supported
if (prevFreq!=0)
{
fclose(fp);
MsgBox("Only DC previous solutions are presently supported\n");
return FALSE;
}
////////////////////////////
// read in the previous solution!!!
///////////////////////////
// read in nodes
fgets(s,1024,fp);
sscanf(s,"%i",&NumNodes);
Aprev=(double *)calloc(NumNodes,sizeof(double));
meshnode=(CNode *)calloc(NumNodes,sizeof(CNode));
CNode node;
for(i=0;i<NumNodes;i++){
fgets(s,1024,fp);
sscanf(s,"%lf %lf %lf %i\n",&node.x,&node.y,&Aprev[i],&node.bc);
// convert all lengths to centimeters (better conditioning this way...)
node.x*=c[LengthUnits];
node.y*=c[LengthUnits];
meshnode[i]=node;
}
// read elements
fgets(s,1024,fp);
sscanf(s,"%i",&NumEls);
meshele=(CElement *)calloc(NumEls,sizeof(CElement));
CElement elm;
for(i=0;i<NumEls;i++)
{
fgets(s,1024,fp);
sscanf(s,"%i %i %i %i %i %i %i %lf\n",&elm.p[0],&elm.p[1],&elm.p[2],&elm.lbl,&elm.e[0],&elm.e[1],&elm.e[2],&elm.Jprev);
// look up block type out of the list of block labels
elm.blk=labellist[elm.lbl].BlockType;
meshele[i]=elm;
}
// scroll through block label info
fgets(s,1024,fp);
sscanf(s,"%i",&k);
for(i=0;i<k;i++) fgets(s,1024,fp);
// read in PBC list
if (fgets(s,1024,fp)!=NULL)
{
sscanf(s,"%i",&NumPBCs);
if (NumPBCs!=0) pbclist=(CCommonPoint *)calloc(NumPBCs,sizeof(CCommonPoint));
CCommonPoint pbc;
for(i=0;i<NumPBCs;i++){
fgets(s,1024,fp);
sscanf(s,"%i %i %i\n",&pbc.x,&pbc.y,&pbc.t);
pbclist[i]=pbc;
}
}
fgets(s,1024,fp); sscanf(s,"%i",&NumAGEs);
if (NumAGEs!=0) agelist=(CAirGapElement *)calloc(NumAGEs,sizeof(CAirGapElement));
CAirGapElement age;
for(i=0;i<NumAGEs;i++){
fgets(age.BdryName,80,fp);
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.node=(CQuadPoint *)calloc(age.totalArcElements+1,sizeof(CQuadPoint));
for(k=0;k<=age.totalArcElements;k++){
fgets(s,1024,fp);
sscanf(s,"%i %lf %i %lf %i %lf %i %lf",
&age.node[k].n0, &age.node[k].w0,
&age.node[k].n1, &age.node[k].w1,
&age.node[k].n2, &age.node[k].w2,
&age.node[k].n3, &age.node[k].w3);
}
agelist[i]=age;
}
fclose(fp);
return TRUE;
}
BOOL CFemmeDocCore::OnOpenDocument()
{
FILE *fp;
int i,j,k,ic;
char s[1024],q[1024];
char *v;
CPointProp PProp;
CBoundaryProp BProp;
CMaterialProp MProp;
CCircuit CProp;
CBlockLabel blk;
sprintf(s,"%s.fem",PathName);
if ((fp=fopen(s,"rt"))==NULL){
MsgBox("Couldn't read from specified .fem file");
return FALSE;
}
// define some defaults
Frequency=0.;
Precision=1.e-08;
Relax=1.;
ProblemType=0;
Coords=0;
NumPointProps=0;
NumLineProps=0;
NumBlockProps=0;
NumCircProps=0;
ACSolver=0;
// parse the file
while (fgets(s,1024,fp)!=NULL)
{
sscanf(s,"%s",q);
// Frequency of the problem
if( _strnicmp(q,"[frequency]",11)==0){
v=StripKey(s);
sscanf(v,"%lf",&Frequency);
Frequency=fabs(Frequency);
q[0]=NULL;
}
// Precision
if( _strnicmp(q,"[precision]",11)==0){
v=StripKey(s);
sscanf(v,"%lf",&Precision);
q[0]=NULL;
}
// AC Solver Type
if( _strnicmp(q,"[acsolver]",8)==0){
v=StripKey(s);
sscanf(v,"%i",&ACSolver);
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;
}
// 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){
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;
q[0]=NULL;
}
// Previous solution type
if (_strnicmp(q, "[prevtype]", 10) == 0) {
v = StripKey(s);
sscanf(v, "%i", &PrevType);
q[0] = NULL;
// 0 == None
// 1 == Incremental
// 2 == Frozen
// 3 == Restart
}
// Point Properties
if( _strnicmp(q,"[pointprops]",12)==0){
v=StripKey(s);
sscanf(v,"%i",&k);
if (k>0) nodeproplist=(CPointProp *)calloc(k,sizeof(CPointProp));
q[0]=NULL;
}
if( _strnicmp(q,"<beginpoint>",11)==0){
PProp.Jr=0.;
PProp.Ji=0.;
PProp.Ar=0.;
PProp.Ai=0.;
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[NumPointProps]=PProp;
NumPointProps++;
q[0]=NULL;
}
// Boundary Properties;
if( _strnicmp(q,"[bdryprops]",11)==0){
v=StripKey(s);
sscanf(v,"%i",&k);
if (k>0) lineproplist=(CBoundaryProp *)calloc(k,sizeof(CBoundaryProp));
q[0]=NULL;
}
if( _strnicmp(q,"<beginbdry>",11)==0){
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,"<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,"<innerangle>",12)==0){
v=StripKey(s);
sscanf(v,"%lf",&BProp.InnerAngle);
q[0]=NULL;
}
if( _strnicmp(q,"<outerangle>",12)==0){
v=StripKey(s);
sscanf(v,"%lf",&BProp.OuterAngle);
q[0]=NULL;
}
if( _strnicmp(q,"<endbdry>",9)==0){
lineproplist[NumLineProps]=BProp;
NumLineProps++;
q[0]=NULL;
}
// Block Properties;
if( _strnicmp(q,"[blockprops]",12)==0){
v=StripKey(s);
sscanf(v,"%i",&k);
if (k>0) blockproplist=(CMaterialProp *)calloc(k,sizeof(CMaterialProp));
q[0]=NULL;
}
if( _strnicmp(q,"<beginblock>",12)==0){
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.Theta_m=0.; // magnetization direction, degrees;
MProp.LamFill=1.; // lamination fill factor;
MProp.LamType=0; // type of lamination;
MProp.NStrands=0;
MProp.WireD=0;
MProp.BHpoints=0;
MProp.Bdata=NULL;
MProp.Hdata=NULL;
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,"<H_cAngle>",10)==0){
v=StripKey(s);
sscanf(v,"%lf",&MProp.Theta_m);
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);
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>",7)==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,"<WireD>",7)==0){
v=StripKey(s);
sscanf(v,"%lf",&MProp.WireD);
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,"<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);
sscanf(s,"%lf %lf",&MProp.Bdata[j],&MProp.Hdata[j].re);
MProp.Hdata[j].im=0;
}
}
q[0]=NULL;
}
if( _strnicmp(q,"<endblock>",9)==0)
{
if (MProp.BHpoints>0)
{
if((PrevSoln.GetLength()>0) && (Frequency>0) && (PrevType>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;
// second time through is to get the DC curve
MProp.GetSlopes(0);
}
else MProp.GetSlopes(Frequency*2.*PI);
}
blockproplist[NumBlockProps]=MProp;
NumBlockProps++;
MProp.BHpoints=0;
MProp.Bdata=NULL;
MProp.Hdata=NULL;
MProp.slope=NULL;
q[0]=NULL;
}
// Circuit Properties
if( _strnicmp(q,"[circuitprops]",15)==0){
v=StripKey(s);
sscanf(v,"%i",&k);
if(k>0) circproplist=(CCircuit *)calloc(k,sizeof(CCircuit));
q[0]=NULL;
}
if( _strnicmp(q,"<begincircuit>",14)==0){
CProp.dVolts_re=0.;
CProp.dVolts_im=0.;
CProp.Amps_re=0.;
CProp.Amps_im=0.;
CProp.CircType=0;
q[0]=NULL;
}
if( _strnicmp(q,"<voltgradient_re>",17)==0){
v=StripKey(s);
sscanf(v,"%lf",&CProp.dVolts_re);
q[0]=NULL;
}
if( _strnicmp(q,"<voltgradient_im>",17)==0){
v=StripKey(s);
sscanf(v,"%lf",&CProp.dVolts_im);
q[0]=NULL;
}
if( _strnicmp(q,"<totalamps_re>",14)==0){
v=StripKey(s);
sscanf(v,"%lf",&CProp.Amps_re);
q[0]=NULL;
}
if( _strnicmp(q,"<totalamps_im>",14)==0){
v=StripKey(s);
sscanf(v,"%lf",&CProp.Amps_im);
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[NumCircProps]=CProp;
NumCircProps++;
q[0]=NULL;
}
// read in regional attributes
if(_strnicmp(q,"[numblocklabels]",13)==0){
int i;
CString str;
v=StripKey(s);
sscanf(v,"%i",&k);
if (k>0) labellist=(CBlockLabel *)calloc(k, sizeof(CBlockLabel));
NumBlockLabels=k;
for(i=0;i<k;i++)
{
fgets(s,1024,fp);
// sscanf(s,"%lf %lf %i %lf %i %lf %i %i %i",&blk.x,&blk.y,&blk.BlockType,&blk.MaxArea,
// &blk.InCircuit,&blk.MagDir,&blk.InGroup,&blk.Turns,&blk.IsExternal);
//some defaults
blk.x=0;
blk.y=0;
blk.BlockType=0;
blk.MaxArea=0.;
blk.MagDir=0.;
blk.Turns=1;
blk.InCircuit=0;
blk.InGroup=0;
blk.IsExternal=0;
blk.IsDefault=0;
blk.MagDirFctn=NULL;
str.Empty();
// 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,&str);
if (str.GetLength()>0)
{
blk.MagDirFctn=(char *)calloc(str.GetLength()+1,sizeof(char));
strcpy(blk.MagDirFctn,str);
}
blk.BlockType--;
blk.InCircuit--;
labellist[i]=blk;
}
q[0]=NULL;
}
}
// need to set these so that valid BH data doesn't get wiped
// by the destructor of MProp
MProp.BHpoints=0;
MProp.Bdata=NULL;
MProp.Hdata=NULL;
fclose(fp);
if (NumCircProps==0) return TRUE;
// Process circuits for serial connections.
// The program deals with serial "circuits" by making a separate
// circuit property for each block in the serial circuit. Then,
// each of this larger number of circuits can be processed using
// the previous approach which considered all circuits to be
// parallel connected.
// first, make enough space for all possible circuits;
CCircuit *temp=(CCircuit *)calloc(NumCircProps+NumBlockLabels,sizeof(CCircuit));
for(k=0;k<NumCircProps;k++){
temp[k]=circproplist[k];
temp[k].OrigCirc=-1;
}
free(circproplist);
circproplist=temp;
NumCircPropsOrig=NumCircProps;
// now, go through the block label list and make a new "circuit"
// for every block label that is an element of a "serial" circuit.
CCircuit ncirc;
for(k=0;k<NumBlockLabels;k++)
if(labellist[k].InCircuit>=0){
ic=labellist[k].InCircuit;
if(circproplist[ic].CircType==1)
{
ncirc=circproplist[ic];
ncirc.OrigCirc=ic;
ncirc.Amps_im*=labellist[k].Turns;
ncirc.Amps_re*=labellist[k].Turns;
circproplist[NumCircProps]=ncirc;
labellist[k].InCircuit=NumCircProps;
NumCircProps++;
}
}
// now, all "circuits" look like parallel circuits, so
for(k=0;k<NumCircProps;k++)
if(circproplist[k].CircType==1) circproplist[k].CircType=0;
return TRUE;
}
BOOL CFemmeDocCore::LoadMesh()
{
int i,j,k,q,n0,n1;
char infile[256];
FILE *fp;
char s[1024];
double c[]={2.54,0.1,1.,100.,0.00254,1.e-04};
//if there's a "previous solution" specified,
//and if this is an incremental or frozen permeability problem,
//slurp of the mesh out of that file.
if ((PrevSoln.GetLength()>0) && (PrevType>0))
{
// clear out mesh files
sprintf(infile,"%s.ele",PathName); DeleteFile(infile);
sprintf(infile,"%s.node",PathName); DeleteFile(infile);
sprintf(infile,"%s.pbc",PathName); DeleteFile(infile);
sprintf(infile,"%s.poly",PathName); DeleteFile(infile);
sprintf(infile,"%s.edge",PathName); DeleteFile(infile);
return LoadPrev();
}
//read meshnodes;
sprintf(infile,"%s.node",PathName);
if((fp=fopen(infile,"rt"))==NULL){
return FALSE;
}
fgets(s,1024,fp);
sscanf(s,"%i",&k); NumNodes=k;
meshnode=(CNode *)calloc(k,sizeof(CNode));
CNode node;
for(i=0;i<k;i++){
fscanf(fp,"%i",&j);
fscanf(fp,"%lf",&node.x);
fscanf(fp,"%lf",&node.y);
fscanf(fp,"%i",&j);
if(j>1) j=j-2; else j=-1;
node.bc=j;
// convert all lengths to centimeters (better conditioning this way...)
node.x*=c[LengthUnits];
node.y*=c[LengthUnits];
meshnode[i]=node;
}
fclose(fp);
//read in periodic boundary conditions;
sprintf(infile,"%s.pbc",PathName);
if((fp=fopen(infile,"rt"))==NULL){
return FALSE;
}
fgets(s,1024,fp);
sscanf(s,"%i",&k); NumPBCs=k;
if (k!=0) pbclist=(CCommonPoint *)calloc(k,sizeof(CCommonPoint));
CCommonPoint pbc;
for(i=0;i<k;i++){
fgets(s,1024,fp);
sscanf(s,"%i %i %i %i",&j,&pbc.x,&pbc.y,&pbc.t);
pbclist[i]=pbc;
}
// read in air gap element info
fgets(s,1024,fp); sscanf(s,"%i",&NumAGEs);
if (NumAGEs!=0) agelist=(CAirGapElement *)calloc(NumAGEs,sizeof(CAirGapElement));
CAirGapElement age;
for(i=0;i<NumAGEs;i++){
fgets(age.BdryName,80,fp);
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.node=(CQuadPoint *)calloc(age.totalArcElements+1,sizeof(CQuadPoint));
for(k=0;k<=age.totalArcElements;k++){
fgets(s,1024,fp);
sscanf(s,"%i %lf %i %lf %i %lf %i %lf",
&age.node[k].n0, &age.node[k].w0,
&age.node[k].n1, &age.node[k].w1,
&age.node[k].n2, &age.node[k].w2,
&age.node[k].n3, &age.node[k].w3);
}
agelist[i]=age;
}
fclose(fp);
// read in elements;
sprintf(infile,"%s.ele",PathName);
if((fp=fopen(infile,"rt"))==NULL){
return FALSE;
}
fgets(s,1024,fp);
sscanf(s,"%i",&k); NumEls=k;
meshele=(CElement *)calloc(k,sizeof(CElement));
CElement elm;
int defaultLabel;
for(i=0,defaultLabel=-1;i<NumBlockLabels;i++)
if (labellist[i].IsDefault) defaultLabel=i;
for(i=0;i<k;i++){
fscanf(fp,"%i",&j);
fscanf(fp,"%i",&elm.p[0]);
fscanf(fp,"%i",&elm.p[1]);
fscanf(fp,"%i",&elm.p[2]);
fscanf(fp,"%i",&elm.lbl);
elm.lbl--;
if(elm.lbl<0) elm.lbl=defaultLabel;
if(elm.lbl<0){
CString msg;
msg ="Material properties have not been defined for\n";
msg+="all regions. Press the \"Run Mesh Generator\"\n";
msg+="button to highlight the problem regions.";
MsgBox(msg);
fclose(fp);
sprintf(infile,"%s.ele",PathName); DeleteFile(infile);
sprintf(infile,"%s.node",PathName); DeleteFile(infile);
sprintf(infile,"%s.pbc",PathName); DeleteFile(infile);
sprintf(infile,"%s.poly",PathName); DeleteFile(infile);
sprintf(infile,"%s.edge",PathName); DeleteFile(infile);
exit(1);
}
// look up block type out of the list of block labels
elm.blk=labellist[elm.lbl].BlockType;
meshele[i]=elm;
}
fclose(fp);
// initialize edge bc's and element permeabilities;
for(i=0;i<NumEls;i++)
for(j=0;j<3;j++)
{
meshele[i].e[j] = -1;
meshele[i].mu1 = -1.;
meshele[i].mu2 = -1.;
}
// read in edges to which boundary conditions are applied;
// first, do a little bookkeeping so that element
// associated with a give edge can be identified fast
int *nmbr;
int **mbr;
nmbr=(int *)calloc(NumNodes,sizeof(int));
// Make a list of how many elements that tells how
// many elements to which each node belongs.
for(i=0;i<NumEls;i++)
for(j=0;j<3;j++)
nmbr[meshele[i].p[j]]++;
// mete out some memory to build a list of the
// connectivity...
mbr=(int **)calloc(NumNodes,sizeof(int *));
for(i=0;i<NumNodes;i++){
mbr[i]=(int *)calloc(nmbr[i],sizeof(int));
nmbr[i]=0;
}
// fill up the connectivity information;
for(i=0;i<NumEls;i++)
for(j=0;j<3;j++)
{
k=meshele[i].p[j];
mbr[k][nmbr[k]]=i;
nmbr[k]++;
}
sprintf(infile,"%s.edge",PathName);
if((fp=fopen(infile,"rt"))==NULL)
{
return FALSE;
}
fscanf(fp,"%i",&k); // read in number of lines
fscanf(fp,"%i",&j); // read in boundarymarker flag;
for(i=0;i<k;i++)
{
fscanf(fp,"%i",&j);
fscanf(fp,"%i",&n0);
fscanf(fp,"%i",&n1);
fscanf(fp,"%i",&j);
if(j<0){
j = -(j+2);
// search through elements to find one containing the line;
// set corresponding edge equal to the bc number.
for(q=0;q<nmbr[n0];q++)
{
elm=meshele[mbr[n0][q]];
if ((elm.p[0] == n0) && (elm.p[1] == n1)) elm.e[0]=j;
if ((elm.p[0] == n1) && (elm.p[1] == n0)) elm.e[0]=j;
if ((elm.p[1] == n0) && (elm.p[2] == n1)) elm.e[1]=j;
if ((elm.p[1] == n1) && (elm.p[2] == n0)) elm.e[1]=j;
if ((elm.p[2] == n0) && (elm.p[0] == n1)) elm.e[2]=j;
if ((elm.p[2] == n1) && (elm.p[0] == n0)) elm.e[2]=j;
meshele[mbr[n0][q]]=elm;
}
}
}
fclose(fp);
// free up the connectivity information
free(nmbr);
for(i=0;i<NumNodes;i++) free(mbr[i]);
free(mbr);
// clear out temporary files
sprintf(infile,"%s.ele",PathName); DeleteFile(infile);
sprintf(infile,"%s.node",PathName); DeleteFile(infile);
sprintf(infile,"%s.pbc",PathName); DeleteFile(infile);
sprintf(infile,"%s.poly",PathName); DeleteFile(infile);
return TRUE;
}
void CFemmeDocCore::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[labellist[lbl].BlockType];
CBlockLabel* bl= &labellist[lbl];
double atot,awire,d,o,fill,dd,W,R,c1,c2;
int i,wiretype;
CComplex ufd,ofd;
if ((abs(bl->Turns)>1) || (blockproplist[labellist[lbl].BlockType].LamType>2))
bl->bIsWound=TRUE;
else
bl->bIsWound=FALSE;
if ((Frequency==0) || (blockproplist[labellist[lbl].BlockType].LamType<3))
{
bl->ProximityMu=1.;
return;
}
// compute total area of associated block
for(i=0,atot=0;i<NumEls;i++)
if(meshele[i].lbl==lbl) atot+=ElmArea(i);
if (atot==0) return;
// "non-physical" case where the wire has a zero conductivity
if (bp->Cduct==0)
{
bl->ProximityMu=1;
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;
fill=fabs(d*d*((double) bl->Turns)/atot);
dd=d/sqrt(fill); // foil pitch
fill=d/dd; // fill for purposes of equivalent foil analysis
o=bp->Cduct*(d/dd)*1.e6; // effective foil conductivity in S/m
// effective permeability for the equivalent foil
ufd=muo*tanh(sqrt(I*W*o*muo)*d/2.)/(sqrt(I*W*o*muo)*d/2.);
bl->ProximityMu=(fill*ufd+(1.-fill)*muo)/muo;
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;
// magnet wire, litz wire, 10% CCA, 15%CCA
default:
R=bp->WireD*0.0005;
awire=PI*R*R*((double) bp->NStrands)*((double) bl->Turns);
break;
}
fill=fabs(awire/atot);
// preliminary definitions
o=bp->Cduct*1.e6; // conductivity in S/m
W=2.*PI*Frequency*o*muo*R*R/2.; // non-dimensionalized frequency
// fit for frequency-dependent permeability...
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;
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;
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;
break;
}
ufd=c2*(tanh(sqrt(c1*I*W))/sqrt(c1*I*W))+(1.-c2); // relative frequency-dependent permeability
bl->ProximityMu=ufd;
}
/*
void CFemmeDocCore::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[labellist[lbl].BlockType];
CBlockLabel* bl= &labellist[lbl];
double atot,awire,r,FillFactor;
int i,wiretype;
CComplex ufd;
double W=2.*PI*Frequency;
if ((Frequency==0) || (blockproplist[labellist[lbl].BlockType].LamType<3))
{
bl->ProximityMu=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
r=bp->WireD*0.0005;
for(i=0,atot=0;i<NumEls;i++)
if(meshele[i].lbl==lbl) atot+=ElmArea(i);
awire=PI*r*r;
if (wiretype==3) awire*=(4./PI); // if rectangular wire;
awire*=((double) bp->NStrands);
awire*=((double) bl->Turns);
if (atot==0) return;
FillFactor=fabs(awire/atot);
double w,d,h,o,fill,dd;
// if stranded but non-litz, use an effective wire radius that
// gives the same cross-section as total stranded area
if (wiretype==1) r*=sqrt((double) bp->NStrands);
if (wiretype!=3){
d=r*sqrt(3.);
h=PI/sqrt(3.)*r;
w=r*sqrt(PI/(2.*sqrt(3.)*FillFactor));
dd=sqrt(3.)*w;
}
else{
d=2.*r;
h=2.*r;
w=r/sqrt(FillFactor);
dd=2.*w;
}
o=bp->Cduct*(h/w)*5.e5; // conductivity in S/m
fill=d/dd; //fill for purposes of equivalent foil analysis
// At this point, sanity-check the fill factor;
if (fill>1)
{
CString mymsg;
mymsg.Format("Block label at (%g,%g) has a fill factor",bl->x,bl->y);
mymsg += "greater than the theoretical maximum. Couldn't solve the problem.";
MsgBox(mymsg);
exit(5);
}
// effective permeability for the equivalent foil. Note that this is
// the same equation as effective permeability of a lamination...
if (o!=0) ufd=muo*tanh(sqrt(I*W*o*muo)*d/2.)/(sqrt(I*W*o*muo)*d/2.);
else ufd=0;
// relative complex permeability
bl->ProximityMu=(fill*ufd+(1.-fill)*muo)/muo;
}
*/
double CFemmeDocCore::ElmArea(int i)
{
// returns element cross-section area in meter^2
int j,n[3];
double b0,b1,c0,c1;
for(j=0;j<3;j++) n[j]=meshele[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 0.0001*(b0*c1-b1*c0)/2.;
}