py-pilecore 0.8.3__py3-none-any.whl → 0.9.0__py3-none-any.whl

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.

Potentially problematic release.


This version of py-pilecore might be problematic. Click here for more details.

Files changed (30) hide show
  1. {py_pilecore-0.8.3.dist-info → py_pilecore-0.9.0.dist-info}/METADATA +2 -1
  2. py_pilecore-0.9.0.dist-info/RECORD +49 -0
  3. pypilecore/_version.py +1 -1
  4. pypilecore/api.py +89 -0
  5. pypilecore/common/piles/__init__.py +2 -0
  6. pypilecore/common/piles/geometry/materials.py +15 -0
  7. pypilecore/common/piles/grid.py +222 -0
  8. pypilecore/common/piles/main.py +15 -1
  9. pypilecore/common/piles/type.py +25 -0
  10. pypilecore/input/grouper_properties.py +2 -2
  11. pypilecore/input/soil_properties.py +19 -0
  12. pypilecore/input/tension.py +280 -0
  13. pypilecore/results/__init__.py +12 -4
  14. pypilecore/results/cases_multi_cpt_results.py +31 -26
  15. pypilecore/results/{multi_cpt_results.py → compression/multi_cpt_results.py} +25 -19
  16. pypilecore/results/{single_cpt_results.py → compression/single_cpt_results.py} +7 -7
  17. pypilecore/results/grouper_result.py +5 -3
  18. pypilecore/results/result_definitions.py +20 -13
  19. pypilecore/results/soil_properties.py +50 -0
  20. pypilecore/results/tension/multi_cpt_results.py +393 -0
  21. pypilecore/results/tension/single_cpt_results.py +393 -0
  22. pypilecore/results/typing.py +44 -0
  23. pypilecore/viewers/interactive_figures/figure_cpt_results_plan_view.py +1 -1
  24. pypilecore/viewers/viewer_cpt_group_results.py +7 -3
  25. pypilecore/viewers/viewer_cpt_results.py +8 -3
  26. pypilecore/viewers/viewer_cpt_results_plan_view.py +7 -3
  27. py_pilecore-0.8.3.dist-info/RECORD +0 -44
  28. {py_pilecore-0.8.3.dist-info → py_pilecore-0.9.0.dist-info}/LICENSE +0 -0
  29. {py_pilecore-0.8.3.dist-info → py_pilecore-0.9.0.dist-info}/WHEEL +0 -0
  30. {py_pilecore-0.8.3.dist-info → py_pilecore-0.9.0.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: py-pilecore
3
- Version: 0.8.3
3
+ Version: 0.9.0
4
4
  Summary: Public python SDK for the CEMS PileCore web-API.
5
5
  License: MIT License
6
6
 
@@ -41,6 +41,7 @@ Requires-Dist: scipy<2,>=1.13
41
41
  Requires-Dist: ipywidgets<9,>=8
42
42
  Requires-Dist: dash<3,>=2.17
43
43
  Requires-Dist: plotly-geo<2,>=1.0.0
44
+ Requires-Dist: plotly<6,>=5
44
45
  Provides-Extra: test
45
46
  Requires-Dist: coveralls; extra == "test"
46
47
  Requires-Dist: pytest; extra == "test"
@@ -0,0 +1,49 @@
1
+ pypilecore/__init__.py,sha256=oJvwYShj_7FyNVlUgQda4tTdYyLIi5H1asdiS_uYt9M,162
2
+ pypilecore/_version.py,sha256=uYUhbKiJfH5uxwBkA8VSVjnbTH1Hes0J6kWOvCSTafE,175
3
+ pypilecore/api.py,sha256=20kaAU-rwMzOz_N-nrKIme_vfWRLNEV1lYkcnnwqof4,9857
4
+ pypilecore/exceptions.py,sha256=-MZOfsxyHLCI0k1-wZFfVsMxc1lya5buuhLks5rxlCo,89
5
+ pypilecore/plot_utils.py,sha256=rK5_067-4-x7LzZgt_t6ahcGrZInxNrqHqsy0RzCnq8,954
6
+ pypilecore/utils.py,sha256=ib9LgJBIgWukL7zd_Zk1LP27UTMIZTRJ4RBB6ubn97o,1186
7
+ pypilecore/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ pypilecore/common/piles/__init__.py,sha256=wyAI8cxs_FvCOR7R7vsAhN-o9vfI9vx6M68ufVPpLvc,177
9
+ pypilecore/common/piles/grid.py,sha256=u38mMbPo-Tg8AA5_vfniU_rNvPkUaNCLs7cKRTFBDlQ,7258
10
+ pypilecore/common/piles/main.py,sha256=JUiTPXO7Pe-UddeTohape0SfJKwIQ-y68VwpEddehnA,11215
11
+ pypilecore/common/piles/type.py,sha256=eWpjWr6i7ZqEFifyUTbvKMols8wcy-CMQ9FJbHD7080,8180
12
+ pypilecore/common/piles/geometry/__init__.py,sha256=dFCVazEXnPCt5cQeHkSi5wp-yHRB9gKvtlQ3V5kBuOQ,438
13
+ pypilecore/common/piles/geometry/main.py,sha256=ant3y1ZTGRN2off5-dwz2024Xa7pC0K7auBbmjTy9p8,11231
14
+ pypilecore/common/piles/geometry/materials.py,sha256=ffyq71HHYg-sXKFAa3AANhLkf2fAApsTmyStlOTm9DI,5813
15
+ pypilecore/common/piles/geometry/components/__init__.py,sha256=KugR37RWegxasqrf93h_PencnKzR4_Mi8s0GhEGzctM,326
16
+ pypilecore/common/piles/geometry/components/common.py,sha256=scYoF-4aE0Wknx9GgSO-qhaIJHfwV6vdIOdtfwExW4U,15127
17
+ pypilecore/common/piles/geometry/components/rectangle.py,sha256=591KyIejyjNAMnKg8yThFjbrPXAVHQdf08vaiQYHZdk,18411
18
+ pypilecore/common/piles/geometry/components/round.py,sha256=MX2_qGmxr1dTtodblFfkNGkoDYqd6xgXHJ57xFuz_Z0,14735
19
+ pypilecore/input/__init__.py,sha256=Gyqsp6zqc8AYnIp17SfqbBNjDaUkRgAam8x2r0XibwM,492
20
+ pypilecore/input/grouper_properties.py,sha256=HPGc9n7o1cDe6YtIuMHuSxmNl0yNsYzvlwIctvXvdnM,11168
21
+ pypilecore/input/multi_cpt.py,sha256=b5poixEs5ex8WGcu3rJiFMdS5Q4DE807L6jmeqiFE64,17506
22
+ pypilecore/input/soil_properties.py,sha256=WympKatXyGKr6IL4RhW-sUKOKov2wV_0Wq9YkdBAQgs,9968
23
+ pypilecore/input/tension.py,sha256=W9YbuNZJz8xp-9-RVl3ejxOqGfZ9UF8uTwxMeeLuAyE,11135
24
+ pypilecore/results/__init__.py,sha256=UCMRRVNZxHTtTD4yTrJ-vpHy-Pga8vvxRu45d8pu5DM,844
25
+ pypilecore/results/cases_multi_cpt_results.py,sha256=meCqFDBCGiSwgmwSzvTLxF5Z0HYkKK-LKrvDp5rAUy8,10253
26
+ pypilecore/results/grouper_result.py,sha256=35Yx8VsIT1hridIZLhgcrqBtxszWvaUljBDroFhzCdg,31006
27
+ pypilecore/results/load_settlement.py,sha256=EbfTrSvH_g96KE-x8ZjmO8D0mt5KFaQ_-AR8u4blLsU,9752
28
+ pypilecore/results/post_processing.py,sha256=UWXcdff5dhPFDwzKbVIayEIp3HX6pxW8oQR3Z7AHPn0,22262
29
+ pypilecore/results/result_definitions.py,sha256=Y6lXp_Idm4nrtN-39CDtQGZnaYsgU2uIZCO9MMQR35g,8558
30
+ pypilecore/results/soil_properties.py,sha256=KaQe-2dTDXhjNnYA7nB7jOqqcbxyw3av4JhJdv3qQPE,23578
31
+ pypilecore/results/typing.py,sha256=74oHMuadWnlbvE_1OaZEuphIehnuuCgDMXIcc6ZX-Dc,1085
32
+ pypilecore/results/compression/multi_cpt_results.py,sha256=8fzhttWhT8c5BU0t7WFngsmExcyjD8rQZfRBmwS-Qqw,31232
33
+ pypilecore/results/compression/single_cpt_results.py,sha256=j_Q35Qf_ZB7_8uctN_A75t-d0rrdWcg-1pbTkiRIlVE,17536
34
+ pypilecore/results/tension/multi_cpt_results.py,sha256=elbn7gwRHBAyHt5ULNaQpOlRQCbr1KC7RD8uO5s-hzw,14526
35
+ pypilecore/results/tension/single_cpt_results.py,sha256=PKfonF7mNMAmWSqnSFLRhLuv8fLfPbMZ1VES8U-TV7g,13402
36
+ pypilecore/viewers/__init__.py,sha256=GjPAj7O_L5QsK2fhewi7yd5fZnbYeCvauDAD37I20Rg,330
37
+ pypilecore/viewers/viewer_cpt_group_results.py,sha256=uPm0xltU7yQhOgeS2tqTSFrmU0cVtQbl3L9kmHMyO5M,2563
38
+ pypilecore/viewers/viewer_cpt_results.py,sha256=EWY8S_Xuabz8EGz4JWTD2RJ0dzz5zCmkRqtFt8VskZw,2999
39
+ pypilecore/viewers/viewer_cpt_results_plan_view.py,sha256=BI8VSg55E6QATJsNKskEzmLFRtGSY3Kr_yWaC1QxRME,3689
40
+ pypilecore/viewers/interactive_figures/__init__.py,sha256=u6fkLqDB35J2bdGvUewzRC8UEQUFF6AoXxR-_v8AX0A,481
41
+ pypilecore/viewers/interactive_figures/figure_cpt_group_results_versus_ptls.py,sha256=RzNOYQmP_yT8oYeIMW9aYNl7aAKU-uFQfygxP9AwDsU,6471
42
+ pypilecore/viewers/interactive_figures/figure_cpt_results_plan_view.py,sha256=cTR-huJn_RigWH_xdN19mi8kwngbKhDhUevgsDKcvjs,9287
43
+ pypilecore/viewers/interactive_figures/figure_cpt_results_versus_ptls.py,sha256=6huCKcQ4bsBE-LNY-ZPa13IWuye0ENxPK4wT1dcCFRs,5964
44
+ pypilecore/viewers/interactive_figures/utils.py,sha256=B2X8hbbmJqjm8E2VrS2EoX5F1yQ5qOQnQUG_vbsseT8,1692
45
+ py_pilecore-0.9.0.dist-info/LICENSE,sha256=3OCAZXffN0Bettjeya8uF_ZYegyvvCfH1WUt6CrHb_0,1061
46
+ py_pilecore-0.9.0.dist-info/METADATA,sha256=xkXCyFKicB8hqrhApsveG1hMnOg9EEI5th0srHytIoo,5859
47
+ py_pilecore-0.9.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
48
+ py_pilecore-0.9.0.dist-info/top_level.txt,sha256=7BKIWZuSkbQtJ0ho5P1JvcaEbHzqADCcBuOduZmIaiI,11
49
+ py_pilecore-0.9.0.dist-info/RECORD,,
pypilecore/_version.py CHANGED
@@ -4,4 +4,4 @@ try:
4
4
  __version__ = version("py-pilecore")
5
5
  # during CI
6
6
  except PackageNotFoundError:
7
- __version__ = "0.8.3"
7
+ __version__ = "0.9.0"
pypilecore/api.py CHANGED
@@ -1,5 +1,6 @@
1
1
  import logging
2
2
  from time import sleep
3
+ from typing import Literal
3
4
 
4
5
  from nuclei.client import NucleiClient
5
6
  from requests import Response
@@ -235,3 +236,91 @@ def get_groups_api_report(
235
236
  return client.call_endpoint(
236
237
  "PileCore", "/get-task-result", version="v3", schema=ticket.json()
237
238
  )
239
+
240
+
241
+ def get_multi_cpt_api_result_tension(
242
+ client: NucleiClient,
243
+ payload: dict,
244
+ verbose: bool = False,
245
+ standard: Literal["NEN9997-1", "CUR236"] = "NEN9997-1",
246
+ ) -> dict:
247
+ """
248
+ Wrapper around the PileCore endpoint "/tension/[nen or cur]/multiple-cpts/results".
249
+
250
+ Parameters
251
+ ----------
252
+ client: NucleiClient
253
+ client object created by [nuclei](https://github.com/cemsbv/nuclei)
254
+ payload: dict
255
+ the payload of the request, can be created by calling `create_grouper_payload()`
256
+ verbose: bool
257
+ if True, print additional information to the console
258
+ standard: str
259
+ Norm used to calculate bearing capacities
260
+ """
261
+ logging.info(
262
+ "Calculating bearing capacities... \n"
263
+ "Depending on the amount of pile tip levels and CPT's this can take a while."
264
+ )
265
+ if standard == "NEN9997-1":
266
+ endpoint = "/tension/nen/multiple-cpt/results"
267
+ else:
268
+ endpoint = "/tension/cur/multiple-cpt/results"
269
+
270
+ ticket = client.call_endpoint(
271
+ "PileCore",
272
+ endpoint=endpoint,
273
+ version="v3",
274
+ schema=payload,
275
+ return_response=True,
276
+ )
277
+
278
+ wait_until_ticket_is_ready(client=client, ticket=ticket, verbose=verbose)
279
+
280
+ return client.call_endpoint(
281
+ "PileCore", "/get-task-result", version="v3", schema=ticket.json()
282
+ )
283
+
284
+
285
+ def get_multi_cpt_api_report_tension(
286
+ client: NucleiClient,
287
+ payload: dict,
288
+ verbose: bool = False,
289
+ standard: Literal["NEN9997-1", "CUR236"] = "NEN9997-1",
290
+ ) -> bytes:
291
+ """
292
+ Wrapper around the PileCore endpoint "/tension/[nen or cur]/multiple-cpts/report".
293
+
294
+ Parameters
295
+ ----------
296
+ client: NucleiClient
297
+ client object created by [nuclei](https://github.com/cemsbv/nuclei)
298
+ payload: dict
299
+ the payload of the request, can be created by calling `create_grouper_payload()`
300
+ verbose: bool
301
+ if True, print additional information to the console
302
+ standard: str
303
+ Norm used to calculate bearing capacities
304
+ """
305
+ logging.info(
306
+ "Generate report... \n"
307
+ "Depending on the amount of pile tip levels and CPT's this can take a while."
308
+ )
309
+
310
+ if standard == "NEN9997-1":
311
+ endpoint = "/tension/nen/multiple-cpt/report"
312
+ else:
313
+ endpoint = "/tension/cur/multiple-cpt/report"
314
+
315
+ ticket = client.call_endpoint(
316
+ "PileCore",
317
+ endpoint=endpoint,
318
+ version="v3",
319
+ schema=payload,
320
+ return_response=True,
321
+ )
322
+ wait_until_ticket_is_ready(client=client, ticket=ticket, verbose=verbose)
323
+
324
+ return client.call_endpoint(
325
+ "PileCore", "/get-task-result", version="v3", schema=ticket.json()
326
+ )
@@ -1,6 +1,8 @@
1
+ from .grid import PileGridProperties
1
2
  from .main import PileProperties, create_basic_pile
2
3
 
3
4
  __all__ = [
4
5
  "PileProperties",
6
+ "PileGridProperties",
5
7
  "create_basic_pile",
6
8
  ]
@@ -10,12 +10,14 @@ MATERIALS = {
10
10
  "name": "grout",
11
11
  "elastic_modulus": 15000,
12
12
  "yield_stress": 1.5,
13
+ "tensile_strength": 1500,
13
14
  "color": "#8A8A8A",
14
15
  },
15
16
  "grout_extorted": {
16
17
  "name": "grout_extorted",
17
18
  "elastic_modulus": 20000,
18
19
  "yield_stress": 2,
20
+ "tensile_strength": 2000,
19
21
  "color": "#8A8A8A",
20
22
  },
21
23
  }
@@ -82,6 +84,7 @@ class PileMaterial:
82
84
  name: str,
83
85
  elastic_modulus: float,
84
86
  yield_stress: float | None = None,
87
+ tensile_strength: float | None = None,
85
88
  color: Color | str | Dict[str, int] | None = None,
86
89
  ):
