40 """Read ``data.segments`` off an edge.
42 Absent, empty or malformed gives an empty :class:`LineLoss`, which the
43 caller reads as "this line says nothing" and falls back to the line-level
44 parameters -- the behaviour every existing drawing already gets.
47 DiagramError: a segment states a value with no recognised provenance.
48 Same contract as the reader's own parameters, and for the same
49 reason: a number whose source is unrecognised means the document
50 came from something other than this drawing tool, and quietly
51 defaulting it turns a format mismatch into a figure nobody checked.
53 if not isinstance(raw, Sequence)
or isinstance(raw, (str, bytes)):
56 read: list[tuple[LineSegment, str, str, list[str]]] = []
59 for index, entry
in enumerate(raw):
60 if not isinstance(entry, Mapping):
62 seg_id = str(entry.get(
"id",
"")
or f
"s{index + 1}")
63 place = f
"{where} segment {seg_id}"
64 warnings: list[str] = []
66 method = str(entry.get(
"method")
or DEFAULT_METHOD)
67 if method
not in LOSS_METHODS:
69 f
"{place}: loss method {method!r} is not one of "
70 f
"{', '.join(LOSS_METHODS)}; read as {DEFAULT_METHOD!r}"
72 method = DEFAULT_METHOD
74 fittings, fitting_warnings =
_fittings(entry.get(
"fittings"), place, known)
75 warnings.extend(fitting_warnings)
77 basis = str(entry.get(
"lengthBasis")
or "tube")
81 bore=
_param(entry.get(
"bore"),
"bore", place),
82 length=
_param(entry.get(
"length"),
"length", place),
83 roughness=
_param(entry.get(
"roughness"),
"roughness", place),
85 entry.get(
"elevation_change"),
"elevation_change", place
87 K=
_param(entry.get(
"K"),
"K", place),
88 length_basis=basis
if basis
in _BASES
else "tube",
89 tube_size=str(entry.get(
"tubeSize",
"")
or ""),
90 standard=str(entry.get(
"standard",
"")
or ""),
92 curve=
_curve(entry.get(
"curve"), place, warnings),
94 read.append((segment, basis, place, warnings))
99 stated = [segment.bore_si
for segment, *_
in read
if segment.bore_si > 0.0]
100 run_bore =
min(stated)
if stated
else 0.0
102 for segment, basis, place, warnings
in read:
103 said.extend(warnings)
104 said.extend(
_check(segment, basis, place, run_bore))
105 return LineLoss(segments=tuple(s
for s, *_
in read), warnings=tuple(said))
184def _curve(raw: Any, where: str, warnings: list[str]) -> Curve |
None:
185 """A ``{mdot, mdotUnit, dp, dpUnit}`` table, or None.
187 A curve is the top of the ladder, so a malformed one is *not* silently
188 dropped to a lower rung -- it is reported, and then dropped, because a run
189 somebody flowed and recorded badly is a thing to go and fix rather than to
190 quietly replace with a correlation.
192 if not isinstance(raw, Mapping):
201 x_unit=str(raw.get(
"mdotUnit",
"kg/s")
or "kg/s"),
202 y_unit=str(raw.get(
"dpUnit",
"Pa")
or "Pa"),
205 source=Provenance.MEASURED,
206 reference=str(raw.get(
"reference",
"")
or ""),
208 except (CurveError, TypeError, ValueError)
as exc:
209 warnings.append(f
"{where}: the measured curve cannot be read ({exc})")
213def _param(entry: Any, name: str, where: str) -> Param |
None:
214 """One ``{value, unit, source, reference}`` block, or None if unstated."""
215 if not isinstance(entry, Mapping)
or entry.get(
"value")
is None:
217 source = str(entry.get(
"source",
""))
218 if source
not in _PROVENANCE:
220 f
"{where}: {name} has source {source!r}; expected one of "
221 f
"{', '.join(sorted(_PROVENANCE))}"
225 value=float(entry[
"value"]),
226 unit=str(entry.get(
"unit",
"-")),
227 source=_PROVENANCE[source],
228 reference=str(entry.get(
"reference",
"")),
230 except (KeyError, TypeError, ValueError)
as exc:
231 raise DiagramError(f
"{where}: {name} is malformed ({exc})")
235 raw: Any, where: str, known: frozenset[str]
236) -> tuple[tuple[Fitting, ...], list[str]]:
237 out: list[Fitting] = []
238 warnings: list[str] = []
239 if not isinstance(raw, Sequence)
or isinstance(raw, (str, bytes)):
242 if not isinstance(entry, Mapping):
244 kind = str(entry.get(
"kind",
"")).strip()
247 count =
_count(entry.get(
"count"))
248 if kind
not in known:
250 f
"{where}: fitting {kind!r} is not one this library can price; "
251 "it is carried through but contributes no loss"
263 bore=
_mm(entry.get(
"boreMm")),
264 length=
_mm(entry.get(
"lengthMm")),
265 engagement=
_mm(entry.get(
"engagementMm")),
269 bend_diameters=
_plain(entry.get(
"bendDiameters")),
270 angle=
_plain(entry.get(
"angleDeg")),
273 return tuple(out), warnings