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}