87
90
  """
@@ -95,12 +98,15 @@ class PileMaterial:
95
98
  The elastic modulus [MPa] of the material.
96
99
  yield_stress : float, optional
97
100
  The yield stress [MPa] of the material, by default None.
101
+ tensile_strength : float, optional
102
+ The tensile strengths [MPa] of the material, by default None.
98
103
  color : Color or str or dict, optional
99
104
  The color of the material, by default None.
100
105
  """
101
106
  self._name = name
102
107
  self._elastic_modulus = elastic_modulus
103
108
  self._yield_stress = yield_stress
109
+ self._tensile_strength = tensile_strength
104
110
  if isinstance(color, str):
105
111
  color = Color.from_hex(hex=color)
106
112
  elif isinstance(color, dict):
@@ -132,6 +138,7 @@ class PileMaterial:
132
138
  name=material["name"],
133
139
  elastic_modulus=material["elastic_modulus"],
134
140
  yield_stress=material.get("yield_stress"),
141
+ tensile_strength=material.get("tensile_strength"),
135
142
  color=color,
136
143
  )
137
144
 
@@ -150,6 +157,11 @@ class PileMaterial:
150
157
  """The yield stress [MPa] of the material"""
151
158
  return self._yield_stress
152
159
 
160
+ @property
161
+ def tensile_strength(self) -> float | None:
162
+ """The tensile strength [MPa] of the material"""
163
+ return self._tensile_strength
164
+
153
165
  @property
