// FemmeDocCore.cpp : implementation of the CFemmeDocCore class // #include #include #include #include #include #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;kMid(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;i0) 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,"",11)==0){ PProp.Jr=0.; PProp.Ji=0.; PProp.Ar=0.; PProp.Ai=0.; q[0]=NULL; } if( _strnicmp(q,"",6)==0){ v=StripKey(s); sscanf(v,"%lf",&PProp.Ar); q[0]=NULL; } if( _strnicmp(q,"",6)==0){ v=StripKey(s); sscanf(v,"%lf",&PProp.Ai); q[0]=NULL; } if( _strnicmp(q,"",6)==0){ v=StripKey(s); sscanf(v,"%lf",&PProp.Jr); q[0]=NULL; } if( _strnicmp(q,"",6)==0){ v=StripKey(s); sscanf(v,"%lf",&PProp.Ji); q[0]=NULL; } if( _strnicmp(q,"",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,"",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,"",10)==0){ v=StripKey(s); sscanf(v,"%i",&BProp.BdryFormat); q[0]=NULL; } if( _strnicmp(q,"",8)==0){ v=StripKey(s); sscanf(v,"%lf",&BProp.Mu); q[0]=NULL; } if( _strnicmp(q,"",11)==0){ v=StripKey(s); sscanf(v,"%lf",&BProp.Sig); q[0]=NULL; } if( _strnicmp(q,"",5)==0){ v=StripKey(s); sscanf(v,"%lf",&BProp.A0); q[0]=NULL; } if( _strnicmp(q,"",5)==0){ v=StripKey(s); sscanf(v,"%lf",&BProp.A1); q[0]=NULL; } if( _strnicmp(q,"",5)==0){ v=StripKey(s); sscanf(v,"%lf",&BProp.A2); q[0]=NULL; } if( _strnicmp(q,"",5)==0){ v=StripKey(s); sscanf(v,"%lf",&BProp.phi); q[0]=NULL; } if( _strnicmp(q,"",4)==0){ v=StripKey(s); sscanf(v,"%lf",&BProp.c0.re); q[0]=NULL; } if( _strnicmp(q,"",4)==0){ v=StripKey(s); sscanf(v,"%lf",&BProp.c1.re); q[0]=NULL; } if( _strnicmp(q,"",5)==0){ v=StripKey(s); sscanf(v,"%lf",&BProp.c0.im); q[0]=NULL; } if( _strnicmp(q,"",5)==0){ v=StripKey(s); sscanf(v,"%lf",&BProp.c1.im); q[0]=NULL; } if( _strnicmp(q,"",12)==0){ v=StripKey(s); sscanf(v,"%lf",&BProp.InnerAngle); q[0]=NULL; } if( _strnicmp(q,"",12)==0){ v=StripKey(s); sscanf(v,"%lf",&BProp.OuterAngle); q[0]=NULL; } if( _strnicmp(q,"",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,"",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,"",6)==0){ v=StripKey(s); sscanf(v,"%lf",&MProp.mu_x); q[0]=NULL; } if( _strnicmp(q,"",6)==0){ v=StripKey(s); sscanf(v,"%lf",&MProp.mu_y); q[0]=NULL; } if( _strnicmp(q,"",5)==0){ v=StripKey(s); sscanf(v,"%lf",&MProp.H_c); q[0]=NULL; } if( _strnicmp(q,"",10)==0){ v=StripKey(s); sscanf(v,"%lf",&MProp.Theta_m); q[0]=NULL; } if( _strnicmp(q,"",6)==0){ v=StripKey(s); sscanf(v,"%lf",&MProp.Jr); q[0]=NULL; } if( _strnicmp(q,"",6)==0){ v=StripKey(s); sscanf(v,"%lf",&MProp.Ji); q[0]=NULL; } if( _strnicmp(q,"",7)==0){ v=StripKey(s); sscanf(v,"%lf",&MProp.Cduct); q[0]=NULL; } if( _strnicmp(q,"",7)==0){ v=StripKey(s); sscanf(v,"%lf",&MProp.Theta_hn); q[0]=NULL; } if( _strnicmp(q,"",7)==0){ v=StripKey(s); sscanf(v,"%lf",&MProp.Theta_hx); q[0]=NULL; } if( _strnicmp(q,"",8)==0){ v=StripKey(s); sscanf(v,"%lf",&MProp.Theta_hy); q[0]=NULL; } if( _strnicmp(q,"",7)==0){ v=StripKey(s); sscanf(v,"%lf",&MProp.Lam_d); q[0]=NULL; } if( _strnicmp(q,"",8)==0){ v=StripKey(s); sscanf(v,"%lf",&MProp.LamFill); q[0]=NULL; } if( _strnicmp(q,"",7)==0){ v=StripKey(s); sscanf(v,"%lf",&MProp.WireD); q[0]=NULL; } if( _strnicmp(q,"",9)==0){ v=StripKey(s); sscanf(v,"%i",&MProp.LamType); q[0]=NULL; } if( _strnicmp(q,"",10)==0){ v=StripKey(s); sscanf(v,"%i",&MProp.NStrands); q[0]=NULL; } if( _strnicmp(q,"",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",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;i0) circproplist=(CCircuit *)calloc(k,sizeof(CCircuit)); q[0]=NULL; } if( _strnicmp(q,"",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,"",17)==0){ v=StripKey(s); sscanf(v,"%lf",&CProp.dVolts_re); q[0]=NULL; } if( _strnicmp(q,"",17)==0){ v=StripKey(s); sscanf(v,"%lf",&CProp.dVolts_im); q[0]=NULL; } if( _strnicmp(q,"",14)==0){ v=StripKey(s); sscanf(v,"%lf",&CProp.Amps_re); q[0]=NULL; } if( _strnicmp(q,"",14)==0){ v=StripKey(s); sscanf(v,"%lf",&CProp.Amps_im); q[0]=NULL; } if( _strnicmp(q,"",13)==0){ v=StripKey(s); sscanf(v,"%i",&CProp.CircType); q[0]=NULL; } if( _strnicmp(q,"",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;i0) { 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=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;k0) && (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;i1) 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;iTurns)>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;iCduct==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;iNStrands); 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.; }