diff --git a/assets/femm.svg b/assets/femm.svg index 3f24543..3271172 100644 --- a/assets/femm.svg +++ b/assets/femm.svg @@ -1,5 +1,5 @@ - - - + + + \ No newline at end of file diff --git a/crates/femm-app/assets/brgmodel.fem b/crates/femm-app/assets/brgmodel.fem new file mode 100644 index 0000000..23bba48 --- /dev/null +++ b/crates/femm-app/assets/brgmodel.fem @@ -0,0 +1,423 @@ +[Format] = 4.0 +[Frequency] = 0 +[Precision] = 1e-008 +[MinAngle] = 30 +[Depth] = 1.6000000000000001 +[LengthUnits] = inches +[ProblemType] = planar +[Coordinates] = cartesian +[Comment] = "Add comments here." +[PointProps] = 0 +[BdryProps] = 1 + + = "A=0" + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + +[BlockProps] = 6 + + = "Air" + = 1 + = 1 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + + + = "J+" + = 1 + = 1 + = 0 + = 0 + = 4.2199999999999998 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + + + = "J-" + = 1 + = 1 + = 0 + = 0 + = -4.2199999999999998 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + + + = "Iron" + = 2500 + = 2500 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + + + = "M-19 Steel" + = 4416 + = 4416 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 13 + 0 0 + 0.29999999999999999 39.78875 + 0.80000000000000004 79.577500000000001 + 1.1200000000000001 159.155 + 1.3200000000000001 318.31 + 1.46 795.77499999999998 + 1.54 1591.55 + 1.6187499999999999 3376.6669999999999 + 1.74 7957.75 + 1.8700000000000001 15915.5 + 1.99 31831 + 2.0459640000000001 55102.040000000001 + 2.0800000000000001 79577.5 + + + = "18 AWG" + = 1 + = 1 + = 0 + = 0 + = 0 + = 0 + = 58 + = 0 + = 0 + = 0 + = 0 + = 3 + = 1 + = 1 + = 1.0239652968433499 + = 0 + +[CircuitProps] = 4 + + = "i1" + = 6 + = 0 + = 1 + + + = "i2" + = 12 + = 0 + = 1 + + + = "i3" + = 6 + = 0 + = 1 + + + = "i4" + = 0 + = 0 + = 1 + +[NumPoints] = 102 +0.92388000000000003 -0.382683 0 0 +-0.92388000000000003 0.382683 0 0 +1.020017 -0.20289399999999999 0 0 +0.86472899999999997 -0.577793 0 0 +0.86472800000000005 0.577793 0 0 +1.020016 0.20289399999999999 0 0 +0.20289399999999999 1.020017 0 0 +0.577793 0.86472899999999997 0 0 +-0.577793 0.86472800000000005 0 0 +-0.20289399999999999 1.020016 0 0 +-0.20289399999999999 -1.020017 0 0 +-0.577793 -0.86472899999999997 0 0 +0.577793 -0.86472800000000005 0 0 +0.20289399999999999 -1.020016 0 0 +-0.86472800000000005 -0.577793 0 0 +-1.020016 -0.20289399999999999 0 0 +-1.020017 0.20289399999999999 0 0 +-0.86472899999999997 0.577793 0 0 +1.9158710000000001 -0.57396899999999995 0 0 +1.7605820000000001 -0.94886800000000004 0 0 +1.7605820000000001 0.94886800000000004 0 0 +1.91587 0.57396899999999995 0 0 +0.57396899999999995 1.9158710000000001 0 0 +0.94886800000000004 1.7605820000000001 0 0 +-0.94886800000000004 1.7605820000000001 0 0 +-0.57396899999999995 1.91587 0 0 +-1.9158710000000001 0.57396899999999995 0 0 +-1.7605820000000001 0.94886800000000004 0 0 +-1.7605820000000001 -0.94886800000000004 0 0 +-1.91587 -0.57396899999999995 0 0 +-0.57396899999999995 -1.9158710000000001 0 0 +-0.94886800000000004 -1.7605820000000001 0 0 +0.94886800000000004 -1.7605820000000001 0 0 +0.57396899999999995 -1.91587 0 0 +2.217311 -0.91844000000000003 0 0 +-2.217311 0.91844000000000003 0 0 +0.55432800000000004 -0.22961000000000001 0 0 +-0.55432800000000004 0.22961000000000001 0 0 +1.3461909999999999 -0.016414999999999999 0 0 +0.96350800000000003 -0.94029399999999996 0 0 +1.9005190000000001 -0.24602499999999999 0 0 +1.517835 -1.1699040000000001 0 0 +1.232494 -0.29090500000000002 0 0 +1.077205 -0.66580399999999995 0 0 +1.786821 -0.52051499999999995 0 0 +1.6315329999999999 -0.89541400000000004 0 0 +0.96350800000000003 0.94029399999999996 0 0 +1.517835 1.1699040000000001 0 0 +1.3461909999999999 0.016414000000000002 0 0 +1.9005190000000001 0.24602399999999999 0 0 +1.077205 0.66580399999999995 0 0 +1.2324930000000001 0.29090500000000002 0 0 +1.6315329999999999 0.89541400000000004 0 0 +1.786821 0.52051499999999995 0 0 +0.016414999999999999 1.3461909999999999 0 0 +0.24602499999999999 1.9005190000000001 0 0 +0.94029399999999996 0.96350800000000003 0 0 +1.1699040000000001 1.517835 0 0 +0.29090500000000002 1.232494 0 0 +0.66580399999999995 1.077205 0 0 +0.52051499999999995 1.786821 0 0 +0.89541400000000004 1.6315329999999999 0 0 +-0.94029399999999996 0.96350800000000003 0 0 +-1.1699040000000001 1.517835 0 0 +-0.016414000000000002 1.3461909999999999 0 0 +-0.24602399999999999 1.9005190000000001 0 0 +-0.66580399999999995 1.077205 0 0 +-0.29090500000000002 1.2324930000000001 0 0 +-0.89541400000000004 1.6315329999999999 0 0 +-0.52051499999999995 1.786821 0 0 +-1.3461909999999999 0.016414999999999999 0 0 +-1.9005190000000001 0.24602499999999999 0 0 +-0.96350800000000003 0.94029399999999996 0 0 +-1.517835 1.1699040000000001 0 0 +-1.232494 0.29090500000000002 0 0 +-1.077205 0.66580399999999995 0 0 +-1.786821 0.52051499999999995 0 0 +-1.6315329999999999 0.89541400000000004 0 0 +-0.96350800000000003 -0.94029399999999996 0 0 +-1.517835 -1.1699040000000001 0 0 +-1.3461909999999999 -0.016414000000000002 0 0 +-1.9005190000000001 -0.24602399999999999 0 0 +-1.077205 -0.66580399999999995 0 0 +-1.2324930000000001 -0.29090500000000002 0 0 +-1.6315329999999999 -0.89541400000000004 0 0 +-1.786821 -0.52051499999999995 0 0 +-0.016414999999999999 -1.3461909999999999 0 0 +-0.24602499999999999 -1.9005190000000001 0 0 +-0.94029399999999996 -0.96350800000000003 0 0 +-1.1699040000000001 -1.517835 0 0 +-0.29090500000000002 -1.232494 0 0 +-0.66580399999999995 -1.077205 0 0 +-0.52051499999999995 -1.786821 0 0 +-0.89541400000000004 -1.6315329999999999 0 0 +0.94029399999999996 -0.96350800000000003 0 0 +1.1699040000000001 -1.517835 0 0 +0.016414000000000002 -1.3461909999999999 0 0 +0.24602399999999999 -1.9005190000000001 0 0 +0.66580399999999995 -1.077205 0 0 +0.29090500000000002 -1.2324930000000001 0 0 +0.89541400000000004 -1.6315329999999999 0 0 +0.52051499999999995 -1.786821 0 0 +[NumSegments] = 96 +4 50 -1 0 0 0 +50 52 -1 0 0 0 +52 20 -1 0 0 0 +5 51 -1 0 0 0 +51 53 -1 0 0 0 +53 21 -1 0 0 0 +6 58 -1 0 0 0 +58 60 -1 0 0 0 +60 22 -1 0 0 0 +7 59 -1 0 0 0 +59 61 -1 0 0 0 +61 23 -1 0 0 0 +8 66 -1 0 0 0 +66 68 -1 0 0 0 +68 24 -1 0 0 0 +9 67 -1 0 0 0 +67 69 -1 0 0 0 +69 25 -1 0 0 0 +16 74 -1 0 0 0 +74 76 -1 0 0 0 +76 26 -1 0 0 0 +17 75 -1 0 0 0 +75 77 -1 0 0 0 +77 27 -1 0 0 0 +14 82 -1 0 0 0 +82 84 -1 0 0 0 +84 28 -1 0 0 0 +15 83 -1 0 0 0 +83 85 -1 0 0 0 +85 29 -1 0 0 0 +10 90 -1 0 0 0 +90 92 -1 0 0 0 +92 30 -1 0 0 0 +11 91 -1 0 0 0 +91 93 -1 0 0 0 +93 31 -1 0 0 0 +12 98 -1 0 0 0 +98 100 -1 0 0 0 +100 32 -1 0 0 0 +13 99 -1 0 0 0 +99 101 -1 0 0 0 +101 33 -1 0 0 0 +2 42 -1 0 0 0 +3 43 -1 0 0 0 +38 40 -1 0 0 0 +39 41 -1 0 0 0 +42 44 -1 0 0 0 +43 45 -1 0 0 0 +38 42 -1 0 0 0 +43 39 -1 0 0 0 +44 18 -1 0 0 0 +45 19 -1 0 0 0 +40 44 -1 0 0 0 +45 41 -1 0 0 0 +46 47 -1 0 0 0 +48 49 -1 0 0 0 +46 50 -1 0 0 0 +51 48 -1 0 0 0 +47 52 -1 0 0 0 +53 49 -1 0 0 0 +54 55 -1 0 0 0 +56 57 -1 0 0 0 +54 58 -1 0 0 0 +59 56 -1 0 0 0 +55 60 -1 0 0 0 +61 57 -1 0 0 0 +62 63 -1 0 0 0 +64 65 -1 0 0 0 +62 66 -1 0 0 0 +67 64 -1 0 0 0 +63 68 -1 0 0 0 +69 65 -1 0 0 0 +70 71 -1 0 0 0 +72 73 -1 0 0 0 +70 74 -1 0 0 0 +75 72 -1 0 0 0 +71 76 -1 0 0 0 +77 73 -1 0 0 0 +78 79 -1 0 0 0 +80 81 -1 0 0 0 +78 82 -1 0 0 0 +83 80 -1 0 0 0 +79 84 -1 0 0 0 +85 81 -1 0 0 0 +86 87 -1 0 0 0 +88 89 -1 0 0 0 +86 90 -1 0 0 0 +91 88 -1 0 0 0 +87 92 -1 0 0 0 +93 89 -1 0 0 0 +94 95 -1 0 0 0 +96 97 -1 0 0 0 +94 98 -1 0 0 0 +99 96 -1 0 0 0 +95 100 -1 0 0 0 +101 97 -1 0 0 0 +[NumArcSegments] = 22 +0 1 180 2.5 0 0 0 +1 0 180 2.5 0 0 0 +5 4 22.5 2.5 0 0 0 +7 6 22.5 2.5 0 0 0 +9 8 22.5 2.5 0 0 0 +15 14 22.5 2.5 0 0 0 +11 10 22.5 2.5 0 0 0 +13 12 22.5 2.5 0 0 0 +3 2 22.5 2.5 0 0 0 +17 16 22.5 2.5 0 0 0 +26 29 33.355001000000001 2.5 0 0 0 +28 31 33.355001000000001 2.5 0 0 0 +30 33 33.355001000000001 2.5 0 0 0 +20 23 33.355001000000001 2.5 0 0 0 +22 25 33.355001000000001 2.5 0 0 0 +24 27 33.355001000000001 2.5 0 0 0 +34 35 180 2.5 1 0 0 +35 34 180 2.5 1 0 0 +36 37 180 2.5 0 0 0 +37 36 180 2.5 0 0 0 +32 19 33.355001000000001 2.5 0 0 0 +18 21 33.355001000000001 2.5 0 0 0 +[NumHoles] = 0 +[NumBlockLabels] = 20 +1.588257 -0.26821600000000001 6 0.050000000000000003 1 0 0 80 0 +1.557868 0.28556700000000002 6 0.050000000000000003 1 0 0 80 0 +0.29210599999999998 1.5675380000000001 6 0.050000000000000003 2 0 0 80 0 +-0.28939399999999998 1.548629 6 0.050000000000000003 2 0 0 80 0 +-1.5528869999999999 0.27521299999999999 6 0.050000000000000003 3 0 0 80 0 +-1.5078469999999999 -0.29546299999999998 6 0.050000000000000003 3 0 0 80 0 +-0.227434 -1.594325 6 0.050000000000000003 4 0 0 80 0 +0.32859100000000002 -1.5323929999999999 6 0.050000000000000003 4 0 0 80 0 +0.91271800000000003 -1.2980929999999999 6 0.050000000000000003 4 0 0 -80 0 +1.2764260000000001 -0.864255 6 0.050000000000000003 1 0 0 -80 0 +1.314986 0.92736799999999997 6 0.050000000000000003 1 0 0 -80 0 +0.88563099999999995 1.354163 6 0.050000000000000003 2 0 0 -80 0 +-0.89806699999999995 1.281201 6 0.050000000000000003 2 0 0 -80 0 +-1.296489 0.89421300000000004 6 0.050000000000000003 3 0 0 -80 0 +-1.2703770000000001 -0.92419799999999996 6 0.050000000000000003 3 0 0 -80 0 +-0.83719500000000002 -1.3417539999999999 6 0.050000000000000003 4 0 0 -80 0 +0.76536700000000002 1.8477589999999999 5 0.049999990000000001 0 0 0 1 0 +0.28701300000000002 0.69291000000000003 5 0.049999990000000001 0 0 0 1 0 +0 0 1 0.049999990000000001 0 0 0 1 0 +1.362606 1.329777 1 0.050000000000000003 0 0 0 1 0 diff --git a/crates/femm-app/src/doc_canvas.rs b/crates/femm-app/src/doc_canvas.rs index 1f35388..c693c8c 100644 --- a/crates/femm-app/src/doc_canvas.rs +++ b/crates/femm-app/src/doc_canvas.rs @@ -1,6 +1,7 @@ //! draws a FemmDoc on an iced canvas: nodes, segments, arcs, block labels, with pan/zoom and click-to-add. use femm_doc_mag::FemmDoc; +use femm_doc_mag::ans::MagSolution; use femm_doc_mag::mesh::Mesh; use iced::widget::canvas::{ self, Action, Canvas, Event, Frame, Geometry, Path, Stroke, Text, path::Builder, @@ -23,6 +24,20 @@ const SELECT_COLOR: Color = Color::from_rgb(0.95, 0.20, 0.20); const SELECT_STROKE: f32 = 2.4; const MESH_COLOR: Color = Color::from_rgba(0.55, 0.55, 0.55, 0.55); const MESH_STROKE: f32 = 0.5; +const FLUX_LINE_COLOR: Color = Color::from_rgba(0.0, 0.0, 0.0, 0.85); +const FLUX_LINE_STROKE: f32 = 0.6; +const BAND_COUNT: usize = 20; +const FLUX_LINE_COUNT: usize = 19; + +/// field-plot mode applied on top of the FE solution. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +pub enum RenderMode { + /// smooth |B| jet fill across every element. + Density, + /// 20-band |B| jet fill plus 19 iso-A flux lines. + #[default] + Contour, +} /// active editing mode on the canvas. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] @@ -59,13 +74,15 @@ pub struct ViewState { cursor_world: Option<(f64, f64)>, } -/// constructs the canvas widget for a doc reference and an optional mesh overlay. +/// constructs the canvas widget for a doc reference, optional mesh overlay, and optional solution. pub fn view<'a>( doc: &'a FemmDoc, tool: Tool, mesh: Option<&'a Mesh>, + solution: Option<&'a MagSolution>, + render_mode: RenderMode, ) -> Element<'a, CanvasMessage> { - Canvas::new(DocCanvas { doc, tool, mesh }) + Canvas::new(DocCanvas { doc, tool, mesh, solution, render_mode }) .width(Length::Fill) .height(Length::Fill) .into() @@ -75,6 +92,8 @@ struct DocCanvas<'a> { doc: &'a FemmDoc, tool: Tool, mesh: Option<&'a Mesh>, + solution: Option<&'a MagSolution>, + render_mode: RenderMode, } impl<'a> canvas::Program for DocCanvas<'a> { @@ -222,7 +241,55 @@ impl<'a> canvas::Program for DocCanvas<'a> { let view = ViewTransform::fit(self.doc, bounds, state); - if let Some(mesh) = self.mesh { + if let Some(sol) = self.solution { + let (lo, hi) = sol.b_magnitude_range(); + let span = if hi > lo { hi - lo } else { 1.0 }; + let banded = matches!(self.render_mode, RenderMode::Contour); + for i in 0..sol.mesh_elements.len() { + let el = &sol.mesh_elements[i]; + let (Some(a), Some(b), Some(c)) = ( + sol.mesh_nodes.get(el.n[0] as usize), + sol.mesh_nodes.get(el.n[1] as usize), + sol.mesh_nodes.get(el.n[2] as usize), + ) else { continue }; + let pa = view.map(a.x, a.y); + let pb = view.map(b.x, b.y); + let pc = view.map(c.x, c.y); + let t = ((sol.b_magnitude(i) - lo) / span).clamp(0.0, 1.0); + let t_mapped = if banded { + let band = (t * BAND_COUNT as f64).floor().min(BAND_COUNT as f64 - 1.0); + (band + 0.5) / BAND_COUNT as f64 + } else { + t + }; + let color = jet(t_mapped as f32); + let tri = Path::new(|p| { + p.move_to(pa); + p.line_to(pb); + p.line_to(pc); + p.close(); + }); + frame.fill(&tri, color); + } + if matches!(self.render_mode, RenderMode::Contour) { + let (a_lo, a_hi) = sol.a_real_range(); + if a_hi > a_lo { + let mut levels = Vec::with_capacity(FLUX_LINE_COUNT); + let denom = (FLUX_LINE_COUNT + 1) as f64; + for k in 1..=FLUX_LINE_COUNT { + levels.push(a_lo + (a_hi - a_lo) * (k as f64) / denom); + } + let stroke = Stroke::default() + .with_width(FLUX_LINE_STROKE) + .with_color(FLUX_LINE_COLOR); + for (p0, p1) in sol.flux_lines(&levels) { + let a = view.map(p0.0, p0.1); + let b = view.map(p1.0, p1.1); + frame.stroke(&Path::line(a, b), stroke.clone()); + } + } + } + } else if let Some(mesh) = self.mesh { for el in &mesh.elements { let (Some(a), Some(b), Some(c)) = ( mesh.nodes.get(el.v0 as usize), @@ -430,6 +497,25 @@ fn doc_bounds(doc: &FemmDoc) -> (f64, f64, f64, f64) { (xmin, xmax, ymin, ymax) } +/// maps a normalized t in [0, 1] onto the jet colormap (blue, cyan, green, yellow, red). +fn jet(t: f32) -> Color { + let t = t.clamp(0.0, 1.0); + let (r, g, b) = if t < 0.25 { + let s = t * 4.0; + (0.0, s, 1.0) + } else if t < 0.5 { + let s = (t - 0.25) * 4.0; + (0.0, 1.0, 1.0 - s) + } else if t < 0.75 { + let s = (t - 0.5) * 4.0; + (s, 1.0, 0.0) + } else { + let s = (t - 0.75) * 4.0; + (1.0, 1.0 - s, 0.0) + }; + Color::from_rgb(r, g, b) +} + /// derives center, radius, and angular extent of an arc segment from its endpoints /// and degree sweep. returns None when endpoints coincide. fn arc_geometry( diff --git a/crates/femm-app/src/main.rs b/crates/femm-app/src/main.rs index 5af1b63..d5d016b 100644 --- a/crates/femm-app/src/main.rs +++ b/crates/femm-app/src/main.rs @@ -2,7 +2,7 @@ mod doc_canvas; -use doc_canvas::{CanvasMessage, Tool}; +use doc_canvas::{CanvasMessage, RenderMode, Tool}; use femm_doc_mag::FemmDoc; use femm_doc_mag::ans::MagSolution; use femm_doc_mag::mesh::Mesh; @@ -11,7 +11,7 @@ use iced::{Element, Length, Task}; use std::ffi::CString; use std::path::Path; -const DEMO_FEM: &str = include_str!("../assets/demo.fem"); +const DEMO_FEM: &str = include_str!("../assets/brgmodel.fem"); const ADD_TOLERANCE: f64 = 0.5; const MIN_ANGLE_DEG: f64 = 30.0; @@ -22,6 +22,7 @@ enum Message { Canvas(CanvasMessage), RunMesh, RunAnalyze, + SetRenderMode(RenderMode), } struct App { @@ -31,6 +32,7 @@ struct App { source_label: String, status: String, tool: Tool, + render_mode: RenderMode, } impl App { @@ -40,9 +42,10 @@ impl App { doc, mesh: None, solution: None, - source_label: String::from("demo.fem (embedded)"), + source_label: String::from("brgmodel.fem (embedded)"), status: String::new(), tool: Tool::Select, + render_mode: RenderMode::default(), }; (app, Task::none()) } @@ -158,6 +161,9 @@ impl App { toggle_closest(&mut self.doc, world.0, world.1); self.status = String::from("toggled selection at right-click"); } + Message::SetRenderMode(mode) => { + self.render_mode = mode; + } Message::Canvas(CanvasMessage::DeleteSelected) => { let n = self.doc.delete_selected_nodes(); let s = self.doc.delete_selected_segments(); @@ -193,13 +199,16 @@ impl App { tool_button("Add Label", Tool::AddBlockLabel, self.tool), button("Mesh").on_press(Message::RunMesh), button("Analyze").on_press(Message::RunAnalyze), + render_mode_button("Density", RenderMode::Density, self.render_mode), + render_mode_button("Contour", RenderMode::Contour, self.render_mode), text(&self.source_label).size(13), stats, ] .spacing(8); - let canvas = doc_canvas::view(&self.doc, self.tool, self.mesh.as_ref()) - .map(Message::Canvas); + let canvas = doc_canvas::view( + &self.doc, self.tool, self.mesh.as_ref(), self.solution.as_ref(), self.render_mode, + ).map(Message::Canvas); let mut body = column![toolbar].spacing(8).padding(12); body = body.push(canvas); @@ -229,6 +238,8 @@ fn run_mesh(doc: &FemmDoc) -> Result { doc.save(&fem_path).map_err(|e| format!("save .fem: {e}"))?; doc.save_poly(&poly_path).map_err(|e| format!("save .poly: {e}"))?; + let pbc_path = stem.with_extension("pbc"); + std::fs::write(&pbc_path, "0\n0\n").map_err(|e| format!("save .pbc: {e}"))?; let triangle = locate_triangle() .ok_or_else(|| String::from("triangle binary not found at build/triangle/triangle - run scripts/macos/build_triangle.sh"))?; @@ -358,6 +369,16 @@ fn tool_button(label: &str, this_tool: Tool, active: Tool) -> Element<'_, Messag } } +/// builds a primary/secondary-styled button that switches the post-processor render mode. +fn render_mode_button(label: &str, this_mode: RenderMode, active: RenderMode) -> Element<'_, Message> { + let btn = button(text(label).size(13)).on_press(Message::SetRenderMode(this_mode)); + if this_mode == active { + btn.style(button::primary).into() + } else { + btn.style(button::secondary).into() + } +} + fn main() -> iced::Result { iced::application(App::new, App::update, App::view) .title(App::title) diff --git a/crates/femm-doc-mag/src/ans.rs b/crates/femm-doc-mag/src/ans.rs index 6ea3c0d..8fb26d5 100644 --- a/crates/femm-doc-mag/src/ans.rs +++ b/crates/femm-doc-mag/src/ans.rs @@ -124,7 +124,7 @@ impl MagSolution { block_circuits.push(parse_block_circuit_row(row, ac)?); } - Ok(MagSolution { + let mut sol = MagSolution { header, points: doc.points, boundaries: doc.boundaries, @@ -133,7 +133,9 @@ impl MagSolution { mesh_nodes, mesh_elements, block_circuits, - }) + }; + sol.compute_b(); + Ok(sol) } /// loads a .ans file from disk. @@ -141,6 +143,98 @@ impl MagSolution { let text = std::fs::read_to_string(path)?; Self::parse(&text) } + + /// fills b1/b2 on every element from the nodal vector-potential A via B = curl A. + /// linear triangle, constant B inside, signed by the doc's winding order. + pub fn compute_b(&mut self) { + for el in &mut self.mesh_elements { + let (Some(n0), Some(n1), Some(n2)) = ( + self.mesh_nodes.get(el.n[0] as usize), + self.mesh_nodes.get(el.n[1] as usize), + self.mesh_nodes.get(el.n[2] as usize), + ) else { continue }; + let det = (n1.x - n0.x) * (n2.y - n0.y) - (n2.x - n0.x) * (n1.y - n0.y); + if det.abs() < 1e-18 { continue; } + let inv = 1.0 / det; + let a0 = n0.a; let a1 = n1.a; let a2 = n2.a; + // bx = dA/dy = (a0*(x2-x1) + a1*(x0-x2) + a2*(x1-x0)) / det + // by = -dA/dx = -(a0*(y1-y2) + a1*(y2-y0) + a2*(y0-y1)) / det + let bx_re = (a0.re * (n2.x - n1.x) + a1.re * (n0.x - n2.x) + a2.re * (n1.x - n0.x)) * inv; + let bx_im = (a0.im * (n2.x - n1.x) + a1.im * (n0.x - n2.x) + a2.im * (n1.x - n0.x)) * inv; + let by_re = -(a0.re * (n1.y - n2.y) + a1.re * (n2.y - n0.y) + a2.re * (n0.y - n1.y)) * inv; + let by_im = -(a0.im * (n1.y - n2.y) + a1.im * (n2.y - n0.y) + a2.im * (n0.y - n1.y)) * inv; + el.b1 = Complex::new(bx_re, bx_im); + el.b2 = Complex::new(by_re, by_im); + } + } + + /// peak magnitude of B for one element, blending real and imag components. + pub fn b_magnitude(&self, idx: usize) -> f64 { + let el = &self.mesh_elements[idx]; + (el.b1.re * el.b1.re + el.b1.im * el.b1.im + + el.b2.re * el.b2.re + el.b2.im * el.b2.im).sqrt() + } + + /// (min, max) of |B| across every element, skipping NaN. + pub fn b_magnitude_range(&self) -> (f64, f64) { + let mut lo = f64::INFINITY; + let mut hi = f64::NEG_INFINITY; + for i in 0..self.mesh_elements.len() { + let m = self.b_magnitude(i); + if !m.is_finite() { continue; } + if m < lo { lo = m; } + if m > hi { hi = m; } + } + if !lo.is_finite() || !hi.is_finite() { (0.0, 0.0) } else { (lo, hi) } + } + + /// (min, max) of the real part of A across every node, skipping NaN. + pub fn a_real_range(&self) -> (f64, f64) { + let mut lo = f64::INFINITY; + let mut hi = f64::NEG_INFINITY; + for n in &self.mesh_nodes { + let a = n.a.re; + if !a.is_finite() { continue; } + if a < lo { lo = a; } + if a > hi { hi = a; } + } + if !lo.is_finite() || !hi.is_finite() { (0.0, 0.0) } else { (lo, hi) } + } + + /// extracts iso-A line segments by marching across every triangle at each requested level. + pub fn flux_lines(&self, levels: &[f64]) -> Vec<((f64, f64), (f64, f64))> { + let mut out = Vec::with_capacity(levels.len() * self.mesh_elements.len() / 4); + for el in &self.mesh_elements { + let (Some(n0), Some(n1), Some(n2)) = ( + self.mesh_nodes.get(el.n[0] as usize), + self.mesh_nodes.get(el.n[1] as usize), + self.mesh_nodes.get(el.n[2] as usize), + ) else { continue }; + let pts = [(n0.x, n0.y), (n1.x, n1.y), (n2.x, n2.y)]; + let vals = [n0.a.re, n1.a.re, n2.a.re]; + for &c in levels { + let mut hits: [(f64, f64); 2] = [(0.0, 0.0); 2]; + let mut count = 0usize; + for (i, j) in [(0, 1), (1, 2), (2, 0)] { + let vi = vals[i] - c; + let vj = vals[j] - c; + if vi == 0.0 && vj == 0.0 { continue; } + if (vi > 0.0) == (vj > 0.0) { continue; } + let t = vi / (vi - vj); + let px = pts[i].0 + t * (pts[j].0 - pts[i].0); + let py = pts[i].1 + t * (pts[j].1 - pts[i].1); + if count < 2 { + hits[count] = (px, py); + } + count += 1; + } + if count == 2 { + out.push((hits[0], hits[1])); + } + } + } + out + } } /// splits the raw text on the `[Solution]` marker into a header chunk and a body chunk. @@ -389,13 +483,17 @@ mod tests { } #[test] - fn parses_element_indices_and_label_with_zero_b_field() { + fn parses_element_indices_and_label_with_computed_b_field() { + // first element spans nodes (0,0)/A=0, (1,0)/A=0.125, (0,1)/A=0.25. + // B = curl A on a linear triangle: bx = dA/dy = 0.25, by = -dA/dx = -0.125. let sol = MagSolution::parse(DC_FIXTURE).unwrap(); let e0 = &sol.mesh_elements[0]; assert_eq!(e0.n, [0, 1, 2]); assert_eq!(e0.lab, 0); - assert_eq!(e0.b1, Complex::new(0.0, 0.0)); - assert_eq!(e0.b2, Complex::new(0.0, 0.0)); + assert!((e0.b1.re - 0.25).abs() < 1e-12, "b1.re = {}", e0.b1.re); + assert!((e0.b2.re + 0.125).abs() < 1e-12, "b2.re = {}", e0.b2.re); + assert!(e0.b1.im.abs() < 1e-18); + assert!(e0.b2.im.abs() < 1e-18); assert_eq!(e0.mu1, Complex::new(0.0, 0.0)); assert_eq!(e0.mu2, Complex::new(0.0, 0.0)); } diff --git a/crates/femm-doc-mag/src/poly.rs b/crates/femm-doc-mag/src/poly.rs index 925e86e..e9e217f 100644 --- a/crates/femm-doc-mag/src/poly.rs +++ b/crates/femm-doc-mag/src/poly.rs @@ -1,8 +1,16 @@ //! .poly emitter consumed by the Triangle mesher. -use crate::FemmDoc; +use crate::{FemmDoc, geom_math::circle_from_arc}; use std::fmt::Write; +/// rounds an arc's chord-angle ceiling, defaulting to a single segment when max_side_length is non-positive. +fn arc_subdivisions(arc_length_deg: f64, max_side_length_deg: f64) -> usize { + if max_side_length_deg <= 0.0 || arc_length_deg <= 0.0 { + return 1; + } + (arc_length_deg / max_side_length_deg).ceil().max(1.0) as usize +} + impl FemmDoc { /// renders the doc geometry to the Triangle .poly text format, returning the file contents. pub fn write_poly(&self) -> String { @@ -10,17 +18,64 @@ impl FemmDoc { let bbox_diag = self.bbox_diagonal(); let default_area = if bbox_diag > 0.0 { bbox_diag } else { -1.0 }; - writeln!(out, "{}\t2\t0\t1", self.nodes.len()).unwrap(); + let mut extra_nodes: Vec<(f64, f64)> = Vec::new(); + let mut arc_segments: Vec<(i32, i32, i32)> = Vec::new(); + let base_node_count = self.nodes.len() as i32; + for a in &self.arcs { + let p0 = (self.nodes[a.n0 as usize].x, self.nodes[a.n0 as usize].y); + let p1 = (self.nodes[a.n1 as usize].x, self.nodes[a.n1 as usize].y); + let k = arc_subdivisions(a.arc_length, a.max_side_length); + let marker = -boundary_marker_index(self, &a.boundary_marker); + if k <= 1 { + arc_segments.push((a.n0, a.n1, marker)); + continue; + } + let (cx, cy, _r) = circle_from_arc(p0, p1, a.arc_length); + let step_rad = a.arc_length.to_radians() / (k as f64); + let (cos_s, sin_s) = (step_rad.cos(), step_rad.sin()); + let mut px = p0.0; + let mut py = p0.1; + let mut prev_idx = a.n0; + for j in 0..k { + let dx = px - cx; + let dy = py - cy; + let rx = dx * cos_s - dy * sin_s; + let ry = dx * sin_s + dy * cos_s; + px = cx + rx; + py = cy + ry; + let next_idx = if j == k - 1 { + a.n1 + } else { + let idx = base_node_count + extra_nodes.len() as i32; + extra_nodes.push((px, py)); + idx + }; + arc_segments.push((prev_idx, next_idx, marker)); + prev_idx = next_idx; + } + } + + let total_nodes = self.nodes.len() + extra_nodes.len(); + writeln!(out, "{}\t2\t0\t1", total_nodes).unwrap(); for (i, n) in self.nodes.iter().enumerate() { let marker = point_marker_index(self, &n.boundary_marker); writeln!(out, "{i}\t{:.17e}\t{:.17e}\t{marker}", n.x, n.y).unwrap(); } + for (j, (x, y)) in extra_nodes.iter().enumerate() { + let i = self.nodes.len() + j; + writeln!(out, "{i}\t{:.17e}\t{:.17e}\t0", x, y).unwrap(); + } - writeln!(out, "{}\t1", self.segments.len()).unwrap(); + let total_segments = self.segments.len() + arc_segments.len(); + writeln!(out, "{}\t1", total_segments).unwrap(); for (i, s) in self.segments.iter().enumerate() { let marker = -boundary_marker_index(self, &s.boundary_marker); writeln!(out, "{i}\t{}\t{}\t{marker}", s.n0, s.n1).unwrap(); } + for (j, (n0, n1, marker)) in arc_segments.iter().enumerate() { + let i = self.segments.len() + j; + writeln!(out, "{i}\t{}\t{}\t{marker}", n0, n1).unwrap(); + } let holes: Vec<&_> = self.block_labels.iter().filter(|b| b.block_type == "").collect(); writeln!(out, "{}", holes.len()).unwrap(); diff --git a/examples/IntegralExample/LinearNew.fem b/examples/IntegralExample/LinearNew.fem new file mode 100644 index 0000000..8847a2a --- /dev/null +++ b/examples/IntegralExample/LinearNew.fem @@ -0,0 +1,343 @@ +[Format] = 4.0 +[Frequency] = 0 +[Precision] = 1e-008 +[MinAngle] = 30 +[Depth] = 45 +[LengthUnits] = millimeters +[ProblemType] = planar +[Coordinates] = cartesian +[ACSolver] = 0 +[Comment] = "Add comments here." +[PointProps] = 0 +[BdryProps] = 1 + + = "A=0" + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + +[BlockProps] = 6 + + = "NdFeB 40 MGOe" + = 1.0489999999999999 + = 1.0489999999999999 + = 979000 + = 0 + = 0 + = 0 + = 0.66700000000000004 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + + + = "NdFeB 32 MGOe" + = 1.0449999999999999 + = 1.0449999999999999 + = 883310 + = 0 + = 0 + = 0 + = 0.69399999999999995 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + + + = "Air" + = 1 + = 1 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + + + = "M-19 Steel" + = 4416 + = 4416 + = 0 + = 0 + = 0 + = 0 + = 1.8999999999999999 + = 0.63500000000000001 + = 0 + = 0 + = 0 + = 0 + = 0.97999999999999998 + = 0 + = 0 + = 47 + 0 0 + 0.050000000000000003 15.120714 + 0.10000000000000001 22.718292000000002 + 0.14999999999999999 27.842732999999999 + 0.20000000000000001 31.871434000000001 + 0.25 35.365043999999997 + 0.29999999999999999 38.600588000000002 + 0.34999999999999998 41.736201999999999 + 0.40000000000000002 44.873978999999999 + 0.45000000000000001 48.087806999999998 + 0.5 51.437235999999999 + 0.55000000000000004 54.975220999999998 + 0.59999999999999998 58.752992999999996 + 0.65000000000000002 62.823644000000002 + 0.69999999999999996 67.245284999999996 + 0.75 72.084406000000001 + 0.80000000000000004 77.420100000000005 + 0.84999999999999998 83.350020999999998 + 0.90000000000000002 89.999611999999999 + 0.94999999999999996 97.537352999999996 + 1 106.20140600000001 + 1.05 116.34846400000001 + 1.1000000000000001 128.54732899999999 + 1.1499999999999999 143.76543100000001 + 1.2 163.75416899999999 + 1.25 191.86815799999999 + 1.3 234.833507 + 1.3500000000000001 306.50976900000001 + 1.3999999999999999 435.255202 + 1.45 674.911968 + 1.5 1108.3255690000001 + 1.55 1813.085468 + 1.6000000000000001 2801.2174209999998 + 1.6499999999999999 4053.6531169999998 + 1.7 5591.10689 + 1.75 7448.318413 + 1.8 9708.81567 + 1.8500000000000001 12486.931615 + 1.8999999999999999 16041.483644 + 1.95 21249.420623999998 + 2 31313.495878000002 + 2.0499999999999998 53589.446877000002 + 2.1000000000000001 88477.484601000004 + 2.1499999999999999 124329.41054 + 2.2000000000000002 159968.5693 + 2.25 197751.604272 + 2.2999999999999998 234024.75134700001 + + + = "Winding" + = 1 + = 1 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 4 + = 1 + = 10 + = 0.51056327271548796 + = 0 + + + = "LinearIron" + = 5000 + = 5000 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + +[CircuitProps] = 1 + + = "icoil" + = 0 + = 0 + = 1 + +[NumPoints] = 66 +18.015650883970093 7.4623269311192511 0 0 +13.788582233137674 13.788582233137678 0 0 +13.788582233137678 -13.788582233137674 0 0 +18.015650883970093 -7.4623269311192475 0 0 +-18.015650883970093 -7.4623269311192493 0 0 +-13.788582233137676 -13.788582233137676 0 0 +-13.788582233137676 13.788582233137676 0 0 +-18.015650883970093 7.4623269311192493 0 0 +10 2.5 0 0 +-10 2.5 0 0 +10 -2.5 0 0 +-10 -2.5 0 0 +-10.589003802626873 2.5 0 0 +10.589003802626873 2.5 0 0 +10.589003802626875 -2.5 0 0 +-10.589003802626877 -2.5 0 0 +-4.3770538240280175 7.5 0 0 +4.377053824028013 7.5 0 0 +4.3770538240280219 -7.5 0 0 +-4.377053824028021 -7.5 0 0 +19.615705608064609 -3.9018064403225647 0 0 +19.615705608064609 3.9018064403225656 0 0 +16.629392246050905 11.111404660392044 0 0 +11.111404660392044 16.629392246050905 0 0 +3.9018064403225661 19.615705608064609 0 0 +-3.9018064403225647 19.615705608064609 0 0 +-11.111404660392044 16.629392246050905 0 0 +-16.629392246050905 11.111404660392044 0 0 +-19.615705608064609 3.901806440322567 0 0 +-19.615705608064609 -3.901806440322563 0 0 +-16.629392246050909 -11.111404660392042 0 0 +-11.111404660392047 -16.629392246050905 0 0 +-3.9018064403225683 -19.615705608064609 0 0 +3.9018064403225621 -19.615705608064609 0 0 +11.11140466039204 -16.629392246050909 0 0 +16.629392246050905 -11.111404660392049 0 0 +30 0 0 0 +-30 0 0 0 +24.693641013472625 3.9018064403225656 0 0 +24.693641013472625 -3.9018064403225647 0 0 +14.702047219983314 20.220034805642172 0 0 +20.220034805642172 14.702047219983314 0 0 +-3.9018064403225643 24.693641013472625 0 0 +3.9018064403225661 24.693641013472625 0 0 +-20.220034805642172 14.702047219983314 0 0 +-14.702047219983314 20.220034805642172 0 0 +-24.693641013472625 -3.9018064403225625 0 0 +-24.693641013472625 3.9018064403225678 0 0 +-14.702047219983317 -20.220034805642172 0 0 +-20.220034805642175 -14.702047219983312 0 0 +3.9018064403225612 -24.693641013472625 0 0 +-3.9018064403225692 -24.693641013472625 0 0 +20.220034805642172 -14.702047219983317 0 0 +14.702047219983308 -20.220034805642175 0 0 +-10 11.257132516954488 0 0 +10 11.257132516954492 0 0 +-10 -11.257132516954488 0 0 +10 -11.257132516954492 0 0 +-10 12 0 0 +-6 16 0 0 +6 16 0 0 +10 12 0 0 +-6 -16 0 0 +-10 -12 0 0 +10 -12 0 0 +6 -16 0 0 +[NumSegments] = 44 +7 12 -1 0 0 0 +4 15 -1 0 0 0 +13 0 -1 0 0 0 +12 9 -1 0 0 0 +9 8 -1 0 0 0 +8 13 -1 0 0 0 +14 3 -1 0 0 0 +15 11 -1 0 0 0 +11 10 -1 0 0 0 +10 14 -1 0 0 0 +9 11 -1 0 0 0 +8 10 -1 0 0 0 +16 17 -1 0 0 0 +19 18 -1 0 0 0 +21 38 -1 0 0 1 +20 39 -1 0 0 1 +23 40 -1 0 0 1 +22 41 -1 0 0 1 +25 42 -1 0 0 1 +24 43 -1 0 0 1 +27 44 -1 0 0 1 +26 45 -1 0 0 1 +29 46 -1 0 0 1 +28 47 -1 0 0 1 +31 48 -1 0 0 1 +30 49 -1 0 0 1 +33 50 -1 0 0 1 +32 51 -1 0 0 1 +35 52 -1 0 0 1 +34 53 -1 0 0 1 +6 54 -1 0 0 0 +17 55 -1 0 0 0 +5 56 -1 0 0 0 +56 19 -1 0 0 0 +18 57 -1 0 0 0 +57 2 -1 0 0 0 +54 16 -1 0 0 0 +55 1 -1 0 0 0 +58 54 -1 0 0 0 +59 60 -1 0 0 0 +61 55 -1 0 0 0 +62 65 -1 0 0 0 +63 56 -1 0 0 0 +64 57 -1 0 0 0 +[NumArcSegments] = 26 +0 1 22.5 1 0 0 0 +2 3 22.5 1 0 0 0 +4 5 22.5 1 0 0 0 +6 7 22.5 1 0 0 0 +20 21 22.5 1 0 0 1 +22 23 22.5 1 0 0 1 +24 25 22.5 1 0 0 1 +26 27 22.5 1 0 0 1 +28 29 22.5 1 0 0 1 +30 31 22.5 1 0 0 1 +32 33 22.5 1 0 0 1 +34 35 22.5 1 0 0 1 +36 37 180 1 1 0 1 +37 36 180 1 1 0 1 +46 49 27.042022070815477 1 0 0 1 +48 51 27.042022070815467 1 0 0 1 +50 53 27.042022070815449 1 0 0 1 +52 39 27.04202207081547 1 0 0 1 +38 41 27.042022070815477 1 0 0 1 +40 43 27.04202207081547 1 0 0 1 +42 45 27.042022070815456 1 0 0 1 +44 47 27.042022070815452 1 0 0 1 +59 58 90 10 0 0 0 +61 60 90 10 0 0 0 +63 62 90 10 0 0 0 +65 64 90 10 0 0 0 +[NumHoles] = 0 +[NumBlockLabels] = 7 +10.699999999999999 -6.5999999999999996 6 2 0 0 0 1 0 +10.699999999999999 6.9000000000000004 6 2 0 0 0 1 0 +17.199999999999999 18 6 2 0 0 1 1 0 +-0.40000000000000002 -0.10000000000000001 1 2 0 90 0 1 0 +15.1 0.90000000000000002 3 2 0 0 0 1 0 +-1.1000000000000001 10.800000000000001 5 -1 1 0 0 40 0 +-1 -11.300000000000001 5 -1 1 0 0 -40 0 diff --git a/examples/IntegralExample/simpleintegral.lua b/examples/IntegralExample/simpleintegral.lua new file mode 100644 index 0000000..ca3ed47 --- /dev/null +++ b/examples/IntegralExample/simpleintegral.lua @@ -0,0 +1,41 @@ +open("LinearNew.fem"); +mi_analyze(); +mi_loadsolution(); + +-- Turn off smoothing so that mo_getpointvalues will return the +-- "raw" piece-wise constant values for flux density and field intensity +mo_smooth("off"); + +-- Grab the total number of elements in the problem; +numelm = mo_numelements(); + + +-- Call mo_getprobleminfo to grab the depth of the problem in th +-- into-the-page direction, which we need for computing volume integrals. +-- Note that the problem depth is always returned in units of meters. +problemtype,freq,depth=mo_getprobleminfo() + +-- Loop through all elements to evaluate the stored energy in all regions +-- denoted as being part of Group 1. +nrg = 0; +for k=1,numelm do + p1,p2,p3,x,y,a,g=mo_getelement(k); + if (g == 1) then + -- Compute element volume. + dv = depth*a*mm^2; + -- Evaluate properties at element centroid + a,bx,by,Sig,E,hx,hy = mo_getpointvalues(x,y); + -- Compute the contribution of this element to the integral + nrg = nrg + (1/2)*(bx*hx+by*hy)*dv; + end +end + +-- For comparison, directly select Group 1 and perform the integral using +-- the built-in function +mo_groupselectblock(1); +altnrg = mo_blockintegral(2); + + +-- Print out results +print("Energy in group 1 computed by manual integral ",nrg); +print("Energy in group 1 computed by canned integral ",altnrg); diff --git a/examples/PMExample.fem b/examples/PMExample.fem new file mode 100644 index 0000000..48cffb3 --- /dev/null +++ b/examples/PMExample.fem @@ -0,0 +1,258 @@ +[Format] = 4.0 +[Frequency] = 0 +[Precision] = 1e-008 +[MinAngle] = 30 +[DoSmartMesh] = 1 +[Depth] = 2 +[LengthUnits] = inches +[ProblemType] = planar +[Coordinates] = cartesian +[ACSolver] = 0 +[PrevType] = 0 +[PrevSoln] = "" +[Comment] = "Add comments here." +[PointProps] = 0 +[BdryProps] = 1 + + = "A=0" + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + +[BlockProps] = 9 + + = "u1" + = 2.6498996896116669 + = 2.6498996896116669 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + + + = "u2" + = 0.12953316809300527 + = 0.12953316809300527 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + + + = "u3" + = 14.398967120915913 + = 14.398967120915913 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + + + = "u4" + = 0.042882574356338271 + = 0.042882574356338271 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + + + = "u5" + = 37.197476986533054 + = 37.197476986533054 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + + + = "u6" + = 0.015664246064106369 + = 0.015664246064106369 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + + + = "u7" + = 142.03015659052124 + = 142.03015659052124 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + + + = "Air" + = 1 + = 1 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + + + = "N42" + = 1.05 + = 1.05 + = 1006582.16453601 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + +[CircuitProps] = 0 +[NumPoints] = 20 +0.23999999999999999 0.125 0 0 +-0.23999999999999999 0.125 0 0 +0.23999999999999999 -0.125 0 0 +-0.23999999999999999 -0.125 0 0 +0 1 0 0 +0 -1 0 0 +0 -1.0142857142857142 0 0 +0 1.0142857142857142 0 0 +0 -1.0285714285714285 0 0 +0 1.0285714285714285 0 0 +0 -1.0428571428571429 0 0 +0 1.0428571428571429 0 0 +0 -1.0571428571428572 0 0 +0 1.0571428571428572 0 0 +0 -1.0714285714285714 0 0 +0 1.0714285714285714 0 0 +0 -1.0857142857142856 0 0 +0 1.0857142857142856 0 0 +0 -1.1000000000000001 0 0 +0 1.1000000000000001 0 0 +[NumSegments] = 4 +1 3 -1 0 0 0 +3 2 -1 0 0 0 +2 0 -1 0 0 0 +0 1 -1 0 0 0 +[NumArcSegments] = 16 +4 5 180 1 0 0 0 1 +5 4 180 1 0 0 0 1 +6 7 180 1 0 0 0 1 +7 6 180 1 0 0 0 1 +8 9 180 1 0 0 0 1 +9 8 180 1 0 0 0 1 +10 11 180 1 0 0 0 1 +11 10 180 1 0 0 0 1 +12 13 180 1 0 0 0 1 +13 12 180 1 0 0 0 1 +14 15 180 1 0 0 0 1 +15 14 180 1 0 0 0 1 +16 17 180 1 0 0 0 1 +17 16 180 1 0 0 0 1 +18 19 180 1 1 0 0 1 +19 18 180 1 1 0 0 1 +[NumHoles] = 0 +[NumBlockLabels] = 9 +-0.040000000000000001 -0.02 9 -1 0 90 0 1 0 +0 0.5 8 -1 0 0 0 1 0 +0.98779088954896777 0.19648382431624345 1 -1 0 0 0 1 0 +0.94367695106509997 0.39088379163005599 2 -1 0 0 0 1 0 +0.86116495559906481 0.57541202705601657 3 -1 0 0 0 1 0 +0.74246212024587499 0.74246212024587488 4 -1 0 0 0 1 0 +0.59128546228514811 0.88492123023628033 5 -1 0 0 0 1 0 +0.41275141633663259 0.99647006720860209 6 -1 0 0 0 1 0 +0.21320585191762575 1.0718581992978162 7 -1 0 0 0 1 0 diff --git a/examples/brgmodel.fem b/examples/brgmodel.fem new file mode 100644 index 0000000..23bba48 --- /dev/null +++ b/examples/brgmodel.fem @@ -0,0 +1,423 @@ +[Format] = 4.0 +[Frequency] = 0 +[Precision] = 1e-008 +[MinAngle] = 30 +[Depth] = 1.6000000000000001 +[LengthUnits] = inches +[ProblemType] = planar +[Coordinates] = cartesian +[Comment] = "Add comments here." +[PointProps] = 0 +[BdryProps] = 1 + + = "A=0" + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + +[BlockProps] = 6 + + = "Air" + = 1 + = 1 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + + + = "J+" + = 1 + = 1 + = 0 + = 0 + = 4.2199999999999998 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + + + = "J-" + = 1 + = 1 + = 0 + = 0 + = -4.2199999999999998 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + + + = "Iron" + = 2500 + = 2500 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + + + = "M-19 Steel" + = 4416 + = 4416 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 13 + 0 0 + 0.29999999999999999 39.78875 + 0.80000000000000004 79.577500000000001 + 1.1200000000000001 159.155 + 1.3200000000000001 318.31 + 1.46 795.77499999999998 + 1.54 1591.55 + 1.6187499999999999 3376.6669999999999 + 1.74 7957.75 + 1.8700000000000001 15915.5 + 1.99 31831 + 2.0459640000000001 55102.040000000001 + 2.0800000000000001 79577.5 + + + = "18 AWG" + = 1 + = 1 + = 0 + = 0 + = 0 + = 0 + = 58 + = 0 + = 0 + = 0 + = 0 + = 3 + = 1 + = 1 + = 1.0239652968433499 + = 0 + +[CircuitProps] = 4 + + = "i1" + = 6 + = 0 + = 1 + + + = "i2" + = 12 + = 0 + = 1 + + + = "i3" + = 6 + = 0 + = 1 + + + = "i4" + = 0 + = 0 + = 1 + +[NumPoints] = 102 +0.92388000000000003 -0.382683 0 0 +-0.92388000000000003 0.382683 0 0 +1.020017 -0.20289399999999999 0 0 +0.86472899999999997 -0.577793 0 0 +0.86472800000000005 0.577793 0 0 +1.020016 0.20289399999999999 0 0 +0.20289399999999999 1.020017 0 0 +0.577793 0.86472899999999997 0 0 +-0.577793 0.86472800000000005 0 0 +-0.20289399999999999 1.020016 0 0 +-0.20289399999999999 -1.020017 0 0 +-0.577793 -0.86472899999999997 0 0 +0.577793 -0.86472800000000005 0 0 +0.20289399999999999 -1.020016 0 0 +-0.86472800000000005 -0.577793 0 0 +-1.020016 -0.20289399999999999 0 0 +-1.020017 0.20289399999999999 0 0 +-0.86472899999999997 0.577793 0 0 +1.9158710000000001 -0.57396899999999995 0 0 +1.7605820000000001 -0.94886800000000004 0 0 +1.7605820000000001 0.94886800000000004 0 0 +1.91587 0.57396899999999995 0 0 +0.57396899999999995 1.9158710000000001 0 0 +0.94886800000000004 1.7605820000000001 0 0 +-0.94886800000000004 1.7605820000000001 0 0 +-0.57396899999999995 1.91587 0 0 +-1.9158710000000001 0.57396899999999995 0 0 +-1.7605820000000001 0.94886800000000004 0 0 +-1.7605820000000001 -0.94886800000000004 0 0 +-1.91587 -0.57396899999999995 0 0 +-0.57396899999999995 -1.9158710000000001 0 0 +-0.94886800000000004 -1.7605820000000001 0 0 +0.94886800000000004 -1.7605820000000001 0 0 +0.57396899999999995 -1.91587 0 0 +2.217311 -0.91844000000000003 0 0 +-2.217311 0.91844000000000003 0 0 +0.55432800000000004 -0.22961000000000001 0 0 +-0.55432800000000004 0.22961000000000001 0 0 +1.3461909999999999 -0.016414999999999999 0 0 +0.96350800000000003 -0.94029399999999996 0 0 +1.9005190000000001 -0.24602499999999999 0 0 +1.517835 -1.1699040000000001 0 0 +1.232494 -0.29090500000000002 0 0 +1.077205 -0.66580399999999995 0 0 +1.786821 -0.52051499999999995 0 0 +1.6315329999999999 -0.89541400000000004 0 0 +0.96350800000000003 0.94029399999999996 0 0 +1.517835 1.1699040000000001 0 0 +1.3461909999999999 0.016414000000000002 0 0 +1.9005190000000001 0.24602399999999999 0 0 +1.077205 0.66580399999999995 0 0 +1.2324930000000001 0.29090500000000002 0 0 +1.6315329999999999 0.89541400000000004 0 0 +1.786821 0.52051499999999995 0 0 +0.016414999999999999 1.3461909999999999 0 0 +0.24602499999999999 1.9005190000000001 0 0 +0.94029399999999996 0.96350800000000003 0 0 +1.1699040000000001 1.517835 0 0 +0.29090500000000002 1.232494 0 0 +0.66580399999999995 1.077205 0 0 +0.52051499999999995 1.786821 0 0 +0.89541400000000004 1.6315329999999999 0 0 +-0.94029399999999996 0.96350800000000003 0 0 +-1.1699040000000001 1.517835 0 0 +-0.016414000000000002 1.3461909999999999 0 0 +-0.24602399999999999 1.9005190000000001 0 0 +-0.66580399999999995 1.077205 0 0 +-0.29090500000000002 1.2324930000000001 0 0 +-0.89541400000000004 1.6315329999999999 0 0 +-0.52051499999999995 1.786821 0 0 +-1.3461909999999999 0.016414999999999999 0 0 +-1.9005190000000001 0.24602499999999999 0 0 +-0.96350800000000003 0.94029399999999996 0 0 +-1.517835 1.1699040000000001 0 0 +-1.232494 0.29090500000000002 0 0 +-1.077205 0.66580399999999995 0 0 +-1.786821 0.52051499999999995 0 0 +-1.6315329999999999 0.89541400000000004 0 0 +-0.96350800000000003 -0.94029399999999996 0 0 +-1.517835 -1.1699040000000001 0 0 +-1.3461909999999999 -0.016414000000000002 0 0 +-1.9005190000000001 -0.24602399999999999 0 0 +-1.077205 -0.66580399999999995 0 0 +-1.2324930000000001 -0.29090500000000002 0 0 +-1.6315329999999999 -0.89541400000000004 0 0 +-1.786821 -0.52051499999999995 0 0 +-0.016414999999999999 -1.3461909999999999 0 0 +-0.24602499999999999 -1.9005190000000001 0 0 +-0.94029399999999996 -0.96350800000000003 0 0 +-1.1699040000000001 -1.517835 0 0 +-0.29090500000000002 -1.232494 0 0 +-0.66580399999999995 -1.077205 0 0 +-0.52051499999999995 -1.786821 0 0 +-0.89541400000000004 -1.6315329999999999 0 0 +0.94029399999999996 -0.96350800000000003 0 0 +1.1699040000000001 -1.517835 0 0 +0.016414000000000002 -1.3461909999999999 0 0 +0.24602399999999999 -1.9005190000000001 0 0 +0.66580399999999995 -1.077205 0 0 +0.29090500000000002 -1.2324930000000001 0 0 +0.89541400000000004 -1.6315329999999999 0 0 +0.52051499999999995 -1.786821 0 0 +[NumSegments] = 96 +4 50 -1 0 0 0 +50 52 -1 0 0 0 +52 20 -1 0 0 0 +5 51 -1 0 0 0 +51 53 -1 0 0 0 +53 21 -1 0 0 0 +6 58 -1 0 0 0 +58 60 -1 0 0 0 +60 22 -1 0 0 0 +7 59 -1 0 0 0 +59 61 -1 0 0 0 +61 23 -1 0 0 0 +8 66 -1 0 0 0 +66 68 -1 0 0 0 +68 24 -1 0 0 0 +9 67 -1 0 0 0 +67 69 -1 0 0 0 +69 25 -1 0 0 0 +16 74 -1 0 0 0 +74 76 -1 0 0 0 +76 26 -1 0 0 0 +17 75 -1 0 0 0 +75 77 -1 0 0 0 +77 27 -1 0 0 0 +14 82 -1 0 0 0 +82 84 -1 0 0 0 +84 28 -1 0 0 0 +15 83 -1 0 0 0 +83 85 -1 0 0 0 +85 29 -1 0 0 0 +10 90 -1 0 0 0 +90 92 -1 0 0 0 +92 30 -1 0 0 0 +11 91 -1 0 0 0 +91 93 -1 0 0 0 +93 31 -1 0 0 0 +12 98 -1 0 0 0 +98 100 -1 0 0 0 +100 32 -1 0 0 0 +13 99 -1 0 0 0 +99 101 -1 0 0 0 +101 33 -1 0 0 0 +2 42 -1 0 0 0 +3 43 -1 0 0 0 +38 40 -1 0 0 0 +39 41 -1 0 0 0 +42 44 -1 0 0 0 +43 45 -1 0 0 0 +38 42 -1 0 0 0 +43 39 -1 0 0 0 +44 18 -1 0 0 0 +45 19 -1 0 0 0 +40 44 -1 0 0 0 +45 41 -1 0 0 0 +46 47 -1 0 0 0 +48 49 -1 0 0 0 +46 50 -1 0 0 0 +51 48 -1 0 0 0 +47 52 -1 0 0 0 +53 49 -1 0 0 0 +54 55 -1 0 0 0 +56 57 -1 0 0 0 +54 58 -1 0 0 0 +59 56 -1 0 0 0 +55 60 -1 0 0 0 +61 57 -1 0 0 0 +62 63 -1 0 0 0 +64 65 -1 0 0 0 +62 66 -1 0 0 0 +67 64 -1 0 0 0 +63 68 -1 0 0 0 +69 65 -1 0 0 0 +70 71 -1 0 0 0 +72 73 -1 0 0 0 +70 74 -1 0 0 0 +75 72 -1 0 0 0 +71 76 -1 0 0 0 +77 73 -1 0 0 0 +78 79 -1 0 0 0 +80 81 -1 0 0 0 +78 82 -1 0 0 0 +83 80 -1 0 0 0 +79 84 -1 0 0 0 +85 81 -1 0 0 0 +86 87 -1 0 0 0 +88 89 -1 0 0 0 +86 90 -1 0 0 0 +91 88 -1 0 0 0 +87 92 -1 0 0 0 +93 89 -1 0 0 0 +94 95 -1 0 0 0 +96 97 -1 0 0 0 +94 98 -1 0 0 0 +99 96 -1 0 0 0 +95 100 -1 0 0 0 +101 97 -1 0 0 0 +[NumArcSegments] = 22 +0 1 180 2.5 0 0 0 +1 0 180 2.5 0 0 0 +5 4 22.5 2.5 0 0 0 +7 6 22.5 2.5 0 0 0 +9 8 22.5 2.5 0 0 0 +15 14 22.5 2.5 0 0 0 +11 10 22.5 2.5 0 0 0 +13 12 22.5 2.5 0 0 0 +3 2 22.5 2.5 0 0 0 +17 16 22.5 2.5 0 0 0 +26 29 33.355001000000001 2.5 0 0 0 +28 31 33.355001000000001 2.5 0 0 0 +30 33 33.355001000000001 2.5 0 0 0 +20 23 33.355001000000001 2.5 0 0 0 +22 25 33.355001000000001 2.5 0 0 0 +24 27 33.355001000000001 2.5 0 0 0 +34 35 180 2.5 1 0 0 +35 34 180 2.5 1 0 0 +36 37 180 2.5 0 0 0 +37 36 180 2.5 0 0 0 +32 19 33.355001000000001 2.5 0 0 0 +18 21 33.355001000000001 2.5 0 0 0 +[NumHoles] = 0 +[NumBlockLabels] = 20 +1.588257 -0.26821600000000001 6 0.050000000000000003 1 0 0 80 0 +1.557868 0.28556700000000002 6 0.050000000000000003 1 0 0 80 0 +0.29210599999999998 1.5675380000000001 6 0.050000000000000003 2 0 0 80 0 +-0.28939399999999998 1.548629 6 0.050000000000000003 2 0 0 80 0 +-1.5528869999999999 0.27521299999999999 6 0.050000000000000003 3 0 0 80 0 +-1.5078469999999999 -0.29546299999999998 6 0.050000000000000003 3 0 0 80 0 +-0.227434 -1.594325 6 0.050000000000000003 4 0 0 80 0 +0.32859100000000002 -1.5323929999999999 6 0.050000000000000003 4 0 0 80 0 +0.91271800000000003 -1.2980929999999999 6 0.050000000000000003 4 0 0 -80 0 +1.2764260000000001 -0.864255 6 0.050000000000000003 1 0 0 -80 0 +1.314986 0.92736799999999997 6 0.050000000000000003 1 0 0 -80 0 +0.88563099999999995 1.354163 6 0.050000000000000003 2 0 0 -80 0 +-0.89806699999999995 1.281201 6 0.050000000000000003 2 0 0 -80 0 +-1.296489 0.89421300000000004 6 0.050000000000000003 3 0 0 -80 0 +-1.2703770000000001 -0.92419799999999996 6 0.050000000000000003 3 0 0 -80 0 +-0.83719500000000002 -1.3417539999999999 6 0.050000000000000003 4 0 0 -80 0 +0.76536700000000002 1.8477589999999999 5 0.049999990000000001 0 0 0 1 0 +0.28701300000000002 0.69291000000000003 5 0.049999990000000001 0 0 0 1 0 +0 0 1 0.049999990000000001 0 0 0 1 0 +1.362606 1.329777 1 0.050000000000000003 0 0 0 1 0 diff --git a/examples/uniform_field_2d.fem b/examples/uniform_field_2d.fem new file mode 100644 index 0000000..7cfc306 --- /dev/null +++ b/examples/uniform_field_2d.fem @@ -0,0 +1,230 @@ +[Format] = 4.0 +[Frequency] = 0 +[Precision] = 1e-008 +[MinAngle] = 30 +[DoSmartMesh] = 1 +[Depth] = 1 +[LengthUnits] = inches +[ProblemType] = planar +[Coordinates] = cartesian +[ACSolver] = 0 +[PrevType] = 0 +[PrevSoln] = "" +[Comment] = "Add comments here." +[PointProps] = 0 +[BdryProps] = 1 + + = "A=0" + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + +[BlockProps] = 8 + + = "u1" + = 2.64989968961167 + = 2.64989968961167 + = 795774.71545947704 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + + + = "u2" + = 0.129533168093005 + = 0.129533168093005 + = 795774.71545947704 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + + + = "u3" + = 14.3989671209159 + = 14.3989671209159 + = 795774.71545947704 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + + + = "u4" + = 0.042882574356338299 + = 0.042882574356338299 + = 795774.71545947704 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + + + = "u5" + = 37.197476986533097 + = 37.197476986533097 + = 795774.71545947704 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + + + = "u6" + = 0.0156642460641064 + = 0.0156642460641064 + = 795774.71545947704 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + + + = "u7" + = 142.03015659052099 + = 142.03015659052099 + = 795774.71545947704 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + + + = "Air" + = 1 + = 1 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 0 + = 1 + = 0 + = 0 + = 0 + +[CircuitProps] = 0 +[NumPoints] = 16 +4.625 5.7101000000000006 0 0 +4.625 3.4399000000000002 0 0 +4.625 3.4236842857142857 0 0 +4.625 5.7263157142857146 0 0 +4.625 3.4074685714285717 0 0 +4.625 5.7425314285714286 0 0 +4.625 3.3912528571428573 0 0 +4.625 5.7587471428571426 0 0 +4.625 3.3750371428571428 0 0 +4.625 5.7749628571428575 0 0 +4.625 3.3588214285714288 0 0 +4.625 5.7911785714285715 0 0 +4.625 3.3426057142857148 0 0 +4.625 5.8073942857142855 0 0 +4.625 3.32639 0 0 +4.625 5.8236100000000004 0 0 +[NumSegments] = 0 +[NumArcSegments] = 16 +0 1 180 1 0 0 0 1 +1 0 180 1 0 0 0 1 +2 3 180 1 0 0 0 1 +3 2 180 1 0 0 0 1 +4 5 180 1 0 0 0 1 +5 4 180 1 0 0 0 1 +6 7 180 1 0 0 0 1 +7 6 180 1 0 0 0 1 +8 9 180 1 0 0 0 1 +9 8 180 1 0 0 0 1 +10 11 180 1 0 0 0 1 +11 10 180 1 0 0 0 1 +12 13 180 1 0 0 0 1 +13 12 180 1 0 0 0 1 +14 15 180 1 1 0 0 1 +15 14 180 1 1 0 0 1 +[NumHoles] = 0 +[NumBlockLabels] = 8 +5.7462414387270337 4.7980287889813678 1 -1 0 0 0 1 0 +5.6961677071539949 5.0186921918792766 2 -1 0 0 0 1 0 +5.6025083411004983 5.2281501919112845 3 -1 0 0 0 1 0 +5.467768752691093 5.4177687526910931 4 -1 0 0 0 1 0 +5.2961681282398718 5.5794740884412022 5 -1 0 0 0 1 0 +5.0935141326837119 5.706093173288485 6 -1 0 0 0 1 0 +4.8670099625116974 5.7916662420229512 7 -1 0 0 0 1 0 +4.6239999999999997 4.6230000000000002 8 -1 0 0 0 1 0