154
166
  def color(self) -> Color | Color | None:
155
167
  """The color of the material"""
@@ -170,4 +182,7 @@ class PileMaterial:
170
182
  if self.color is not None:
171
183
  payload["color"] = self.color.serialize_payload()
172
184
 
185
+ if self.tensile_strength is not None:
186
+ payload["tensile_strength"] = self.tensile_strength
187
+
173
188
  return payload
@@ -0,0 +1,222 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, List, Tuple
4
+
5
+ import matplotlib.patches as patches
6
+ import matplotlib.ticker as ticker
7
+ import numpy as np
8
+ from matplotlib import pyplot as plt
9
+ from matplotlib.axes import Axes
10
+ from matplotlib.lines import Line2D
11
+ from shapely.geometry import MultiPolygon, shape
12
+ from shapely.plotting import plot_polygon
13
+
14
+
15
+ class PileGridProperties:
16
+ def __init__(
17
+ self,
18
+ points: List[Tuple[float, float]],
19
+ index_location: int,
20
+ geometry: MultiPolygon | None = None,
21
+ _validate: bool = True,
22
+ ):
23
+ """
24
+ Class that holds the information of the pile placement.
25
+ The structure of the grid effects the effective area of the
26
+ pile.
27
+
28
+ Parameters
29
+ ----------
30
+ points: List of tuple
31
+ List of tuple with xy coordinates.
32
+ index_location: int
33
+ selected index of the points list as pile location
34
+ geometry: MultiPolygon, optional
35
+ A;eff as polygon
36
+ _validate: bool, optional
37
+ flag that overrules validation of the parameters
38
+
39
+ """
40
+ if len(points) < 2 and _validate:
41
+ raise ValueError("Provide at least two points to the pile grid.")
42
+
43
+ if len(points) != len(set(points)):
44
+ raise ValueError("All points of the pile grid must be unique.")
45
+ if len(points) - 1 < index_location > 0:
46
+ raise IndexError(
47
+ f"Index out of range, must be between 0 and {len(points) - 1} got {index_location}."
48
+ )
49
+
50
+ self._points = points
51
+ self._index_location = index_location
52
+ self._geometry = geometry
53
+
54
+ @classmethod
55
+ def regular(cls, ctc: float, index_location: int) -> "PileGridProperties":
56
+ """
57
+ Create a regular grid with a centre to centre distance provided by the user.
58
+ The regular grid contains 9 points. Numbering start in the lower left corner.
59
+ So for the
60
+ - center pile `index_location= 4`
61
+ - middle pile `index_location= 1 or 3 or 4 or 5 or 7`
62
+ - corner pile `index_location= 0 or 2 or 6 or 8`
63
+
64
+ x --- x --- x
65
+ | | |
66
+ x --- x --- x
67
+ | | |
68
+ x --- x --- x with --- == | == ctc
69
+
70
+ Parameters
71
+ ----------
72
+ ctc: float
73
+ Centre to centre distance of regular grid [m]
74
+ index_location: int
75
+ Location of the pile to calculate
76
+ Returns
77
+ -------
78
+ PileGrid
79
+ """
80
+ xx, yy = np.meshgrid(np.arange(0, 3) * ctc, np.arange(0, 3) * ctc)
81
+
82
+ return cls(
83
+ points=list(zip(xx.flatten(), yy.flatten())), index_location=index_location
84
+ )
85
+
86
+ @classmethod
87
+ def from_api_response(cls, payload: dict) -> PileGridProperties:
88
+ """
89
+ Instantiates a PileGeometry from a geometry object in the API response payload.
90
+
91
+ Parameters:
92
+ -----------
93
+ geometry: dict
94
+ A dictionary that is retrieved from the API response payload at "/pile_properties/geometry".
95
+
96
+ Returns:
97
+ --------
98
+ PileGeometry
99
+ A pile geometry.
100
+ """
101
+ # make list type hashable
102
+ points = [(point[0], point[1]) for point in payload["points"]]
103
+ return cls(
104
+ points=points,
105
+ index_location=payload["index_location"],
106
+ geometry=shape(payload["geometry"]),
107
+ _validate=False,
108
+ )
109
+
110
+ def serialize_payload(self) -> dict:
111
+ return {
112
+ "locations": self._points,
113
+ "pile_index": self._index_location,
114
+ }
115
+
116
+ def plot_overview(
117
+ self,
118
+ figsize: Tuple[float, float] = (6.0, 6.0),
119
+ axes: Axes | None = None,
120
+ add_ticks: bool = False,
121
+ add_legend: bool = True,
122
+ **kwargs: Any,
123
+ ) -> Axes:
124
+ """
125
+ Plot the Bird's-eye view of the pile grid. When provided the effect area of
126
+ the pile influence zone is add to the figure.
127
+
128
+ Parameters
129
+ ----------
130
+ figsize : tuple, optional
131
+ The figure size (width, height) in inches, by default (6.0, 6.0).
132
+ axes : Axes
133
+ The axes object to plot the cross-section on.
134
+ add_ticks : bool
135
+ Add ticks to figure, by default False
136
+ add_legend : bool
137
+ Add legend to figure, by default True
138
+ **kwargs
139
+ Additional keyword arguments to pass to the `plt
140
+ """
141
+
142
+ # Create axes objects if not provided
143
+ if axes is not None:
144
+ if not isinstance(axes, Axes):
145
+ raise ValueError(
146
+ "'axes' argument to plot_overview() must be a `pyplot.axes.Axes` object or None."
147
+ )
148
+ else:
149
+ kwargs_subplot = {
150
+ "figsize": figsize,
151
+ "tight_layout": True,
152
+ }
153
+
154
+ kwargs_subplot.update(kwargs)
155
+
156
+ _, axes = plt.subplots(1, 1, **kwargs_subplot)
157
+
158
+ if not isinstance(axes, Axes):
159
+ raise ValueError(
160
+ "Could not create Axes objects. This is probably due to invalid matplotlib keyword arguments. "
161
+ )
162
+ handles = [
163
+ Line2D(
164
+ [0],
165
+ [0],
166
+ label="Selected pile",
167
+ marker=".",
168
+ color="None",
169
+ markerfacecolor="tab:orange",
170
+ markeredgecolor="None",
171
+ ls="",
172
+ ),
173
+ ]
174
+
175
+ if len(self._points) >= 2:
176
+ handles.append(
177
+ Line2D(
178
+ [0],
179
+ [0],
180
+ color="None",
181
+ label="Other piles",
182
+ marker=".",
183
+ markerfacecolor="gray",
184
+ markeredgecolor="None",
185
+ ls="",
186
+ )
187
+ )
188
+ # add the effective area of the pile with the pile grid
189
+ if self._geometry is not None:
190
+ plot_polygon(self._geometry, ax=axes, add_points=False, color="tab:blue")
191
+ handles.append(
192
+ patches.Patch(
193
+ facecolor="tab:blue",
194
+ alpha=0.3,
195
+ label=r"$A_{eff}$" + rf" {self._geometry.area:.1f} $m^2$",
196
+ edgecolor="tab:blue",
197
+ )
198
+ )
199
+
200
+ # plot points
201
+ colors = ["gray"] * len(self._points)
202
+ colors[self._index_location] = "tab:orange"
203
+ axes.scatter(*zip(*self._points), color=colors, marker=".")
204
+
205
+ # add labels to points
206
+ for x, y, label in zip(*zip(*self._points), range(len(self._points))):
207
+ axes.annotate(label, xy=(x, y), xytext=(3, 3), textcoords="offset points")
208
+
209
+ axes.ticklabel_format(useOffset=False, style="plain")
210
+ axes.set_aspect("equal", adjustable="box")
211
+ if add_ticks:
212
+ axes.xaxis.set_major_locator(ticker.NullLocator())
213
+ axes.yaxis.set_major_locator(ticker.NullLocator())
214
+
215
+ if add_legend:
216
+ axes.legend(
217
+ title="Pile grid configuration",
218
+ bbox_to_anchor=(1.04, 1),
219
+ loc="upper left",
220
+ handles=handles,
221
+ )
222
+ return axes
@@ -111,10 +111,13 @@ def create_basic_pile(
111
111
  alpha_s_clay: float | None = None,
112
112
  alpha_s_sand: float | None = None,
113
113
  beta_p: float | None = None,
114
+ alpha_t_clay: float | None = None,
115
+ alpha_t_sand: float | None = None,
114
116
  pile_tip_factor_s: float | None = None,
115
117
  is_auger: bool | None = None,
116
118
  is_low_vibrating: bool | None = None,
117
119
  negative_fr_delta_factor: float | None = None,
120
+ chamfered: float | None = None,
118
121
  ) -> PileProperties:
