// 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 #include #include // 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(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"