441 lines
9.6 KiB
C++
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);
|
|
}
|
|
|
|
}
|