119
122
  """
120
123
  Create a basic pile with the provided parameters.
@@ -171,6 +174,12 @@ def create_basic_pile(
171
174
  alpha_s_sand : float, optional
172
175
  The alpha_s_sand of the pile, by default None.
173
176
  Required if no standard pile type was specified.
177
+ alpha_t_clay : float, optional
178
+ The alpha_t_clay of the pile, by default None.
179
+ Required if no standard pile type was specified.
180
+ alpha_t_sand : float, optional
181
+ The alpha_t_sand of the pile, by default None.
182
+ Required if no standard pile type was specified.
174
183
  beta_p : float, optional
175
184
  The beta_p of the pile, by default None.
176
185
  Required if no standard pile type was specified.
@@ -186,6 +195,9 @@ def create_basic_pile(
186
195
  negative_fr_delta_factor : float, optional
187
196
  The negative friction delta factor of the pile, by default None.
188
197
  Required if no standard pile type was specified.
198
+ chamfered : float, optional
199
+ The chamfered value of the pile type, by default None.
200
+ Required if no standard pile type was specified.
189
201
 
190
202
  Returns
191
203
  -------
@@ -281,12 +293,14 @@ def create_basic_pile(
281
293
  alpha_s_sand=alpha_s_sand,
282
294
  alpha_s_clay=alpha_s_clay,
283
295
  alpha_p=alpha_p,
284
- alpha_t_sand=None,
296
+ alpha_t_sand=alpha_t_sand,
297
+ alpha_t_clay=alpha_t_clay,
285
298
  settlement_curve=settlement_curve,
286
299
  negative_fr_delta_factor=negative_fr_delta_factor,
287
300
  adhesion=adhesion,
288
301
  is_low_vibrating=is_low_vibrating,
289
302
  is_auger=is_auger,
303
+ chamfered=chamfered,
290
304
  )
291
305
 
292
306
  return PileProperties(geometry=geometry, pile_type=pile_type, name=pile_name)
@@ -13,11 +13,13 @@ class PileType:
13
13
  alpha_s_clay: float | None = None,
14
14
  alpha_p: float | None = None,
15
15
  alpha_t_sand: float | None = None,
16
+ alpha_t_clay: float | None = None,
16
17
  settlement_curve: int | None = None,
17
18
  negative_fr_delta_factor: float | None = None,
18
19
  adhesion: float | None = None,
19
20
  is_low_vibrating: bool | None = None,
20
21
  is_auger: bool | None = None,
22
+ chamfered: float | None = None,
21
23
  ):
22
24
  """
