opensemantic.characteristics.quantitative 0.2.2.dev1__tar.gz → 0.2.2.dev2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/PKG-INFO +3 -1
  2. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/setup.cfg +2 -0
  3. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/src/opensemantic/characteristics/quantitative/__init__.py +4 -0
  4. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/src/opensemantic/characteristics/quantitative/_model.py +3 -3
  5. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/src/opensemantic/characteristics/quantitative/_static.py +96 -3
  6. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/src/opensemantic.characteristics.quantitative.egg-info/PKG-INFO +3 -1
  7. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/src/opensemantic.characteristics.quantitative.egg-info/requires.txt +2 -0
  8. opensemantic_characteristics_quantitative-0.2.2.dev2/tests/integration_test.py +238 -0
  9. opensemantic_characteristics_quantitative-0.2.2.dev1/tests/integration_test.py +0 -106
  10. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/.coveragerc +0 -0
  11. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/.github/workflows/ci.yml +0 -0
  12. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/.gitignore +0 -0
  13. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/.isort.cfg +0 -0
  14. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/.pre-commit-config.yaml +0 -0
  15. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/.readthedocs.yml +0 -0
  16. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/AUTHORS.md +0 -0
  17. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/CHANGELOG.md +0 -0
  18. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/CONTRIBUTING.md +0 -0
  19. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/LICENSE.txt +0 -0
  20. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/README.md +0 -0
  21. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/docs/Makefile +0 -0
  22. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/docs/_static/.gitignore +0 -0
  23. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/docs/authors.md +0 -0
  24. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/docs/changelog.md +0 -0
  25. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/docs/conf.py +0 -0
  26. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/docs/contributing.md +0 -0
  27. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/docs/index.md +0 -0
  28. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/docs/license.md +0 -0
  29. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/docs/readme.md +0 -0
  30. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/docs/requirements.txt +0 -0
  31. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/pyproject.toml +0 -0
  32. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/setup.py +0 -0
  33. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/src/opensemantic/characteristics/quantitative/conversion_test.py +0 -0
  34. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/src/opensemantic.characteristics.quantitative.egg-info/SOURCES.txt +0 -0
  35. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/src/opensemantic.characteristics.quantitative.egg-info/dependency_links.txt +0 -0
  36. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/src/opensemantic.characteristics.quantitative.egg-info/not-zip-safe +0 -0
  37. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/src/opensemantic.characteristics.quantitative.egg-info/top_level.txt +0 -0
  38. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/tests/conftest.py +0 -0
  39. {opensemantic_characteristics_quantitative-0.2.2.dev1 → opensemantic_characteristics_quantitative-0.2.2.dev2}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opensemantic.characteristics.quantitative
3
- Version: 0.2.2.dev1
3
+ Version: 0.2.2.dev2
4
4
  Summary: Library with Python models derived from the page package world.opensemantic.characteristics.quantitative
5
5
  Home-page: https://github.com/OpenSemanticWorld-Packages/opensemantic.characteristics.quantitative-python
6
6
  Author: OpenSemanticWorld
@@ -17,12 +17,14 @@ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
17
17
  License-File: LICENSE.txt
18
18
  Requires-Dist: pydantic
19
19
  Requires-Dist: pint
20
+ Requires-Dist: pint-pandas
20
21
  Requires-Dist: oold
21
22
  Requires-Dist: opensemantic.characteristics
22
23
  Provides-Extra: testing
23
24
  Requires-Dist: setuptools; extra == "testing"
24
25
  Requires-Dist: pytest; extra == "testing"
25
26
  Requires-Dist: pytest-cov; extra == "testing"
27
+ Requires-Dist: scipy; extra == "testing"
26
28
  Dynamic: license-file
27
29
 
28
30
  <!-- These are examples of badges you might want to add to your README:
@@ -27,6 +27,7 @@ python_requires = >=3.11
27
27
  install_requires =
28
28
  pydantic
29
29
  pint
30
+ pint-pandas
30
31
  oold
