FEMM/femm/BHData.cpp

441 lines
9.6 KiB
C++

// BHData.cpp : implementation file
//
#include "stdafx.h"
#include "femm.h"
#include "BHData.h"
#include "fullmatrix.h"
#include "BHPlot.h"
#include "BHDatafile.h"
#include <process.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CBHData dialog
CBHData::CBHData(CWnd* pParent /*=NULL*/)
: CDialog(CBHData::IDD, pParent)
{
//{{AFX_DATA_INIT(CBHData)
m_Bdata = _T("");
m_Hdata = _T("");
m_BHname = _T("");
//}}AFX_DATA_INIT
logplot=FALSE;
}
void CBHData::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CBHData)
DDX_Text(pDX, IDC_BDATA, m_Bdata);
DDX_Text(pDX, IDC_HDATA, m_Hdata);
DDX_Text(pDX, IDC_BHNAME, m_BHname);
//}}AFX_DATA_MAP
DDX_Control(pDX, IDC_BDATA, m_IDC_BDATA);
DDX_Control(pDX, IDC_HDATA, m_IDC_HDATA);
}
BEGIN_MESSAGE_MAP(CBHData, CDialog)
//{{AFX_MSG_MAP(CBHData)
ON_BN_CLICKED(IDC_PLOT_BHCURVE, OnPlotBHcurve)
ON_BN_CLICKED(IDC_LOGPLOT_BHCURVE, OnLogPlotBHcurve)
ON_BN_CLICKED(IDC_READ_BHCURVE, OnReadBhcurve)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CBHData message handlers
void CBHData::StripBHData()
{
int k;
char *buff,*nptr,*endptr;
double z;
B.RemoveAll();
H.RemoveAll();
BHpoints=0;
if((m_Bdata.GetLength()==0) || (m_Hdata.GetLength()==0)) return;
k=m_Bdata.GetLength()*2;
buff=(char *)calloc(k,sizeof(char));
strcpy(buff,m_Bdata);
nptr=buff;
while (sscanf(nptr,"%lf",&z)!=EOF){
z=strtod(nptr,&endptr );
if(nptr==endptr) nptr++; //catch special case
else nptr=endptr;
if(B.GetSize()>0){ // enforce monotonicity
if (z<=B[B.GetSize()-1])
break;
}
else if(z!=0) B.Add(0);
B.Add(z);
}
free(buff);
k=m_Hdata.GetLength()*2;
buff=(char *)calloc(k,sizeof(char));
strcpy(buff,m_Hdata);
nptr=buff;
while (sscanf(nptr,"%lf",&z)!=EOF){
z=strtod(nptr,&endptr );
if(nptr==endptr) nptr++;
else nptr=endptr;
if(H.GetSize()>0){
if (z<=H[H.GetSize()-1])
break;
}
else if(z!=0) H.Add(0);
H.Add(z);
}
BHpoints=(int) B.GetSize();
if ((int) H.GetSize()<BHpoints) BHpoints=(int) H.GetSize();
free(buff);
}
void CBHData::GetSlopes()
{
if (BHpoints==0) return; // catch trivial case;
CFullMatrix Z;
int i;
BOOL CurveOK=FALSE;
BOOL Smooth=FALSE;
double l1,l2;
double *bn,*hn;
Z.Create(BHpoints);
slope=(double *)calloc(BHpoints,sizeof(double));
bn=(double *)calloc(BHpoints,sizeof(double));
hn=(double *)calloc(BHpoints,sizeof(double));
while(CurveOK!=TRUE)
{
// make sure that the space for computing slopes is cleared out
Z.Wipe();
// impose natural BC on the `left'
l1=B[1]-B[0];
Z.M[0][0]=4./l1;
Z.M[0][1]=2./l1;
Z.b[0]=6.*(H[1]-H[0])/(l1*l1);
// impose natural BC on the `right'
int n=BHpoints;
l1=B[n-1]-B[n-2];
Z.M[n-1][n-1]=4./l1;
Z.M[n-1][n-2]=2./l1;
Z.b[n-1]=6.*(H[n-1]-H[n-2])/(l1*l1);
for(i=1;i<BHpoints-1;i++)
{
l1=B[i]-B[i-1];
l2=B[i+1]-B[i];
Z.M[i][i-1]=2./l1;
Z.M[i][i]=4.*(l1+l2)/(l1*l2);
Z.M[i][i+1]=2./l2;
Z.b[i]=6.*(H[i]-H[i-1])/(l1*l1) +
6.*(H[i+1]-H[i])/(l2*l2);
}
Z.GaussSolve();
for(i=0;i<BHpoints;i++) slope[i]=Z.b[i];
// now, test to see if there are any "bad" segments in there.
for(i=1,CurveOK=TRUE;i<BHpoints;i++)
{
double L,c0,c1,c2,d0,d1,u0,u1,X0,X1;
d0=slope[i-1];
d1=slope[i];
u0=H[i-1];
u1=H[i];
L=B[i]-B[i-1];
c0=d0;
c1= -(2.*(2.*d0*L + d1*L + 3.*u0 - 3.*u1))/(L*L);
c2= (3.*(d0*L + d1*L + 2.*u0 - 2.*u1))/(L*L*L);
X0=-1.;
X1=-1.;
u0=c1*c1-4.*c0*c2;
// check out degenerate cases
if(c2==0)
{
if(c1!=0) X0=-c0/c1;
}
else if(u0>0)
{
u0=sqrt(u0);
X0=-(c1 + u0)/(2.*c2);
X1=(-c1 + u0)/(2.*c2);
}
//now, see if we've struck gold!
if (((X0>=0.)&&(X0<=L))||((X1>=0.)&&(X1<=L)))
CurveOK=FALSE;
}
if(CurveOK!=TRUE) //remedial action
{
// Smooth out input points
// to get rid of rapid transitions;
// Uses a 3-point moving average
for(i=1;i<BHpoints-1;i++)
{
bn[i]=(B[i-1]+B[i]+B[i+1])/3.;
hn[i]=(H[i-1]+H[i]+H[i+1])/3.;
}
for(i=1;i<BHpoints-1;i++){
H[i]=hn[i];
B[i]=bn[i];
}
Smooth++;
}
}
free(bn);
free(hn);
// alert user if smoothing was required
// if(Smooth!=FALSE) MsgBox("Data was smoothed %i times\nto obtain a single-valued BH curve fit",Smooth);
return;
}
/*
void CBHData::GetSlopes()
{
if (BHpoints==0) return; // catch trivial case;
int i,bDone;
double m1,m2;
slope=(double *)calloc(BHpoints,sizeof(double));
do{
for(i=1;i<BHpoints-1;i++)
{
// calculate nominal slope of each intermediate knot
m1=(H[i]-H[i-1])/(B[i]-B[i-1]);
m2=(H[i+1]-H[i])/(B[i+1]-B[i]);
// average of the linear interpolation slope on either side of the knot
slope[i]=(m1+m2)/2.;
// check a sufficient condition for monotonicity.
bDone=TRUE;
if ((slope[i]>3.*m1) || (slope[i]>3.*m2))
{
H[i]=(8.*H[i]+H[i-1]+H[i+1])/10.;
B[i]=(8.*B[i]+B[i-1]+B[i+1])/10.;
bDone=FALSE;
}
}
}while(!bDone);
// do endpoints
slope[0]=(H[1]-H[0])/(B[1]-B[0]);
slope[i]=(H[i]-H[i-1])/(B[i]-B[i-1]);
return;
}
*/
double CBHData::GetH(double x)
{
double b,h,z,z2,l;
int i;
b=fabs(x);
if ((BHpoints==0) || (b==0)) return 0;
if(b>B[BHpoints-1])
return (H[BHpoints-1] + slope[BHpoints-1]*(b-B[BHpoints-1]));
for(i=0;i<BHpoints-1;i++)
if((b>=B[i]) && (b<=B[i+1])){
l=(B[i+1]-B[i]);
z=(b-B[i])/l;
z2=z*z;
h=(1.-3.*z2+2.*z2*z)*H[i] +
z*(1.-2.*z+z2)*l*slope[i] +
z2*(3.-2.*z)*H[i+1] +
z2*(z-1.)*l*slope[i+1];
return h;
}
return 0;
}
void CBHData::OnLogPlotBHcurve()
{
logplot=TRUE;
OnPlotBHcurve();
}
void CBHData::OnPlotBHcurve()
{
CBHPlot xyplot;
int i;
double b,db;
BOOL logscale=logplot;
logplot=FALSE;
slope=NULL;
UpdateData();
StripBHData();
if (BHpoints<3){
MsgBox("Must have at least 3 pairs of data points");
return;
}
// copy raw B-H data for plotting in comparison to
// splined (and possibly smoothed) curve
xyplot.NumPts=BHpoints;
xyplot.Pts=(CComplex *)calloc(BHpoints,sizeof(CComplex));
for(i=0;i<BHpoints;i++) xyplot.Pts[i]=H[i]+I*B[i];
GetSlopes();
// get path to femmplot that we will need to display
// the plot of the B-H curve...
CString comline=((CFemmApp *)AfxGetApp())->GetExecutablePath();
// Actually evaluate all the points on the line...
if(xyplot.Create(101,2)==FALSE){
free(slope);
return;
}
db=(B[BHpoints-1]-B[0])/100.;
for(i=0,b=B[0];i<=100;i++,b+=db)
{
xyplot.M[i][1]=b;
xyplot.M[i][0]=GetH(b);
}
sprintf(xyplot.lbls[0],"H, Amp/Meter");
sprintf(xyplot.lbls[1],"B, Tesla");
// Create the plot, send it to the clipboard, spawn viewer...
CMetaFileDC Meta;
Meta.CreateEnhanced(NULL,NULL,NULL,NULL);
xyplot.MakePlot(&Meta,logscale);
HENHMETAFILE hMeta=Meta.CloseEnhanced();
if (hMeta==NULL) MsgBox("No Handle...");
if (OpenClipboard()==FALSE)
MsgBox("Cannot access the Clipboard");
else{
EmptyClipboard();
if(SetClipboardData(CF_ENHMETAFILE,hMeta)==NULL)
{
MsgBox("Couldn't SetClipboardData");
}
CloseClipboard();
// fire up plot viewer;
// ((CFemmApp *)AfxGetApp())->CreateNewDocument(8);
// in this case call the external program rather than
// displaying in the window. Since dialog is running modal,
// it obscures the plotted BH curve--this is an annoying kludge.
char CommandLine[MAX_PATH];
sprintf(CommandLine,"%sfemmplot.exe", (const char *) ((CFemmApp *)AfxGetApp())->GetExecutablePath());
STARTUPINFO StartupInfo2 = {0};
PROCESS_INFORMATION ProcessInfo2;
StartupInfo2.cb = sizeof(STARTUPINFO);
CreateProcess(NULL,CommandLine, NULL, NULL, FALSE,0, NULL, NULL, &StartupInfo2, &ProcessInfo2);
CloseHandle(ProcessInfo2.hProcess);
CloseHandle(ProcessInfo2.hThread);
}
if (slope!=NULL) free(slope);
}
void CBHData::OnReadBhcurve()
{
// TODO: Add your control notification handler code here
CFileDialog *fname_dia;
CString infile;
fname_dia=new CFileDialog(
TRUE,
"dat | * ",
infile,
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
"Two column text data file (*.dat) | *.dat; *.DAT | All Files (*.*) | *.*||",
NULL);
if(fname_dia->DoModal()==IDCANCEL){
delete[] fname_dia;
return;
}
infile=fname_dia->GetPathName();
delete[] fname_dia;
CBHDatafile dlg;
if(dlg.DoModal()==IDCANCEL) return;
// read in data from text file;
m_Bdata.Empty();
m_Hdata.Empty();
double bunits[]={1.,0.0001,0.1};
double hunits[]={1.,1000.,79.5775,79577.5};
char s[1024];
double b_in,h_in,b_off,h_off;
b_off=0;h_off=0;
FILE *fp=fopen(infile,"rt");
if (fp==NULL){
MsgBox("problem opening data file");
return;
}
do{
if(fgets(s,1024,fp)==NULL) break;
if(dlg.BHOrder==0) sscanf(s,"%lf %lf",&b_in,&h_in);
else sscanf(s,"%lf %lf",&h_in,&b_in);
b_in *= bunits[dlg.BUnits];
if ((b_off==0) && (b_in<0)) b_off=fabs(b_in);
b_in += b_off;
h_in *= hunits[dlg.HUnits];
if ((h_off==0) && (h_in<0)) h_off=fabs(h_in);
h_in += h_off;
sprintf(s,"%f\r\n",b_in); m_Bdata += s;
sprintf(s,"%f\r\n",h_in); m_Hdata += s;
} while(1>0);
SetDlgItemText(IDC_BDATA,m_Bdata);
SetDlgItemText(IDC_HDATA,m_Hdata);
fclose(fp);
if(h_off!=0){
sprintf(s,"Suggested Hc = %.0f A/m",h_off);
AfxMessageBox(s,MB_ICONINFORMATION);
}
}