23
25
  Represents the type of a pile.
@@ -34,6 +36,8 @@ class PileType:
34
36
  The alpha_p value of the pile type, by default None.
35
37
  alpha_t_sand : float, optional
36
38
  The alpha_t_sand value of the pile type, by default None.
39
+ alpha_t_clay : float, optional
40
+ The alpha_t_clay value of the pile type, by default None.
37
41
  settlement_curve : int, optional
38
42
  The settlement curve of the pile type, by default None.
39
43
  negative_fr_delta_factor : float, optional
@@ -44,17 +48,21 @@ class PileType:
44
48
  The is_low_vibrating value of the pile type, by default None.
45
49
  is_auger : bool, optional
46
50
  The is_auger value of the pile type, by default None.
51
+ chamfered : float, optional
52
+ The chamfered value of the pile type, by default None.
47
53
  """
48
54
  self._standard_pile = standard_pile
49
55
  self._alpha_s_sand = alpha_s_sand
50
56
  self._alpha_s_clay = alpha_s_clay
51
57
  self._alpha_p = alpha_p
52
58
  self._alpha_t_sand = alpha_t_sand
59
+ self._alpha_t_clay = alpha_t_clay
53
60
  self._settlement_curve = settlement_curve
54
61
  self._negative_fr_delta_factor = negative_fr_delta_factor
55
62
  self._adhesion = adhesion
56
63
  self._is_low_vibrating = is_low_vibrating
57
64
  self._is_auger = is_auger
65
+ self._chamfered = chamfered
58
66
 
59
67
  @classmethod
60
68
  def from_api_response(cls, pile_type: dict) -> PileType:
@@ -77,6 +85,7 @@ class PileType:
77
85
  alpha_s_clay=pile_type["properties"]["alpha_s_clay"],
78
86
  alpha_p=pile_type["properties"]["alpha_p"],
79
87
  alpha_t_sand=pile_type["properties"]["alpha_t_sand"],
88
+ alpha_t_clay=pile_type["properties"].get("alpha_t_clay", None),
80
89
  settlement_curve=pile_type["properties"]["settlement_curve"],
81
90
  negative_fr_delta_factor=pile_type["properties"][
82
91
  "negative_fr_delta_factor"
@@ -111,6 +120,11 @@ class PileType:
111
120
  """The alpha_t_sand value of the pile type"""
112
121
  return self._alpha_t_sand
113
122
 
123
+ @property
124
+ def alpha_t_clay(self) -> float | None:
125
+ """The alpha_t_clay value of the pile type"""
126
+ return self._alpha_t_clay
127
+
114
128
  @property
115
129
  def settlement_curve(self) -> int | None:
116
130
  """The settlement curve of the pile type"""
@@ -136,6 +150,11 @@ class PileType:
136
150
  """The is_auger value of the pile type"""
137
151
  return self._is_auger
138
152
 
153
+ @property
154
+ def chamfered(self) -> float | None:
155
+ """The chamfered value of the pile type"""
156
+ return self._chamfered
157
+
139
158
  def serialize_payload(self) -> Dict[str, str | dict]:
140
159
  """
