Skip to main content

stem_wire/
rectangular.rs

1/*!
2This module contains the predefined [`Wire`] type [`RectangularWire`].
3 */
4
5use std::sync::Arc;
6
7use compare_variables::compare_variables;
8
9use stem_material::prelude::*;
10
11#[cfg(feature = "serde")]
12use stem_material::prelude::serialize_quantity;
13
14#[cfg(feature = "serde")]
15use serde::{Deserialize, Serialize};
16
17#[cfg(feature = "serde")]
18use serde_mosaic::serialize_arc_link;
19
20use super::wire::Wire;
21
22/**
23A rectangular bar made of a conducting material, usually a metal such as
24copper, possibly with an insulation layer.
25
26This type of wire is often found in "constructed" windings such as hairpin
27windings with a low number of turns per coil. It is defined by the following
28fields:
29- `height`: Height of the bar. Must be positive.
30- `width`: Width of the bar. Must be positive.
31- `insulation_thickness`: Thickness of the insulation layer wrapped around the
32outer diameter. Must be positive or zero (zero means no insulation layer).
33- `conductor_material`: The material of the conductor.
34
35The effective conductor area is the space between the inner and the outer
36diameter:
37
38```
39use std::sync::Arc;
40use std::f64::consts::PI;
41
42use approx::assert_abs_diff_eq;
43
44use stem_wire::prelude::*;
45
46let wire_round = RoundWire::new(
47    Arc::new(Material::default()),
48    Length::new::<millimeter>(2.0), // height
49    Length::new::<millimeter>(1.0), // width
50    Length::new::<millimeter>(0.1), // insulation_thickness
51).expect("valid inputs");
52
53assert_abs_diff_eq!(
54    wire_round.effective_conductor_area(Area::new::<square_millimeter>(20.0), 3).get::<square_millimeter>(),
55    PI - 0.25*PI,
56    epsilon = 1e-3
57);
58```
59
60# Deserialization
61
62All length fields accept SI units during deserialization (e.g. `8 mm`, `0.5 m`).
63See [crate-level](crate) and [dyn_quantity] documentation for details.
64 */
65#[derive(Debug, Clone, Default)]
66#[cfg_attr(feature = "serde", derive(Serialize))]
67#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
68pub struct RectangularWire {
69    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_arc_link",))]
70    conductor_material: Arc<Material>,
71    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_quantity"))]
72    height: Length,
73    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_quantity"))]
74    width: Length,
75    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_quantity"))]
76    insulation_thickness: Length,
77}
78
79impl RectangularWire {
80    /**
81    Returns a new instance of [`RectangularWire`] if the given field values
82    fulfill the following conditions:
83    - `height` must be positive.
84    - `width` must be positive.
85    - `insulation_thickness` must be positive or zero.
86
87    See the struct docstring [`RectangularWire`] for more.
88
89    # Examples
90
91    ```
92    use std::sync::Arc;
93    use stem_wire::prelude::*;
94
95    assert!(RectangularWire::new(
96        Arc::new(Material::default()),
97        Length::new::<millimeter>(2.0),
98        Length::new::<millimeter>(1.0),
99        Length::new::<millimeter>(0.1)
100    ).is_ok());
101
102    // Height is not positive
103    assert!(RectangularWire::new(
104        Arc::new(Material::default()),
105        Length::new::<millimeter>(0.0),
106        Length::new::<millimeter>(1.0),
107        Length::new::<millimeter>(0.1)
108    ).is_err());
109
110    // Width is not positive
111    assert!(RectangularWire::new(
112        Arc::new(Material::default()),
113        Length::new::<millimeter>(2.0),
114        Length::new::<millimeter>(-1.0),
115        Length::new::<millimeter>(0.1)
116    ).is_err());
117
118    // Insulation thickness is negative
119    assert!(RectangularWire::new(
120        Arc::new(Material::default()),
121        Length::new::<millimeter>(2.0),
122        Length::new::<millimeter>(1.0),
123        Length::new::<millimeter>(-0.1)
124    ).is_err());
125    ```
126     */
127    pub fn new(
128        conductor_material: Arc<Material>,
129        height: Length,
130        width: Length,
131        insulation_thickness: Length,
132    ) -> Result<Self, crate::error::Error> {
133        return RectangularWire {
134            conductor_material,
135            height,
136            width,
137            insulation_thickness,
138        }
139        .check();
140    }
141
142    /// Checks if the values of `self` are within their valid ranges.
143    fn check(self) -> Result<Self, crate::error::Error> {
144        let zero_length = Length::new::<meter>(0.0);
145        compare_variables!(zero_length < self.height)?;
146        compare_variables!(zero_length < self.width)?;
147        compare_variables!(zero_length <= self.insulation_thickness)?;
148        return Ok(self);
149    }
150
151    /// Returns the thickness of the insulation layer.
152    pub fn insulation_thickness(&self) -> Length {
153        return self.insulation_thickness;
154    }
155
156    /**
157    Returns the conductor area of the wire.
158
159    This function returns the same value as [`Wire::effective_conductor_area`],
160    but does not require `zone_area` and `turns` due to all needed information
161    being stored within the [`RectangularWire`] struct.
162
163    # Examples
164
165    ```
166    use std::sync::Arc;
167    use stem_wire::prelude::*;
168
169    let wire = RectangularWire::new(
170        Arc::new(Material::default()),
171        Length::new::<millimeter>(2.0),
172        Length::new::<millimeter>(1.0),
173        Length::new::<millimeter>(0.1)
174    ).expect("valid inputs");
175    assert_eq!(
176        wire.conductor_area(),
177        wire.effective_conductor_area(Default::default(), 0)
178    );
179    ```
180     */
181    pub fn conductor_area(&self) -> Area {
182        return self.height * self.width;
183    }
184
185    /**
186    Returns the overall area of the wire.
187
188    This function returns the same value as [`Wire::effective_overall_area`],
189    but does not require `zone_area` and `turns` due to all needed information
190    being stored within the [`RectangularWire`] struct.
191
192    # Examples
193
194    ```
195    use std::sync::Arc;
196    use stem_wire::prelude::*;
197
198    let wire = RectangularWire::new(
199        Arc::new(Material::default()),
200        Length::new::<millimeter>(2.0),
201        Length::new::<millimeter>(1.0),
202        Length::new::<millimeter>(0.1)
203    ).expect("valid inputs");
204    assert_eq!(
205        wire.overall_area(),
206        wire.effective_overall_area(Default::default(), 0)
207    );
208    ```
209     */
210    pub fn overall_area(&self) -> Area {
211        return (self.height + 2.0 * self.insulation_thickness)
212            * (self.width + 2.0 * self.insulation_thickness);
213    }
214}
215
216#[cfg_attr(feature = "serde", typetag::serde)]
217impl Wire for RectangularWire {
218    fn material(&self) -> &Material {
219        return &*self.conductor_material;
220    }
221
222    fn material_arc(&self) -> Arc<Material> {
223        return self.conductor_material.clone();
224    }
225
226    fn effective_conductor_area(&self, _zone_area: Area, _turns: usize) -> Area {
227        return self.conductor_area();
228    }
229
230    fn effective_overall_area(&self, _zone_area: Area, _turns: usize) -> Area {
231        return self.overall_area();
232    }
233}
234
235#[cfg(feature = "serde")]
236impl<'de> Deserialize<'de> for RectangularWire {
237    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
238    where
239        D: serde::Deserializer<'de>,
240    {
241        use serde_mosaic::deserialize_arc_link;
242        use stem_material::prelude::deserialize_quantity;
243
244        #[derive(Deserialize)]
245        #[serde(deny_unknown_fields)]
246        struct RectangularWireSerde {
247            #[serde(deserialize_with = "deserialize_arc_link")]
248            conductor_material: Arc<Material>,
249            #[serde(deserialize_with = "deserialize_quantity")]
250            height: Length, // Height of the wire (when inserted in the slot)
251            #[serde(deserialize_with = "deserialize_quantity")]
252            width: Length, // Width of the wire (when inserted in the slot)
253            #[serde(deserialize_with = "deserialize_quantity")]
254            insulation_thickness: Length, // Thickness of the insulation layer
255        }
256
257        let wire_serde = RectangularWireSerde::deserialize(deserializer)?;
258        return RectangularWire {
259            conductor_material: wire_serde.conductor_material,
260            height: wire_serde.height,
261            width: wire_serde.width,
262            insulation_thickness: wire_serde.insulation_thickness,
263        }
264        .check()
265        .map_err(serde::de::Error::custom);
266    }
267}