31
32
  opensemantic.characteristics
32
33
 
@@ -40,6 +41,7 @@ testing =
40
41
  setuptools
41
42
  pytest
42
43
  pytest-cov
44
+ scipy
43
45
 
44
46
  [options.entry_points]
45
47
 
@@ -10,3 +10,7 @@ finally:
10
10
  del version, PackageNotFoundError
11
11
 
12
12
  from opensemantic.characteristics.quantitative._model import * # noqa
13
+ from opensemantic.characteristics.quantitative._static import ( # noqa
14
+ QuantityValue,
15
+ TabularData,
16
+ )
@@ -369,7 +369,7 @@ class AmountOfSubstancePerMass(QuantityValue):
369
369
 
370
370
 
371
371
  class DimensionlessUnit(UnitEnum):
372
- field_ = "Item:OSW5d3fe58ebbac5483bad8904ff8811366"
372
+ dimensionless = "Item:OSW5d3fe58ebbac5483bad8904ff8811366"
373
373
 
374
374
 
375
375
  class Dimensionless(QuantityValue):
@@ -398,7 +398,7 @@ class Dimensionless(QuantityValue):
398
398
 
399
399
  type: Optional[Any] = ["Category:OSWbcaa33bd770e53e09d5e6087d141648b"]
400
400
  unit: Optional[DimensionlessUnit] = Field(
401
- DimensionlessUnit.field_,
401
+ DimensionlessUnit.dimensionless,
402
402
  options={"enum_titles": ["#"]},
403
403
  title="DimensionlessUnit",
404
404
  x_enum_varnames=[""],
@@ -1595,7 +1595,7 @@ class Dimensionless(QuantityValue):
1595
1595
 
1596
1596
  type: Optional[Any] = ["Category:OSWbcaa33bd770e53e09d5e6087d141648b"]
1597
1597
  unit: Optional[DimensionlessUnit] = Field(
1598
- DimensionlessUnit.field_,
1598
+ DimensionlessUnit.dimensionless,
1599
1599
  options={"enum_titles": ["#"]},
1600
1600
  title="DimensionlessUnit",
1601
1601
  x_enum_varnames=[""],
@@ -10,11 +10,13 @@ else:
10
10
 
11
11
  from typing import Any, Dict, List, Optional, Union
12
12
 
13
+ import pandas as pd
14
+
13
15
  # pip install pint
14
16
  import pint
17
+ import pint_pandas # noqa: F401
15
18
  from oold.model.v1 import LinkedBaseModelMetaClass as ModelMetaclass
16
- from pint import UnitRegistry
17
- from pydantic.v1 import Field
19
+ from pydantic.v1 import Field, create_model
18
20
  from pydantic.v1.fields import FieldInfo
19
21
 
20
22
  from opensemantic import OswBaseModel
@@ -80,7 +82,7 @@ class Characteristic(OswBaseModel):
80
82
  # uuid: UUID = Field(default_factory=uuid4, options={"hidden": True}, title="UUID")
81
83
 
82
84
 
83
- ureg = UnitRegistry()
85
+ ureg = pint.get_application_registry()
84
86
 
85
87
  quantity_registry: Dict[EnumType, ModelMetaclass] = {}
86
88
 
@@ -212,6 +214,11 @@ class QuantityValue(Characteristic, metaclass=QuantityValueMetaclass):
212
214
  pint_quantity = self.to_pint().to_base_units()
213
215
  return self.from_pint(pint_quantity, simplify=False)
214
216
 
217
+ def __eq__(self, other: "QuantityValue") -> bool:
218
+ if isinstance(other, QuantityValue):
219
+ other = other.to_pint()
220
+ return self.to_pint() == other
221
+
215
222
  def __add__(self, other: "QuantityValue") -> "QuantityValue":
216
223
  res_pint = self.to_pint() + other.to_pint()
217
224
  return self.from_pint(res_pint)
@@ -220,8 +227,94 @@ class QuantityValue(Characteristic, metaclass=QuantityValueMetaclass):
220
227
  res_pint = self.to_pint() - other.to_pint()
221
228
  return self.from_pint(res_pint)
222
229
 
230
+ # * operator
223
231
  def __mul__(self, other: Union["QuantityValue", float, int]) -> "QuantityValue":
224
232
  if not isinstance(other, (float, int)):
225
233
  other = other.to_pint()
226
234
  res_pint = self.to_pint() * other
227
235
  return self.from_pint(res_pint)
236
+
237
+ # / operator
238
+ def __truediv__(self, other: Union["QuantityValue", float, int]) -> "QuantityValue":
239
+ if not isinstance(other, (float, int)):
240
+ other = other.to_pint()
241
+ res_pint = self.to_pint() / other
242
+ return self.from_pint(res_pint)
243
+
244
+
245
+ class TabularData(OswBaseModel):
246
+ # rows: List[Any] # convention for tabular data is a list of rows
247
+
248
+ # consider https://stackoverflow.com/questions/51505504/pandas-nesting-dataframes # noqa: E501
249
+ # consider https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.attrs.html # noqa: E501
250
+
251
+ def to_df(self) -> pd.DataFrame:
252
+ series = []
253
+ row_class = self.__class__.__fields__["rows"].type_
254
+ for attr in row_class.__fields__.keys():
255
+ q_name = (
256
+ row_class.__fields__[attr]
257
+ .type_.__fields__["unit"]
258
+ .default.name.replace("_", " ")
259
+ )
260
+ # q_pint = ureg[q_name]
261
+ s = pd.Series(
262
+ [
263
+ (
264
+ getattr(m, attr).to_pint().to(q_name).magnitude
265
+ if getattr(m, attr, None) is not None
266
+ else None
267
+ )
268
+ for m in self.rows
269
+ ],
270
+ dtype="pint[" + q_name + "]",
271
+ name=attr,
272
+ )
273
+ series.append(s)
274
+ rows = {s.name: s for s in series}
275
+ return pd.DataFrame(rows)
276
+
277
+ @classmethod
278
+ def from_df(cls, df: pd.DataFrame):
279
+ rows = []
280
+ row_class = OswBaseModel
281
+ if "rows" in cls.__fields__:
282
+ row_class = cls.__fields__["rows"].type_
283
+
284
+ additional_fields = {}
285
+ for key in df.columns:
286
+ # print(df[key].pint.__dict__)
287
+ if key not in row_class.__fields__.keys():
288
+ # raise ValueError(f"Column '{key}' not found in '{row_class.__name__}'") # noqa: E501
289
+ quantity = QuantityValue.from_pint(
290
+ 1 * getattr(df.dtypes, key).units
291
+ ).__class__
292
+ additional_fields[key] = (quantity, ...)
293
+
294
+ if len(additional_fields) > 0:
295
+ row_class = create_model(
296
+ row_class.__name__ + "Extended", **additional_fields, __base__=row_class
297
+ )
298
+ cls = create_model(
299
+ cls.__name__ + "Extended",
300
+ **{"rows": (List[row_class], ...)},
301
+ __base__=cls,
302
+ )
303
+
304
+ # convert all columns to the default unit
305
+ for attr in row_class.__fields__.keys():
306
+ q_name = (
307
+ row_class.__fields__[attr]
308
+ .type_.__fields__["unit"]
309
+ .default.name.replace("_", " ")
310
+ )
311
+ q_pint = ureg[q_name]
312
+ df[attr] = df[attr].pint.to(q_pint)
313
+
314
+ for i, row in df.iterrows():
315
+ # create a dictionary with the values of the row
316
+ # using the column names as keys
317
+ d = {key: {"value": row[key].magnitude} for key in df.columns}
318
+ m = row_class(**d)
319
+ rows.append(m)
320
+ return cls(rows=rows)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opensemantic.characteristics.quantitative
3
- Version: 0.2.2.dev1
3
+ Version: 0.2.2.dev2
4
4
  Summary: Library with Python models derived from the page package world.opensemantic.characteristics.quantitative
5
5
  Home-page: https://github.com/OpenSemanticWorld-Packages/opensemantic.characteristics.quantitative-python
6
6
  Author: OpenSemanticWorld
@@ -17,12 +17,14 @@ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
17
17
  License-File: LICENSE.txt
18
18
  Requires-Dist: pydantic
19
19
  Requires-Dist: pint
20
+ Requires-Dist: pint-pandas
20
21
  Requires-Dist: oold
21
22
  Requires-Dist: opensemantic.characteristics
22
23
  Provides-Extra: testing
23
24
  Requires-Dist: setuptools; extra == "testing"
24
25
  Requires-Dist: pytest; extra == "testing"
25
26
  Requires-Dist: pytest-cov; extra == "testing"
27
+ Requires-Dist: scipy; extra == "testing"
26
28
  Dynamic: license-file
27
29
 
28
30
  <!-- These are examples of badges you might want to add to your README:
@@ -1,5 +1,6 @@
1
1
  pydantic
2
2
  pint
3
+ pint-pandas
3
4
  oold
4
5
  opensemantic.characteristics
5
6
 
@@ -7,3 +8,4 @@ opensemantic.characteristics
7
8
  setuptools
8
9
  pytest
9
10
  pytest-cov
11
+ scipy
@@ -0,0 +1,238 @@
1
+ import json
2
+ from typing import List, Optional
3
+
4
+ from scipy.stats import linregress
5
+
6
+ from opensemantic import OswBaseModel
7
+ from opensemantic.characteristics.quantitative import (
8
+ Area,
9
+ AreaUnit,
10
+ Force,
11
+ ForcePerAreaUnit,
12
+ ForceUnit,
13
+ Length,
14
+ LengthUnit,
15
+ LinearStrain,
16
+ ModulusOfElasticity,
17
+ QuantityValue,
18
+ Stress,
19
+ TabularData,
20
+ Thickness,
21
+ Width,
22
+ )
23
+
24
+ # to we have to adapt VSCode settings to include the package index?
25
+ # "python.analysis.packageIndexDepths": [
26
+ # {"name": "opensemantic.characteristics.quantitative",
27
+ # "depth": 4, "includeAllSymbols": true}
28
+ # ]
29
+
30
+
31
+ def test_pint():
32
+
33
+ q = Length(value=1.0, unit=LengthUnit.milli_meter)
34
+ # transform to pint
35
+ q_pint = q.to_pint()
36
+ # transform back to QuantityValue
37
+ q_ = QuantityValue.from_pint(q_pint)
38
+ assert q == q_
39
+
40
+ q2 = Length(value=1.0, unit=LengthUnit.meter)
41
+ q3 = q + q2
42
+ assert q3 == Length(value=1.001, unit=LengthUnit.meter)
43
+
44
+ q31 = q * q2
45
+ assert q31 == Area(value=1000.0, unit=AreaUnit.milli_meter_squared)
46
+
47
+ q41 = Area(value=1.0, unit=AreaUnit.meter_squared)
48
+ q42 = Area(value=1.0, unit=AreaUnit.milli_meter_squared)
49
+ # 'square_meter' is not a valid unit for pint, but 'square_meter' is
50
+ q43 = q41 + q42
51
+ assert q43 == Area(value=1.000001, unit=AreaUnit.meter_squared)
52
+
53
+
54
+ def test_export():
55
+
56
+ q = Length(value=1.0, unit=LengthUnit.milli_meter)
57
+
58
+ q_json = json.loads(q.json(exclude_none=True))
59
+ print(q_json)
60
+ assert q_json == {
61
+ "type": ["Category:OSWee9c7e5c343e542cb5a8b4648315902f"],
62
+ "value": 1.0,
63
+ "unit": str(
64
+ "Item:OSWf101d25e944856e3bd4b4c9863db7de2"
65
+ "#OSW322dec469be75aedb008b3ebff29db86"
66
+ ),
67
+ }
68
+
69
+ q = Length(value=1.0, unit=LengthUnit.meter)
70
+
71
+ q_json = json.loads(q.json(exclude_none=True))
72
+ print(q_json)
73
+ assert q_json == {
74
+ "type": ["Category:OSWee9c7e5c343e542cb5a8b4648315902f"],
75
+ "value": 1.0,
76
+ "unit": "Item:OSWf101d25e944856e3bd4b4c9863db7de2",
77
+ }
78
+
79
+ q_json = json.loads(q.json(exclude_none=True, exclude_defaults=True))
80
+ print(q_json)
81
+ assert q_json == {"value": 1.0}
82
+
83
+ ln = Length(value=0.1)
84
+ w = Width(value=200, unit=LengthUnit.milli_meter)
85
+ a = ln * w
86
+ print(a)
87
+
88
+ json_dict = a.dict()
89
+ print(json_dict)
90
+ assert json_dict["type"] == ["Category:OSW1fcf1694712e5684885071efdf775bd9"]
91
+ assert json_dict["value"] == 20000.0
92
+ assert json_dict["unit"] == (
93
+ "Item:OSWd10e5841c68e5aad94b481b58ef9dfb9"
94
+ "#OSWeca22bf4270853038ef3395bd6dd797b"
95
+ )
96
+
97
+ # _a = QuantityValue(**json_dict)
98
+
99
+ _a = a.to_base()
100
+ json_dict = _a.dict(exclude_none=True, exclude_defaults=True)
101
+ print(json_dict)
102
+ assert json_dict["value"] == 0.02
103
+ assert len(json_dict.keys()) == 1
104
+
105
+ __a = Area(**json_dict)
106
+ assert __a == _a
107
+
108
+ # not supported yet
109
+ # jsonld_dict = a.to_jsonld()
110
+ # print(json.dumps(jsonld_dict, indent=2))
111
+
112
+ # a2 = QuantityValue.from_jsonld(jsonld_dict)
113
+ # print(a2)
114
+
115
+
116
+ def test_pandas():
117
+
118
+ class Measurement(OswBaseModel):
119
+ length: Length
120
+ width: Width
121
+ area: Optional[Area] = None
122
+
123
+ class MeasurementData(TabularData):
124
+ rows: List[Measurement]
125
+
126
+ measurement = MeasurementData(
127
+ rows=[
128
+ Measurement(length=Length(value=1.0), width=Width(value=2.0)),
129
+ Measurement(length=Length(value=3.0), width=Width(value=4.0)),
130
+ ]
131
+ )
132
+ df = measurement.to_df()
133
+ print(df)
134
+ df["area"] = df["length"] * df["width"]
135
+ print(df)
136
+ measurement2 = MeasurementData.from_df(df)
137
+ print(measurement2)
138
+ measurement3 = TabularData.from_df(df)
139
+ print(measurement3.json(exclude_none=True, exclude_defaults=True, indent=2))
140
+ # print(measurement3.__class__.schema_json(indent=2))
141
+
142
+
143
+ def test_tensile_test():
144
+
145
+ class TensileTestSpecimen(OswBaseModel):
146
+ length: Length
147
+ width: Width
148
+ thickness: Length
149
+ cross_section_area: Optional[Area] = None
150
+ e_mod: Optional[ModulusOfElasticity] = None
151
+
152
+ class TensileTestResultRow(OswBaseModel):
153
+ elongation: Length
154
+ force: Force
155
+ strain: Optional[LinearStrain] = None
156
+ stress: Optional[Stress] = None
157
+
158
+ class TensileTestResult(TabularData):
159
+ rows: List[TensileTestResultRow]
160
+ linear_region: Optional[LinearStrain] = LinearStrain(value=0.002)
161
+
162
+ class TensileTestDataset(OswBaseModel):
163
+ specimen: TensileTestSpecimen
164
+ result: TensileTestResult
165
+
166
+ def tensile_test_analysis(dataset: TensileTestDataset):
167
+ # Calculate cross section area if not provided
168
+ if dataset.specimen.cross_section_area is None:
169
+ dataset.specimen.cross_section_area = (
170
+ dataset.specimen.width * dataset.specimen.thickness
171
+ )
172
+
173
+ # Calculate stress and strain - slow iteration
174
+ # for row in dataset.result.rows:
175
+ # #row.stress = Stress(value=row.force.value / dataset.specimen.cross_section_area.value, unit=row.force.unit) # noqa: E501
176
+ # #row.strain = LinearStrain(value=row.force.value / (dataset.specimen.e_mod.value * dataset.specimen.cross_section_area.value), unit=row.force.unit) # noqa: E501
177
+ # row.stress = row.force / dataset.specimen.cross_section_area # noqa: E501
178
+
179
+ # Calculate stress and strain - fast as pandas DataFrame operation
180
+ df = dataset.result.to_df()
181
+ df["strain"] = df["elongation"] / dataset.specimen.length.to_pint()
182
+ df["stress"] = df["force"] / dataset.specimen.cross_section_area.to_pint()
183
+
184
+ # make a linear fit on the linear region of the stress-strain curve
185
+ # to find the modulus of elasticity
186
+ linear_region = df[df["strain"] <= dataset.result.linear_region.to_pint()]
187
+
188
+ slope, intercept, r_value, p_value, std_err = linregress(
189
+ linear_region["strain"].pint.to_base_units().pint.magnitude,
190
+ linear_region["stress"].pint.to_base_units().pint.magnitude,
191
+ )
192
+
193
+ slope = (
194
+ slope
195
+ * linear_region["stress"].pint.to_base_units().pint.units
196
+ / linear_region["strain"].pint.to_base_units().pint.units
197
+ ) # noqa: E501
198
+ dataset.specimen.e_mod = ModulusOfElasticity.from_pint(slope.to("Pa"))
199
+
200
+ dataset.result = TensileTestResult.from_df(df)
201
+
202
+ return dataset
203
+
204
+ # Example usage
205
+ specimen = TensileTestSpecimen(
206
+ length=Length(value=100, unit=LengthUnit.milli_meter),
207
+ width=Width(value=10, unit=LengthUnit.milli_meter),
208
+ thickness=Thickness(value=10, unit=LengthUnit.milli_meter),
209
+ )
210
+ result = TensileTestResult(
211
+ rows=[
212
+ TensileTestResultRow(
213
+ force=Force(value=1.0000, unit=ForceUnit.kilo_newton),
214
+ elongation=Length(value=0.10, unit=LengthUnit.milli_meter),
215
+ ), # noqa: E501
216
+ TensileTestResultRow(
217
+ force=Force(value=1.5050, unit=ForceUnit.kilo_newton),
218
+ elongation=Length(value=0.15, unit=LengthUnit.milli_meter),
219
+ ), # noqa: E501
220
+ TensileTestResultRow(
221
+ force=Force(value=2.0000, unit=ForceUnit.kilo_newton),
222
+ elongation=Length(value=0.20, unit=LengthUnit.milli_meter),
223
+ ), # noqa: E501
224
+ ]
225
+ )
226
+ dataset = TensileTestDataset(specimen=specimen, result=result)
227
+ analyzed_dataset = tensile_test_analysis(dataset)
228
+ # print(analyzed_dataset.json(exclude_none=True, indent=2))
229
+ assert analyzed_dataset.specimen.e_mod == ModulusOfElasticity(
230
+ value=10.0, unit=ForcePerAreaUnit.giga_pascal
231
+ )
232
+
233
+
234
+ if __name__ == "__main__":
235
+ test_pint()
236
+ test_export()
237
+ test_pandas()
238
+ test_tensile_test()
@@ -1,106 +0,0 @@
1
- import json
2
-
3
- from opensemantic.characteristics.quantitative import (
4
- Area,
5
- AreaUnit,
6
- Length,
7
- LengthUnit,
8
- QuantityValue,
9
- Width,
10
- )
11
-
12
- # to we have to adapt VSCode settings to include the package index?
13
- # "python.analysis.packageIndexDepths": [
14
- # {"name": "opensemantic.characteristics.quantitative",
15
- # "depth": 4, "includeAllSymbols": true}
16
- # ]
17
-
18
-
19
- def test_pint():
20
-
21
- q = Length(value=1.0, unit=LengthUnit.milli_meter)
22
- # transform to pint
23
- q_pint = q.to_pint()
24
- # transform back to QuantityValue
25
- q_ = QuantityValue.from_pint(q_pint)
26
- assert q == q_
27
-
28
- q2 = Length(value=1.0, unit=LengthUnit.meter)
29
- q3 = q + q2
30
- assert q3 == Length(value=1.001, unit=LengthUnit.meter)
31
-
32
- q31 = q * q2
33
- assert q31 == Area(value=1000.0, unit=AreaUnit.milli_meter_squared)
34
-
35
- q41 = Area(value=1.0, unit=AreaUnit.meter_squared)
36
- q42 = Area(value=1.0, unit=AreaUnit.milli_meter_squared)
37
- # 'square_meter' is not a valid unit for pint, but 'square_meter' is
38
- q43 = q41 + q42
39
- assert q43 == Area(value=1.000001, unit=AreaUnit.meter_squared)
40
-
41
-
42
- def test_export():
43
-
44
- q = Length(value=1.0, unit=LengthUnit.milli_meter)
45
-
46
- q_json = json.loads(q.json(exclude_none=True))
47
- print(q_json)
48
- assert q_json == {
49
- "type": ["Category:OSWee9c7e5c343e542cb5a8b4648315902f"],
50
- "value": 1.0,
51
- "unit": str(
52
- "Item:OSWf101d25e944856e3bd4b4c9863db7de2"
53
- "#OSW322dec469be75aedb008b3ebff29db86"
54
- ),
55
- }
56
-
57
- q = Length(value=1.0, unit=LengthUnit.meter)
58
-
59
- q_json = json.loads(q.json(exclude_none=True))
60
- print(q_json)
61
- assert q_json == {
62
- "type": ["Category:OSWee9c7e5c343e542cb5a8b4648315902f"],
63
- "value": 1.0,
64
- "unit": "Item:OSWf101d25e944856e3bd4b4c9863db7de2",
65
- }
66
-
67
- q_json = json.loads(q.json(exclude_none=True, exclude_defaults=True))
68
- print(q_json)
69
- assert q_json == {"value": 1.0}
70
-
71
- ln = Length(value=0.1)
72
- w = Width(value=200, unit=LengthUnit.milli_meter)
73
- a = ln * w
74
- print(a)
75
-
76
- json_dict = a.dict()
77
- print(json_dict)
78
- assert json_dict["type"] == ["Category:OSW1fcf1694712e5684885071efdf775bd9"]
79
- assert json_dict["value"] == 20000.0
80
- assert json_dict["unit"] == (
81
- "Item:OSWd10e5841c68e5aad94b481b58ef9dfb9"
82
- "#OSWeca22bf4270853038ef3395bd6dd797b"
83
- )
84
-
85
- # _a = QuantityValue(**json_dict)
86
-
87
- _a = a.to_base()
88
- json_dict = _a.dict(exclude_none=True, exclude_defaults=True)
89
- print(json_dict)
90
- assert json_dict["value"] == 0.02
91
- assert len(json_dict.keys()) == 1
92
-
93
- __a = Area(**json_dict)
94
- assert __a == _a
95
-
96
- # not supported yet
97
- # jsonld_dict = a.to_jsonld()
98
- # print(json.dumps(jsonld_dict, indent=2))
99
-
100
- # a2 = QuantityValue.from_jsonld(jsonld_dict)
101
- # print(a2)
102
-
103
-
104
- if __name__ == "__main__":
105
- test_pint()
106
- test_export()