141
160
  Serialize the pile type to a dictionary payload for the API.
@@ -173,6 +192,9 @@ class PileType:
173
192
  if self.alpha_t_sand is not None:
174
193
  custom_type_properties["alpha_t_sand"] = self.alpha_t_sand
175
194
 
195
+ if self.alpha_t_clay is not None:
196
+ custom_type_properties["alpha_t_clay"] = self.alpha_t_clay
197
+
176
198
  if self.settlement_curve is not None:
177
199
  custom_type_properties["settlement_curve"] = self.settlement_curve
178
200
 
@@ -190,6 +212,9 @@ class PileType:
190
212
  if self.is_auger is not None:
191
213
  custom_type_properties["is_auger"] = self.is_auger
192
214
 
215
+ if self.chamfered is not None:
216
+ custom_type_properties["chamfered"] = self.chamfered
217
+
193
218
  if len(custom_type_properties.keys()) > 0:
194
219
  payload["custom_properties"] = custom_type_properties
195
220
 
@@ -7,7 +7,7 @@ from typing import Any, Dict, List, Literal
7
7
  import numpy as np
8
8
  from shapely.geometry import Polygon, mapping
9
9
 
10
- from pypilecore.results import SingleCPTBearingResults
10
+ from pypilecore.results import SingleCPTCompressionBearingResults
11
11
 
