163 lines
5.1 KiB
C++
163 lines
5.1 KiB
C++
// magnetostatic FFI body: opaque doc, pipeline, mesh accessors. delegates to fkn's CFemmeDocCore.
|
|
|
|
#include "../fkn/StdAfx.h"
|
|
#include "../fkn/fknDlg.h"
|
|
#include "../fkn/complex.h"
|
|
#include "../fkn/spars.h"
|
|
#include "../fkn/mesh.h"
|
|
#include "../fkn/FemmeDocCore.h"
|
|
#include "../fkn/lua.h"
|
|
|
|
#include "femm_mag.h"
|
|
|
|
#include <cstdio>
|
|
#include <cstdarg>
|
|
#include <string>
|
|
|
|
// liblua library-open entry points called from fkn's prob*big solvers.
|
|
void lua_baselibopen(lua_State* L);
|
|
void lua_iolibopen(lua_State* L);
|
|
void lua_strlibopen(lua_State* L);
|
|
void lua_mathlibopen(lua_State* L);
|
|
|
|
// global Lua state read by fkn/prob*big.cpp during functional MagDir evaluation.
|
|
lua_State* lua = nullptr;
|
|
|
|
// creates the shared Lua interpreter on first FFI doc construction.
|
|
static void ensure_lua_state() {
|
|
if (lua) return;
|
|
lua = lua_open(4096);
|
|
lua_baselibopen(lua);
|
|
lua_strlibopen(lua);
|
|
lua_mathlibopen(lua);
|
|
lua_iolibopen(lua);
|
|
}
|
|
|
|
// stub view: math files reference TheView globally, math methods call SetPos/SetDlgItemText/InvalidateRect on it.
|
|
static CFknDlg s_stub_view;
|
|
CFknDlg* TheView = &s_stub_view;
|
|
|
|
// math files declare and call these for error reporting.
|
|
int MsgBox(const char* fmt, ...) {
|
|
va_list ap; va_start(ap, fmt);
|
|
std::vfprintf(stderr, fmt, ap);
|
|
std::fputc('\n', stderr);
|
|
va_end(ap);
|
|
return 0;
|
|
}
|
|
int MsgBox(const std::string& s) {
|
|
std::fprintf(stderr, "%s\n", s.c_str());
|
|
return 0;
|
|
}
|
|
|
|
// referenced by fkn/main.cpp's old_main wait loop; main.cpp itself is not linked here.
|
|
inline bool IsWindow(void*) { return true; }
|
|
|
|
struct FemmMagDoc {
|
|
CFemmeDocCore doc;
|
|
FemmMagProgressFn cb = nullptr;
|
|
void* user = nullptr;
|
|
std::string path_buf;
|
|
};
|
|
|
|
extern "C" {
|
|
|
|
FemmMagDoc* femm_mag_doc_new(void) {
|
|
ensure_lua_state();
|
|
auto* d = new FemmMagDoc();
|
|
d->doc.TheView = &s_stub_view;
|
|
return d;
|
|
}
|
|
|
|
void femm_mag_doc_free(FemmMagDoc* d) {
|
|
delete d;
|
|
}
|
|
|
|
void femm_mag_doc_set_progress(FemmMagDoc* d, FemmMagProgressFn fn, void* user) {
|
|
if (!d) return;
|
|
d->cb = fn;
|
|
d->user = user;
|
|
}
|
|
|
|
int femm_mag_doc_load_fem(FemmMagDoc* d, const char* path) {
|
|
if (!d || !path) return 0;
|
|
d->path_buf = path;
|
|
d->doc.PathName = const_cast<char*>(d->path_buf.c_str());
|
|
return d->doc.OnOpenDocument() ? 1 : 0;
|
|
}
|
|
|
|
int femm_mag_doc_load_mesh(FemmMagDoc* d) {
|
|
return (d && d->doc.LoadMesh()) ? 1 : 0;
|
|
}
|
|
|
|
int femm_mag_doc_renumber(FemmMagDoc* d) {
|
|
return (d && d->doc.Cuthill()) ? 1 : 0;
|
|
}
|
|
|
|
// dispatches on Frequency (DC vs AC) and ProblemType (planar vs axisymmetric).
|
|
int femm_mag_doc_solve(FemmMagDoc* d) {
|
|
if (!d) return 0;
|
|
if (d->doc.Frequency == 0) {
|
|
CBigLinProb L;
|
|
L.TheView = &s_stub_view;
|
|
L.Precision = d->doc.Precision;
|
|
if (!L.Create(d->doc.NumNodes, d->doc.BandWidth)) return 0;
|
|
if (d->doc.ProblemType == FALSE) {
|
|
if (!d->doc.Static2D(L)) return 0;
|
|
} else {
|
|
if (!d->doc.StaticAxisymmetric(L)) return 0;
|
|
}
|
|
if (!d->doc.WriteStatic2D(L)) return 0;
|
|
} else {
|
|
CBigComplexLinProb L;
|
|
L.TheView = &s_stub_view;
|
|
L.Precision = d->doc.Precision;
|
|
if (!L.Create(d->doc.NumNodes + d->doc.NumCircProps, d->doc.BandWidth, d->doc.NumNodes)) return 0;
|
|
if (d->doc.ProblemType == FALSE) {
|
|
if (!d->doc.Harmonic2D(L)) return 0;
|
|
} else {
|
|
if (!d->doc.HarmonicAxisymmetric(L)) return 0;
|
|
}
|
|
if (!d->doc.WriteHarmonic2D(L)) return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int femm_mag_doc_write_results(FemmMagDoc* /*d*/, const char* /*out_path*/) {
|
|
// results currently emitted inline by solve(); reserved hook for explicit output redirection.
|
|
return 1;
|
|
}
|
|
|
|
double femm_mag_doc_frequency (const FemmMagDoc* d) { return d ? d->doc.Frequency : 0.0; }
|
|
int femm_mag_doc_axisymmetric (const FemmMagDoc* d) { return (d && d->doc.ProblemType) ? 1 : 0; }
|
|
double femm_mag_doc_depth (const FemmMagDoc* d) { return d ? d->doc.extZo : 0.0; }
|
|
double femm_mag_doc_precision (const FemmMagDoc* d) { return d ? d->doc.Precision : 0.0; }
|
|
|
|
int femm_mag_doc_num_nodes (const FemmMagDoc* d) { return d ? d->doc.NumNodes : 0; }
|
|
|
|
void femm_mag_doc_node (const FemmMagDoc* d, int i, double* x, double* y) {
|
|
if (!d || !d->doc.meshnode) return;
|
|
if (x) *x = d->doc.meshnode[i].x;
|
|
if (y) *y = d->doc.meshnode[i].y;
|
|
}
|
|
|
|
int femm_mag_doc_num_elements (const FemmMagDoc* d) { return d ? d->doc.NumEls : 0; }
|
|
|
|
void femm_mag_doc_element (const FemmMagDoc* d, int i, int* p0, int* p1, int* p2) {
|
|
if (!d || !d->doc.meshele) return;
|
|
if (p0) *p0 = d->doc.meshele[i].p[0];
|
|
if (p1) *p1 = d->doc.meshele[i].p[1];
|
|
if (p2) *p2 = d->doc.meshele[i].p[2];
|
|
}
|
|
|
|
int femm_mag_doc_num_materials (const FemmMagDoc* d) { return d ? d->doc.NumBlockProps : 0; }
|
|
int femm_mag_doc_num_boundaries (const FemmMagDoc* d) { return d ? d->doc.NumLineProps : 0; }
|
|
int femm_mag_doc_num_circuits (const FemmMagDoc* d) { return d ? d->doc.NumCircProps : 0; }
|
|
|
|
// field sampling is post-processor territory; not exposed by the solver alone.
|
|
double femm_mag_doc_field_at (const FemmMagDoc* /*d*/, double /*x*/, double /*y*/, FemmMagField /*c*/) {
|
|
return 0.0;
|
|
}
|
|
|
|
} // extern "C"
|