ffi
This commit is contained in:
parent
d59389bba8
commit
a1989fb1a9
|
|
@ -0,0 +1,4 @@
|
||||||
|
build/ffi/
|
||||||
|
.DS_Store
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
|
@ -0,0 +1,124 @@
|
||||||
|
// current-flow FFI body: opaque doc, pipeline, mesh accessors. delegates to csolv's CFemmeDocCore.
|
||||||
|
|
||||||
|
#include "../csolv/StdAfx.h"
|
||||||
|
#include "../csolv/CSOLVDLG.H"
|
||||||
|
#include "../csolv/complex.h"
|
||||||
|
#include "../csolv/mesh.h"
|
||||||
|
#include "../csolv/spars.h"
|
||||||
|
#include "../csolv/femmedoccore.h"
|
||||||
|
|
||||||
|
#include "femm_curr.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdarg>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// stub view: math files reference TheView globally, math methods call SetPos/SetDlgItemText/InvalidateRect on it.
|
||||||
|
static CcsolvDlg s_stub_view;
|
||||||
|
CcsolvDlg* 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 csolv/main.cpp's old_main wait loop; main.cpp itself is not linked here.
|
||||||
|
inline bool IsWindow(void*) { return true; }
|
||||||
|
|
||||||
|
struct FemmCurrDoc {
|
||||||
|
CFemmeDocCore doc;
|
||||||
|
FemmCurrProgressFn cb = nullptr;
|
||||||
|
void* user = nullptr;
|
||||||
|
std::string path_buf;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
FemmCurrDoc* femm_curr_doc_new(void) {
|
||||||
|
auto* d = new FemmCurrDoc();
|
||||||
|
d->doc.TheView = &s_stub_view;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void femm_curr_doc_free(FemmCurrDoc* d) {
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void femm_curr_doc_set_progress(FemmCurrDoc* d, FemmCurrProgressFn fn, void* user) {
|
||||||
|
if (!d) return;
|
||||||
|
d->cb = fn;
|
||||||
|
d->user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
int femm_curr_doc_load_fec(FemmCurrDoc* 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_curr_doc_load_mesh(FemmCurrDoc* d) {
|
||||||
|
return (d && d->doc.LoadMesh()) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int femm_curr_doc_renumber(FemmCurrDoc* d) {
|
||||||
|
return (d && d->doc.Cuthill()) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocates a CBigComplexLinProb and runs AnalyzeProblem + WriteResults.
|
||||||
|
int femm_curr_doc_solve(FemmCurrDoc* d) {
|
||||||
|
if (!d) return 0;
|
||||||
|
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.AnalyzeProblem(L)) return 0;
|
||||||
|
if (!d->doc.WriteResults(L)) return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int femm_curr_doc_write_results(FemmCurrDoc* /*d*/, const char* /*out_path*/) {
|
||||||
|
// results currently emitted inline by solve(); reserved hook for explicit output redirection.
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
double femm_curr_doc_frequency (const FemmCurrDoc* d) { return d ? d->doc.Frequency : 0.0; }
|
||||||
|
int femm_curr_doc_axisymmetric (const FemmCurrDoc* d) { return (d && d->doc.ProblemType) ? 1 : 0; }
|
||||||
|
double femm_curr_doc_depth (const FemmCurrDoc* d) { return d ? d->doc.Depth : 0.0; }
|
||||||
|
double femm_curr_doc_precision (const FemmCurrDoc* d) { return d ? d->doc.Precision : 0.0; }
|
||||||
|
|
||||||
|
int femm_curr_doc_num_nodes (const FemmCurrDoc* d) { return d ? d->doc.NumNodes : 0; }
|
||||||
|
|
||||||
|
void femm_curr_doc_node (const FemmCurrDoc* 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_curr_doc_num_elements (const FemmCurrDoc* d) { return d ? d->doc.NumEls : 0; }
|
||||||
|
|
||||||
|
void femm_curr_doc_element (const FemmCurrDoc* 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_curr_doc_num_materials (const FemmCurrDoc* d) { return d ? d->doc.NumBlockProps : 0; }
|
||||||
|
int femm_curr_doc_num_boundaries (const FemmCurrDoc* d) { return d ? d->doc.NumLineProps : 0; }
|
||||||
|
int femm_curr_doc_num_conductors (const FemmCurrDoc* d) { return d ? d->doc.NumCircProps : 0; }
|
||||||
|
|
||||||
|
// field sampling is post-processor territory; not exposed by the solver alone.
|
||||||
|
double femm_curr_doc_field_at (const FemmCurrDoc* /*d*/, double /*x*/, double /*y*/, FemmCurrField /*c*/) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
// C ABI for the current-flow solver (csolv): opaque doc, pipeline, mesh accessors, progress callback.
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct FemmCurrDoc FemmCurrDoc;
|
||||||
|
|
||||||
|
// pct in 0..100, or -1 for label-only updates. label may be NULL.
|
||||||
|
typedef void (*FemmCurrProgressFn)(int pct, const char* label, void* user);
|
||||||
|
|
||||||
|
// lifetime
|
||||||
|
FemmCurrDoc* femm_curr_doc_new(void);
|
||||||
|
void femm_curr_doc_free(FemmCurrDoc* doc);
|
||||||
|
|
||||||
|
// progress reporting routed to the host (Rust/Iced).
|
||||||
|
void femm_curr_doc_set_progress(FemmCurrDoc* doc, FemmCurrProgressFn fn, void* user);
|
||||||
|
|
||||||
|
// pipeline. each returns 1 on success, 0 on failure.
|
||||||
|
int femm_curr_doc_load_fec (FemmCurrDoc* doc, const char* path);
|
||||||
|
int femm_curr_doc_load_mesh (FemmCurrDoc* doc);
|
||||||
|
int femm_curr_doc_renumber (FemmCurrDoc* doc);
|
||||||
|
int femm_curr_doc_solve (FemmCurrDoc* doc);
|
||||||
|
int femm_curr_doc_write_results(FemmCurrDoc* doc, const char* out_path);
|
||||||
|
|
||||||
|
// problem attributes after load_fec.
|
||||||
|
double femm_curr_doc_frequency (const FemmCurrDoc* doc);
|
||||||
|
int femm_curr_doc_axisymmetric (const FemmCurrDoc* doc);
|
||||||
|
double femm_curr_doc_depth (const FemmCurrDoc* doc);
|
||||||
|
double femm_curr_doc_precision (const FemmCurrDoc* doc);
|
||||||
|
|
||||||
|
// mesh, valid after load_mesh + renumber.
|
||||||
|
int femm_curr_doc_num_nodes (const FemmCurrDoc* doc);
|
||||||
|
void femm_curr_doc_node (const FemmCurrDoc* doc, int i, double* x, double* y);
|
||||||
|
int femm_curr_doc_num_elements (const FemmCurrDoc* doc);
|
||||||
|
void femm_curr_doc_element (const FemmCurrDoc* doc, int i, int* p0, int* p1, int* p2);
|
||||||
|
|
||||||
|
// property table sizes.
|
||||||
|
int femm_curr_doc_num_materials (const FemmCurrDoc* doc);
|
||||||
|
int femm_curr_doc_num_boundaries (const FemmCurrDoc* doc);
|
||||||
|
int femm_curr_doc_num_conductors (const FemmCurrDoc* doc);
|
||||||
|
|
||||||
|
// field-point sampling after solve. component selects which scalar to fetch.
|
||||||
|
typedef enum {
|
||||||
|
FEMM_CURR_FIELD_V_RE = 0,
|
||||||
|
FEMM_CURR_FIELD_V_IM = 1,
|
||||||
|
FEMM_CURR_FIELD_EX_RE = 2,
|
||||||
|
FEMM_CURR_FIELD_EX_IM = 3,
|
||||||
|
FEMM_CURR_FIELD_EY_RE = 4,
|
||||||
|
FEMM_CURR_FIELD_EY_IM = 5,
|
||||||
|
FEMM_CURR_FIELD_E_MAG_RE = 6,
|
||||||
|
FEMM_CURR_FIELD_E_MAG_IM = 7,
|
||||||
|
FEMM_CURR_FIELD_JX_RE = 8,
|
||||||
|
FEMM_CURR_FIELD_JX_IM = 9,
|
||||||
|
FEMM_CURR_FIELD_JY_RE = 10,
|
||||||
|
FEMM_CURR_FIELD_JY_IM = 11,
|
||||||
|
FEMM_CURR_FIELD_J_MAG_RE = 12,
|
||||||
|
FEMM_CURR_FIELD_J_MAG_IM = 13,
|
||||||
|
} FemmCurrField;
|
||||||
|
|
||||||
|
double femm_curr_doc_field_at(const FemmCurrDoc* doc, double x, double y, FemmCurrField component);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,122 @@
|
||||||
|
// electrostatic FFI body: opaque doc, pipeline, mesh accessors. delegates to belasolv's CFemmeDocCore.
|
||||||
|
|
||||||
|
#include "../belasolv/StdAfx.h"
|
||||||
|
#include "../belasolv/belasolvDlg.h"
|
||||||
|
#include "../belasolv/mesh.h"
|
||||||
|
#include "../belasolv/spars.h"
|
||||||
|
#include "../belasolv/femmedoccore.h"
|
||||||
|
|
||||||
|
#include "femm_elec.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdarg>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// stub view: math files reference TheView globally, math methods call SetPos/SetDlgItemText/InvalidateRect on it.
|
||||||
|
static CbelasolvDlg s_stub_view;
|
||||||
|
CbelasolvDlg* 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 belasolv/main.cpp's old_main wait loop; main.cpp itself is not linked here.
|
||||||
|
inline bool IsWindow(void*) { return true; }
|
||||||
|
|
||||||
|
struct FemmElecDoc {
|
||||||
|
CFemmeDocCore doc;
|
||||||
|
FemmElecProgressFn cb = nullptr;
|
||||||
|
void* user = nullptr;
|
||||||
|
std::string path_buf;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
FemmElecDoc* femm_elec_doc_new(void) {
|
||||||
|
auto* d = new FemmElecDoc();
|
||||||
|
d->doc.TheView = &s_stub_view;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void femm_elec_doc_free(FemmElecDoc* d) {
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void femm_elec_doc_set_progress(FemmElecDoc* d, FemmElecProgressFn fn, void* user) {
|
||||||
|
if (!d) return;
|
||||||
|
d->cb = fn;
|
||||||
|
d->user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
int femm_elec_doc_load_fee(FemmElecDoc* 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_elec_doc_load_mesh(FemmElecDoc* d) {
|
||||||
|
return (d && d->doc.LoadMesh()) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int femm_elec_doc_renumber(FemmElecDoc* d) {
|
||||||
|
return (d && d->doc.Cuthill()) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocates a real-valued CBigLinProb and runs AnalyzeProblem + WriteResults.
|
||||||
|
int femm_elec_doc_solve(FemmElecDoc* d) {
|
||||||
|
if (!d) return 0;
|
||||||
|
CBigLinProb L;
|
||||||
|
L.TheView = &s_stub_view;
|
||||||
|
L.Precision = d->doc.Precision;
|
||||||
|
if (!L.Create(d->doc.NumNodes + d->doc.NumCircProps, d->doc.BandWidth)) return 0;
|
||||||
|
if (!d->doc.AnalyzeProblem(L)) return 0;
|
||||||
|
if (!d->doc.WriteResults(L)) return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int femm_elec_doc_write_results(FemmElecDoc* /*d*/, const char* /*out_path*/) {
|
||||||
|
// results currently emitted inline by solve(); reserved hook for explicit output redirection.
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int femm_elec_doc_axisymmetric (const FemmElecDoc* d) { return (d && d->doc.ProblemType) ? 1 : 0; }
|
||||||
|
double femm_elec_doc_depth (const FemmElecDoc* d) { return d ? d->doc.Depth : 0.0; }
|
||||||
|
double femm_elec_doc_precision (const FemmElecDoc* d) { return d ? d->doc.Precision : 0.0; }
|
||||||
|
|
||||||
|
int femm_elec_doc_num_nodes (const FemmElecDoc* d) { return d ? d->doc.NumNodes : 0; }
|
||||||
|
|
||||||
|
void femm_elec_doc_node (const FemmElecDoc* 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_elec_doc_num_elements (const FemmElecDoc* d) { return d ? d->doc.NumEls : 0; }
|
||||||
|
|
||||||
|
void femm_elec_doc_element (const FemmElecDoc* 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_elec_doc_num_materials (const FemmElecDoc* d) { return d ? d->doc.NumBlockProps : 0; }
|
||||||
|
int femm_elec_doc_num_boundaries (const FemmElecDoc* d) { return d ? d->doc.NumLineProps : 0; }
|
||||||
|
int femm_elec_doc_num_conductors (const FemmElecDoc* d) { return d ? d->doc.NumCircProps : 0; }
|
||||||
|
|
||||||
|
// field sampling is post-processor territory; not exposed by the solver alone.
|
||||||
|
double femm_elec_doc_field_at (const FemmElecDoc* /*d*/, double /*x*/, double /*y*/, FemmElecField /*c*/) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
// C ABI for the electrostatic solver (belasolv): opaque doc, pipeline, mesh accessors, progress callback.
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct FemmElecDoc FemmElecDoc;
|
||||||
|
|
||||||
|
// pct in 0..100, or -1 for label-only updates. label may be NULL.
|
||||||
|
typedef void (*FemmElecProgressFn)(int pct, const char* label, void* user);
|
||||||
|
|
||||||
|
// lifetime
|
||||||
|
FemmElecDoc* femm_elec_doc_new(void);
|
||||||
|
void femm_elec_doc_free(FemmElecDoc* doc);
|
||||||
|
|
||||||
|
// progress reporting routed to the host (Rust/Iced).
|
||||||
|
void femm_elec_doc_set_progress(FemmElecDoc* doc, FemmElecProgressFn fn, void* user);
|
||||||
|
|
||||||
|
// pipeline. each returns 1 on success, 0 on failure.
|
||||||
|
int femm_elec_doc_load_fee (FemmElecDoc* doc, const char* path);
|
||||||
|
int femm_elec_doc_load_mesh (FemmElecDoc* doc);
|
||||||
|
int femm_elec_doc_renumber (FemmElecDoc* doc);
|
||||||
|
int femm_elec_doc_solve (FemmElecDoc* doc);
|
||||||
|
int femm_elec_doc_write_results(FemmElecDoc* doc, const char* out_path);
|
||||||
|
|
||||||
|
// problem attributes after load_fee.
|
||||||
|
int femm_elec_doc_axisymmetric (const FemmElecDoc* doc);
|
||||||
|
double femm_elec_doc_depth (const FemmElecDoc* doc);
|
||||||
|
double femm_elec_doc_precision (const FemmElecDoc* doc);
|
||||||
|
|
||||||
|
// mesh, valid after load_mesh + renumber.
|
||||||
|
int femm_elec_doc_num_nodes (const FemmElecDoc* doc);
|
||||||
|
void femm_elec_doc_node (const FemmElecDoc* doc, int i, double* x, double* y);
|
||||||
|
int femm_elec_doc_num_elements (const FemmElecDoc* doc);
|
||||||
|
void femm_elec_doc_element (const FemmElecDoc* doc, int i, int* p0, int* p1, int* p2);
|
||||||
|
|
||||||
|
// property table sizes.
|
||||||
|
int femm_elec_doc_num_materials (const FemmElecDoc* doc);
|
||||||
|
int femm_elec_doc_num_boundaries (const FemmElecDoc* doc);
|
||||||
|
int femm_elec_doc_num_conductors (const FemmElecDoc* doc);
|
||||||
|
|
||||||
|
// field-point sampling after solve. component selects which scalar to fetch.
|
||||||
|
typedef enum {
|
||||||
|
FEMM_ELEC_FIELD_V = 0,
|
||||||
|
FEMM_ELEC_FIELD_EX = 1,
|
||||||
|
FEMM_ELEC_FIELD_EY = 2,
|
||||||
|
FEMM_ELEC_FIELD_E_MAG = 3,
|
||||||
|
FEMM_ELEC_FIELD_DX = 4,
|
||||||
|
FEMM_ELEC_FIELD_DY = 5,
|
||||||
|
FEMM_ELEC_FIELD_D_MAG = 6,
|
||||||
|
} FemmElecField;
|
||||||
|
|
||||||
|
double femm_elec_doc_field_at(const FemmElecDoc* doc, double x, double y, FemmElecField component);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,128 @@
|
||||||
|
// heat-flow FFI body: opaque doc, pipeline, mesh accessors. delegates to hsolv's Chsolvdoc.
|
||||||
|
|
||||||
|
#include "../hsolv/StdAfx.h"
|
||||||
|
#include "../hsolv/hsolvDlg.h"
|
||||||
|
#include "../hsolv/mesh.h"
|
||||||
|
#include "../hsolv/spars.h"
|
||||||
|
#include "../hsolv/hsolvdoc.h"
|
||||||
|
|
||||||
|
#include "femm_heat.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdarg>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// stub view: math files reference TheView globally, math methods call SetPos/SetDlgItemText/InvalidateRect on it.
|
||||||
|
static ChsolvDlg s_stub_view;
|
||||||
|
ChsolvDlg* 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 hsolv/main.cpp's old_main wait loop; main.cpp itself is not linked here.
|
||||||
|
inline bool IsWindow(void*) { return true; }
|
||||||
|
|
||||||
|
struct FemmHeatDoc {
|
||||||
|
Chsolvdoc doc;
|
||||||
|
FemmHeatProgressFn cb = nullptr;
|
||||||
|
void* user = nullptr;
|
||||||
|
std::string path_buf;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
FemmHeatDoc* femm_heat_doc_new(void) {
|
||||||
|
auto* d = new FemmHeatDoc();
|
||||||
|
d->doc.TheView = &s_stub_view;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void femm_heat_doc_free(FemmHeatDoc* d) {
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void femm_heat_doc_set_progress(FemmHeatDoc* d, FemmHeatProgressFn fn, void* user) {
|
||||||
|
if (!d) return;
|
||||||
|
d->cb = fn;
|
||||||
|
d->user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
int femm_heat_doc_load_feh(FemmHeatDoc* 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_heat_doc_load_mesh(FemmHeatDoc* d) {
|
||||||
|
return (d && d->doc.LoadMesh()) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// loads the previous temperature solution referenced by the .feh.
|
||||||
|
int femm_heat_doc_load_prev(FemmHeatDoc* d) {
|
||||||
|
return (d && d->doc.LoadPrev()) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int femm_heat_doc_renumber(FemmHeatDoc* d) {
|
||||||
|
return (d && d->doc.Cuthill()) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocates a real-valued CBigLinProb and runs AnalyzeProblem + WriteResults.
|
||||||
|
int femm_heat_doc_solve(FemmHeatDoc* d) {
|
||||||
|
if (!d) return 0;
|
||||||
|
CBigLinProb L;
|
||||||
|
L.TheView = &s_stub_view;
|
||||||
|
L.Precision = d->doc.Precision;
|
||||||
|
if (!L.Create(d->doc.NumNodes + d->doc.NumCircProps, d->doc.BandWidth)) return 0;
|
||||||
|
if (!d->doc.AnalyzeProblem(L)) return 0;
|
||||||
|
if (!d->doc.WriteResults(L)) return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int femm_heat_doc_write_results(FemmHeatDoc* /*d*/, const char* /*out_path*/) {
|
||||||
|
// results currently emitted inline by solve(); reserved hook for explicit output redirection.
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int femm_heat_doc_axisymmetric (const FemmHeatDoc* d) { return (d && d->doc.ProblemType) ? 1 : 0; }
|
||||||
|
double femm_heat_doc_depth (const FemmHeatDoc* d) { return d ? d->doc.Depth : 0.0; }
|
||||||
|
double femm_heat_doc_precision (const FemmHeatDoc* d) { return d ? d->doc.Precision : 0.0; }
|
||||||
|
double femm_heat_doc_dt (const FemmHeatDoc* d) { return d ? d->doc.dT : 0.0; }
|
||||||
|
|
||||||
|
int femm_heat_doc_num_nodes (const FemmHeatDoc* d) { return d ? d->doc.NumNodes : 0; }
|
||||||
|
|
||||||
|
void femm_heat_doc_node (const FemmHeatDoc* 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_heat_doc_num_elements (const FemmHeatDoc* d) { return d ? d->doc.NumEls : 0; }
|
||||||
|
|
||||||
|
void femm_heat_doc_element (const FemmHeatDoc* 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_heat_doc_num_materials (const FemmHeatDoc* d) { return d ? d->doc.NumBlockProps : 0; }
|
||||||
|
int femm_heat_doc_num_boundaries (const FemmHeatDoc* d) { return d ? d->doc.NumLineProps : 0; }
|
||||||
|
int femm_heat_doc_num_conductors (const FemmHeatDoc* d) { return d ? d->doc.NumCircProps : 0; }
|
||||||
|
|
||||||
|
// field sampling is post-processor territory; not exposed by the solver alone.
|
||||||
|
double femm_heat_doc_field_at (const FemmHeatDoc* /*d*/, double /*x*/, double /*y*/, FemmHeatField /*c*/) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
// C ABI for the heat-flow solver (hsolv): opaque doc, pipeline, mesh accessors, progress callback.
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct FemmHeatDoc FemmHeatDoc;
|
||||||
|
|
||||||
|
// pct in 0..100, or -1 for label-only updates. label may be NULL.
|
||||||
|
typedef void (*FemmHeatProgressFn)(int pct, const char* label, void* user);
|
||||||
|
|
||||||
|
// lifetime
|
||||||
|
FemmHeatDoc* femm_heat_doc_new(void);
|
||||||
|
void femm_heat_doc_free(FemmHeatDoc* doc);
|
||||||
|
|
||||||
|
// progress reporting routed to the host (Rust/Iced).
|
||||||
|
void femm_heat_doc_set_progress(FemmHeatDoc* doc, FemmHeatProgressFn fn, void* user);
|
||||||
|
|
||||||
|
// pipeline. each returns 1 on success, 0 on failure.
|
||||||
|
int femm_heat_doc_load_feh (FemmHeatDoc* doc, const char* path);
|
||||||
|
int femm_heat_doc_load_mesh (FemmHeatDoc* doc);
|
||||||
|
int femm_heat_doc_load_prev (FemmHeatDoc* doc);
|
||||||
|
int femm_heat_doc_renumber (FemmHeatDoc* doc);
|
||||||
|
int femm_heat_doc_solve (FemmHeatDoc* doc);
|
||||||
|
int femm_heat_doc_write_results(FemmHeatDoc* doc, const char* out_path);
|
||||||
|
|
||||||
|
// problem attributes after load_feh.
|
||||||
|
int femm_heat_doc_axisymmetric (const FemmHeatDoc* doc);
|
||||||
|
double femm_heat_doc_depth (const FemmHeatDoc* doc);
|
||||||
|
double femm_heat_doc_precision (const FemmHeatDoc* doc);
|
||||||
|
double femm_heat_doc_dt (const FemmHeatDoc* doc);
|
||||||
|
|
||||||
|
// mesh, valid after load_mesh + renumber.
|
||||||
|
int femm_heat_doc_num_nodes (const FemmHeatDoc* doc);
|
||||||
|
void femm_heat_doc_node (const FemmHeatDoc* doc, int i, double* x, double* y);
|
||||||
|
int femm_heat_doc_num_elements (const FemmHeatDoc* doc);
|
||||||
|
void femm_heat_doc_element (const FemmHeatDoc* doc, int i, int* p0, int* p1, int* p2);
|
||||||
|
|
||||||
|
// property table sizes.
|
||||||
|
int femm_heat_doc_num_materials (const FemmHeatDoc* doc);
|
||||||
|
int femm_heat_doc_num_boundaries (const FemmHeatDoc* doc);
|
||||||
|
int femm_heat_doc_num_conductors (const FemmHeatDoc* doc);
|
||||||
|
|
||||||
|
// field-point sampling after solve. component selects which scalar to fetch.
|
||||||
|
typedef enum {
|
||||||
|
FEMM_HEAT_FIELD_T = 0,
|
||||||
|
FEMM_HEAT_FIELD_FX = 1,
|
||||||
|
FEMM_HEAT_FIELD_FY = 2,
|
||||||
|
FEMM_HEAT_FIELD_F_MAG = 3,
|
||||||
|
FEMM_HEAT_FIELD_GX = 4,
|
||||||
|
FEMM_HEAT_FIELD_GY = 5,
|
||||||
|
FEMM_HEAT_FIELD_G_MAG = 6,
|
||||||
|
} FemmHeatField;
|
||||||
|
|
||||||
|
double femm_heat_doc_field_at(const FemmHeatDoc* doc, double x, double y, FemmHeatField component);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
// CComplex comparison ops, long-to-CComplex ctor, and 2-arg atan2 missing from fkn/complex.cpp.
|
||||||
|
|
||||||
|
#include "../liblua/COMPLEX.H"
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
bool CComplex::operator<(const CComplex& z) { return re < z.re; }
|
||||||
|
bool CComplex::operator<(double z) { return re < z; }
|
||||||
|
bool CComplex::operator<(int z) { return re < (double)z; }
|
||||||
|
bool CComplex::operator<(long long z) { return re < (double)z; }
|
||||||
|
|
||||||
|
bool CComplex::operator>(const CComplex& z) { return re > z.re; }
|
||||||
|
bool CComplex::operator>(double z) { return re > z; }
|
||||||
|
bool CComplex::operator>(int z) { return re > (double)z; }
|
||||||
|
bool CComplex::operator>(long long z) { return re > (double)z; }
|
||||||
|
|
||||||
|
bool CComplex::operator<=(const CComplex& z) { return re <= z.re; }
|
||||||
|
bool CComplex::operator<=(double z) { return re <= z; }
|
||||||
|
bool CComplex::operator<=(int z) { return re <= (double)z; }
|
||||||
|
bool CComplex::operator<=(long long z) { return re <= (double)z; }
|
||||||
|
|
||||||
|
bool CComplex::operator>=(const CComplex& z) { return re >= z.re; }
|
||||||
|
bool CComplex::operator>=(double z) { return re >= z; }
|
||||||
|
bool CComplex::operator>=(int z) { return re >= (double)z; }
|
||||||
|
bool CComplex::operator>=(long long z) { return re >= (double)z; }
|
||||||
|
|
||||||
|
CComplex::CComplex(long x) { re = (double)x; im = 0.0; }
|
||||||
|
CComplex::CComplex(long long x) { re = (double)x; im = 0.0; }
|
||||||
|
|
||||||
|
// 2-arg atan2 over CComplex.
|
||||||
|
CComplex atan2(const CComplex& y, const CComplex& x) {
|
||||||
|
if (y.im == 0 && x.im == 0) return CComplex(std::atan2(y.re, x.re), 0);
|
||||||
|
return atan(y / x);
|
||||||
|
}
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
#include "../fkn/spars.h"
|
#include "../fkn/spars.h"
|
||||||
#include "../fkn/mesh.h"
|
#include "../fkn/mesh.h"
|
||||||
#include "../fkn/FemmeDocCore.h"
|
#include "../fkn/FemmeDocCore.h"
|
||||||
|
#include "../fkn/lua.h"
|
||||||
|
|
||||||
#include "femm_mag.h"
|
#include "femm_mag.h"
|
||||||
|
|
||||||
|
|
@ -13,6 +14,25 @@
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <string>
|
#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.
|
// stub view: math files reference TheView globally, math methods call SetPos/SetDlgItemText/InvalidateRect on it.
|
||||||
static CFknDlg s_stub_view;
|
static CFknDlg s_stub_view;
|
||||||
CFknDlg* TheView = &s_stub_view;
|
CFknDlg* TheView = &s_stub_view;
|
||||||
|
|
@ -43,6 +63,7 @@ struct FemmMagDoc {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
FemmMagDoc* femm_mag_doc_new(void) {
|
FemmMagDoc* femm_mag_doc_new(void) {
|
||||||
|
ensure_lua_state();
|
||||||
auto* d = new FemmMagDoc();
|
auto* d = new FemmMagDoc();
|
||||||
d->doc.TheView = &s_stub_view;
|
d->doc.TheView = &s_stub_view;
|
||||||
return d;
|
return d;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# per-engine static archives for mag/elec/heat/curr with internal symbols localized via ld -exported_symbols_list.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT=$(cd "$(dirname "$0")/../.." && pwd)
|
||||||
|
BUILD=${BUILD:-"$ROOT/build/ffi"}
|
||||||
|
|
||||||
|
CXX=${CXX:-clang++}
|
||||||
|
LD=${LD:-ld}
|
||||||
|
AR=${AR:-ar}
|
||||||
|
CXXFLAGS=${CXXFLAGS:-"-std=c++17 -fno-exceptions -fno-rtti -O2 -w"}
|
||||||
|
|
||||||
|
mkdir -p "$BUILD"/{fkn,liblua,belasolv,csolv,hsolv,ffi}
|
||||||
|
|
||||||
|
compile() {
|
||||||
|
local incs="$1"; shift
|
||||||
|
local outdir="$1"; shift
|
||||||
|
for src in "$@"; do
|
||||||
|
local base
|
||||||
|
base=$(basename "$src")
|
||||||
|
base=${base%.cpp}
|
||||||
|
base=${base%.CPP}
|
||||||
|
$CXX $CXXFLAGS $incs -c "$src" -o "$outdir/${base}.o"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# liblua compiled against fkn's complex.h.
|
||||||
|
compile "-I $ROOT/fkn -I $ROOT/liblua -I $ROOT/compat" \
|
||||||
|
"$BUILD/liblua" \
|
||||||
|
"$ROOT/liblua/lapi.cpp" "$ROOT/liblua/lauxlib.cpp" "$ROOT/liblua/lbaselib.cpp" \
|
||||||
|
"$ROOT/liblua/lcode.cpp" "$ROOT/liblua/ldblib.cpp" "$ROOT/liblua/ldebug.cpp" \
|
||||||
|
"$ROOT/liblua/ldo.cpp" "$ROOT/liblua/lfunc.cpp" "$ROOT/liblua/lgc.cpp" \
|
||||||
|
"$ROOT/liblua/liolib.cpp" "$ROOT/liblua/llex.cpp" "$ROOT/liblua/lmathlib.cpp" \
|
||||||
|
"$ROOT/liblua/lmem.cpp" "$ROOT/liblua/lobject.cpp" "$ROOT/liblua/lparser.cpp" \
|
||||||
|
"$ROOT/liblua/lstate.cpp" "$ROOT/liblua/lstring.cpp" "$ROOT/liblua/lstrlib.cpp" \
|
||||||
|
"$ROOT/liblua/ltable.cpp" "$ROOT/liblua/ltests.cpp" "$ROOT/liblua/ltm.cpp" \
|
||||||
|
"$ROOT/liblua/lundump.cpp" "$ROOT/liblua/lvm.cpp" "$ROOT/liblua/lzio.cpp"
|
||||||
|
|
||||||
|
compile "-I $ROOT/fkn -I $ROOT/compat" \
|
||||||
|
"$BUILD/fkn" \
|
||||||
|
"$ROOT/fkn/complex.cpp" "$ROOT/fkn/cspars.cpp" "$ROOT/fkn/cuthill.cpp" \
|
||||||
|
"$ROOT/fkn/femmedoccore.cpp" "$ROOT/fkn/fullmatrix.cpp" "$ROOT/fkn/matprop.cpp" \
|
||||||
|
"$ROOT/fkn/prob1big.cpp" "$ROOT/fkn/prob2big.cpp" "$ROOT/fkn/prob3big.cpp" \
|
||||||
|
"$ROOT/fkn/prob4big.cpp" "$ROOT/fkn/spars.cpp"
|
||||||
|
|
||||||
|
compile "-I $ROOT/belasolv -I $ROOT/compat" \
|
||||||
|
"$BUILD/belasolv" \
|
||||||
|
"$ROOT/belasolv/cuthill.cpp" "$ROOT/belasolv/femmedoccore.cpp" \
|
||||||
|
"$ROOT/belasolv/prob1big.cpp" "$ROOT/belasolv/spars.cpp"
|
||||||
|
|
||||||
|
compile "-I $ROOT/csolv -I $ROOT/compat" \
|
||||||
|
"$BUILD/csolv" \
|
||||||
|
"$ROOT/csolv/complex.cpp" "$ROOT/csolv/cspars.cpp" "$ROOT/csolv/CUTHILL.CPP" \
|
||||||
|
"$ROOT/csolv/femmedoccore.cpp" "$ROOT/csolv/PROB1BIG.CPP"
|
||||||
|
|
||||||
|
compile "-I $ROOT/hsolv -I $ROOT/compat" \
|
||||||
|
"$BUILD/hsolv" \
|
||||||
|
"$ROOT/hsolv/complex.cpp" "$ROOT/hsolv/CUTHILL.CPP" "$ROOT/hsolv/hsolvdoc.cpp" \
|
||||||
|
"$ROOT/hsolv/prob1big.cpp" "$ROOT/hsolv/SPARS.CPP"
|
||||||
|
|
||||||
|
# ffi translation units, one per engine plus the liblua complex-op shim.
|
||||||
|
$CXX $CXXFLAGS -I "$ROOT/fkn" -I "$ROOT/compat" -c "$ROOT/ffi/femm_mag.cpp" -o "$BUILD/ffi/femm_mag.o"
|
||||||
|
$CXX $CXXFLAGS -I "$ROOT/belasolv" -I "$ROOT/compat" -c "$ROOT/ffi/femm_elec.cpp" -o "$BUILD/ffi/femm_elec.o"
|
||||||
|
$CXX $CXXFLAGS -I "$ROOT/hsolv" -I "$ROOT/compat" -c "$ROOT/ffi/femm_heat.cpp" -o "$BUILD/ffi/femm_heat.o"
|
||||||
|
$CXX $CXXFLAGS -I "$ROOT/csolv" -I "$ROOT/compat" -c "$ROOT/ffi/femm_curr.cpp" -o "$BUILD/ffi/femm_curr.o"
|
||||||
|
$CXX $CXXFLAGS -I "$ROOT/liblua" -I "$ROOT/compat" -c "$ROOT/ffi/femm_lua_complex_ops.cpp" -o "$BUILD/ffi/femm_lua_complex_ops.o"
|
||||||
|
|
||||||
|
# per-engine exported-symbols lists.
|
||||||
|
exports_for() {
|
||||||
|
local prefix="$1"
|
||||||
|
nm "$BUILD/ffi/femm_${prefix}.o" | awk -v p="$prefix" '
|
||||||
|
$2=="T" && $3 ~ ("^_femm_" p "_") { print $3 }
|
||||||
|
'
|
||||||
|
}
|
||||||
|
|
||||||
|
mkdir -p "$BUILD/exports"
|
||||||
|
exports_for mag > "$BUILD/exports/mag.txt"
|
||||||
|
exports_for elec > "$BUILD/exports/elec.txt"
|
||||||
|
exports_for heat > "$BUILD/exports/heat.txt"
|
||||||
|
exports_for curr > "$BUILD/exports/curr.txt"
|
||||||
|
|
||||||
|
# merges each engine into a relocatable object and archives it.
|
||||||
|
$LD -r "$BUILD"/fkn/*.o "$BUILD"/liblua/*.o "$BUILD"/ffi/femm_mag.o "$BUILD"/ffi/femm_lua_complex_ops.o \
|
||||||
|
-exported_symbols_list "$BUILD/exports/mag.txt" -o "$BUILD/femm_mag_merged.o"
|
||||||
|
$LD -r "$BUILD"/belasolv/*.o "$BUILD"/ffi/femm_elec.o \
|
||||||
|
-exported_symbols_list "$BUILD/exports/elec.txt" -o "$BUILD/femm_elec_merged.o"
|
||||||
|
$LD -r "$BUILD"/hsolv/*.o "$BUILD"/ffi/femm_heat.o \
|
||||||
|
-exported_symbols_list "$BUILD/exports/heat.txt" -o "$BUILD/femm_heat_merged.o"
|
||||||
|
$LD -r "$BUILD"/csolv/*.o "$BUILD"/ffi/femm_curr.o \
|
||||||
|
-exported_symbols_list "$BUILD/exports/curr.txt" -o "$BUILD/femm_curr_merged.o"
|
||||||
|
|
||||||
|
rm -f "$BUILD"/libfemm_*.a
|
||||||
|
$AR rcs "$BUILD/libfemm_mag.a" "$BUILD/femm_mag_merged.o"
|
||||||
|
$AR rcs "$BUILD/libfemm_elec.a" "$BUILD/femm_elec_merged.o"
|
||||||
|
$AR rcs "$BUILD/libfemm_heat.a" "$BUILD/femm_heat_merged.o"
|
||||||
|
$AR rcs "$BUILD/libfemm_curr.a" "$BUILD/femm_curr_merged.o"
|
||||||
|
|
||||||
|
echo "built:"
|
||||||
|
ls -lh "$BUILD"/libfemm_*.a
|
||||||
Loading…
Reference in New Issue