12
12
  _dft_optimize_result_by = [
13
13
  "minimum_pile_level",
@@ -17,7 +17,7 @@ _dft_optimize_result_by = [
17
17
 
18
18
 
19
19
  def create_grouper_payload(
20
- cpt_results_dict: Dict[str, SingleCPTBearingResults],
20
+ cpt_results_dict: Dict[str, SingleCPTCompressionBearingResults],
21
21
  pile_load_uls: float,
22
22
  building_polygon: Polygon | None = None,
23
23
  cpt_grid_rotation: float = 0.0,
@@ -52,6 +52,8 @@ def create_soil_properties_payload(
52
52
  ]
53
53
  | None = None,
54
54
  individual_ocr: Mapping[Any, float] | None = None,
55
+ master_top_of_tension_zone_nap: float | None = None,
56
+ individual_top_of_tension_zone_nap: Mapping[Any, float] | None = None,
55
57
  verbose: bool = False,
56
58
  ) -> Tuple[List[dict], Dict[str, dict]]:
57
59
  """
@@ -112,6 +114,10 @@ def create_soil_properties_payload(
112
114
  A dictionary, mapping ``CPTData.alias`` values to Over-Consolidation-Ratio [-]
113
115
  values of the foundation layer. This will overrule the general `ocr` setting for
114
116
  these specific CPTs only.
117
+ master_top_of_tension_zone_nap:
118
+ Set a fixed top of the tension zone for all CPT's
119
+ individual_top_of_tension_zone_nap:
120
+ A dictionary, mapping `CPTData.alias` values to fixed top of the tension zone.
115
121
  verbose:
116
122
  If True, show progress bars and status messages in stdout.
117
123
 
@@ -211,6 +217,19 @@ def create_soil_properties_payload(
211
217
  ] = individual_positive_friction_range_nap[cpt.alias]
212
218
  soil_properties["friction_range_strategy"] = "manual"
213
219
 
220
+ # Optionally add top_of_tension_zone_nap parameter
221
+ if (
222
+ individual_top_of_tension_zone_nap is not None
223
+ and cpt.alias in individual_top_of_tension_zone_nap.keys()
224
+ ):
225
+ top_of_tension_zone_nap: float | None = individual_top_of_tension_zone_nap[
226
+ cpt.alias
227
+ ]
228
+ else:
229
+ top_of_tension_zone_nap = master_top_of_tension_zone_nap
230
+ if top_of_tension_zone_nap is not None:
231
+ soil_properties["top_of_tension_zone_nap"] = top_of_tension_zone_nap
232
+
214
233
  # Optionally add OCR parameter
215
234
  if individual_ocr is not None and cpt.alias in individual_ocr.keys():
216
235
  ocr: float | None = individual_ocr[cpt.alias]