py-pilecore 0.3.4__py3-none-any.whl → 0.4.1__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.

@@ -1,77 +1,186 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from copy import deepcopy
3
4
  from dataclasses import dataclass
4
- from typing import Any, List, Tuple
5
+ from functools import cached_property
6
+ from typing import Any, Dict, List, Sequence, Tuple
5
7
 
6
8
  import natsort
7
9
  import numpy as np
8
10
  import pandas as pd
9
11
  from matplotlib import pyplot as plt
12
+ from numpy.typing import NDArray
10
13
  from shapely import MultiPoint
11
14
 
15
+ from pypilecore.results.multi_cpt_results import MultiCPTBearingResults
16
+ from pypilecore.results.post_processing import (
17
+ MaxBearingResult,
18
+ MaxBearingResults,
19
+ MaxBearingTable,
20
+ )
21
+
12
22
 
13
- @dataclass(frozen=True)
14
23
  class SingleClusterData:
15
24
  """
25
+ Data for a single CPT subgroup
16
26
  *Not meant to be instantiated by the user.*
17
-
18
- Attributes:
19
- ------------
20
- characteristic_bearing_capacity: List[float]
21
- characteristic bearing capacity [kN]
22
- design_bearing_capacity: List[float]
23
- design bearing capacity [kN]
24
- design_negative_friction: List[float]
25
- design negative friction [kN]
26
- group_centre_to_centre_validation: List[bool]
27
- group centre to centre validation
28
- group_centre_to_centre_validation_15: List[bool]
29
- group centre to centre validation 15 meter
30
- group_centre_to_centre_validation_20: List[bool]
31
- group centre to centre validation 20 meter
32
- group_centre_to_centre_validation_25: List[bool]
33
- group centre to centre validation 25 meter
34
- mean_calculated_bearing_capacity: List[float]
35
- mean calculated bearing capacity [kN]
36
- min_calculated_bearing_capacity: List[float]
37
- min calculated bearing capacity [kN]
38
- net_design_bearing_capacity: List[float]
39
- net design bearing capacity [kN]
40
- nominal_cpt: List[str]
41
- nominal cpt
42
- pile_tip_level: List[float]
43
- pile tip level [m w.r.t NAP]
44
- variation_coefficient: List[float]
45
- variation coefficient [-]
46
- xi_factor: List[str]
47
- xi factor
48
- xi_values: List[float]
49
- xi values [-]
50
27
  """
51
28
 
52
- characteristic_bearing_capacity: List[float]
53
- design_bearing_capacity: List[float]
54
- design_negative_friction: List[float]
55
- group_centre_to_centre_validation: List[bool]
56
- group_centre_to_centre_validation_15: List[bool]
57
- group_centre_to_centre_validation_20: List[bool]
58
- group_centre_to_centre_validation_25: List[bool]
59
- mean_calculated_bearing_capacity: List[float]
60
- min_calculated_bearing_capacity: List[float]
61
- net_design_bearing_capacity: List[float]
62
- nominal_cpt: List[str]
63
- pile_tip_level: List[float]
64
- variation_coefficient: List[float]
65
- xi_factor: List[str]
66
- xi_values: List[float]
29
+ def __init__(
30
+ self,
31
+ characteristic_bearing_capacity: Sequence[float],
32
+ design_bearing_capacity: Sequence[float],
33
+ design_negative_friction: Sequence[float],
34
+ group_centre_to_centre_validation: Sequence[bool],
35
+ group_centre_to_centre_validation_15: Sequence[bool],
36
+ group_centre_to_centre_validation_20: Sequence[bool],
37
+ group_centre_to_centre_validation_25: Sequence[bool],
38
+ mean_calculated_bearing_capacity: Sequence[float],
39
+ min_calculated_bearing_capacity: Sequence[float],
40
+ net_design_bearing_capacity: Sequence[float],
41
+ nominal_cpt: Sequence[str],
42
+ pile_tip_level: Sequence[float],
43
+ variation_coefficient: Sequence[float],
44
+ xi_factor: Sequence[str],
45
+ xi_values: Sequence[float],
46
+ ):
47
+ """
48
+ Parameters
49
+ ----------
50
+ characteristic_bearing_capacity:
51
+ characteristic bearing capacity [kN]
52
+ design_bearing_capacity:
53
+ design bearing capacity [kN]
54
+ design_negative_friction:
55
+ design negative friction [kN]
56
+ group_centre_to_centre_validation:
57
+ group centre to centre validation
58
+ group_centre_to_centre_validation_15:
59
+ group centre to centre validation 15 meter
60
+ group_centre_to_centre_validation_20:
61
+ group centre to centre validation 20 meter
62
+ group_centre_to_centre_validation_25:
63
+ group centre to centre validation 25 meter
64
+ mean_calculated_bearing_capacity:
65
+ mean calculated bearing capacity [kN]
66
+ min_calculated_bearing_capacity:
67
+ min calculated bearing capacity [kN]
68
+ net_design_bearing_capacity:
69
+ net design bearing capacity [kN]
70
+ nominal_cpt:
71
+ nominal cpt
72
+ pile_tip_level:
73
+ pile tip level [m w.r.t NAP]
74
+ variation_coefficient:
75
+ variation coefficient [-]
76
+ xi_factor:
77
+ xi factor
78
+ xi_values:
79
+ xi values [-]
80
+ """
81
+ self._characteristic_bearing_capacity = characteristic_bearing_capacity
82
+ self._design_bearing_capacity = design_bearing_capacity
83
+ self._design_negative_friction = design_negative_friction
84
+ self._group_centre_to_centre_validation = group_centre_to_centre_validation
85
+ self._group_centre_to_centre_validation_15 = (
86
+ group_centre_to_centre_validation_15
87
+ )
88
+ self._group_centre_to_centre_validation_20 = (
89
+ group_centre_to_centre_validation_20
90
+ )
91
+ self._group_centre_to_centre_validation_25 = (
92
+ group_centre_to_centre_validation_25
93
+ )
94
+ self._mean_calculated_bearing_capacity = mean_calculated_bearing_capacity
95
+ self._min_calculated_bearing_capacity = min_calculated_bearing_capacity
96
+ self._net_design_bearing_capacity = net_design_bearing_capacity
97
+ self._nominal_cpt = nominal_cpt
98
+ self._pile_tip_level = pile_tip_level
99
+ self._variation_coefficient = variation_coefficient
100
+ self._xi_factor = xi_factor
101
+ self._xi_values = xi_values
67
102
 
68
- def __post_init__(self) -> None:
69
103
  raw_lengths = [len(values) for values in self.__dict__.values()]
70
104
  if len(list(set(raw_lengths))) > 1:
71
105
  raise ValueError("All values in this dataclass must have the same length.")
72
106
 
73
107
  @property
74
- def dataframe(self) -> pd.DataFrame:
108
+ def characteristic_bearing_capacity(self) -> NDArray[np.float64]:
109
+ """Characteristic bearing capacity [kN]"""
110
+ return np.array(self._characteristic_bearing_capacity).astype(np.float64)
111
+
112
+ @property
113
+ def design_bearing_capacity(self) -> NDArray[np.float64]:
114
+ """Design bearing capacity [kN]"""
115
+ return np.array(self._design_bearing_capacity).astype(np.float64)
116
+
117
+ @property
118
+ def design_negative_friction(self) -> NDArray[np.float64]:
119
+ """Design negative friction [kN]"""
120
+ return np.array(self._design_negative_friction).astype(np.float64)
121
+
122
+ @property
123
+ def group_centre_to_centre_validation(self) -> NDArray[np.bool_]:
124
+ """Group centre to centre validation"""
125
+ return np.array(self._group_centre_to_centre_validation).astype(np.bool_)
126
+
127
+ @property
128
+ def group_centre_to_centre_validation_15(self) -> NDArray[np.bool_]:
129
+ """Group centre to centre validation 15 meter"""
130
+ return np.array(self._group_centre_to_centre_validation_15).astype(np.bool_)
131
+
132
+ @property
133
+ def group_centre_to_centre_validation_20(self) -> NDArray[np.bool_]:
134
+ """Group centre to centre validation 20 meter"""
135
+ return np.array(self._group_centre_to_centre_validation_20).astype(np.bool_)
136
+
137
+ @property
138
+ def group_centre_to_centre_validation_25(self) -> NDArray[np.bool_]:
139
+ """Group centre to centre validation 25 meter"""
140
+ return np.array(self._group_centre_to_centre_validation_25).astype(np.bool_)
141
+
142
+ @property
143
+ def mean_calculated_bearing_capacity(self) -> NDArray[np.float64]:
144
+ """Mean calculated bearing capacity [kN]"""
145
+ return np.array(self._mean_calculated_bearing_capacity).astype(np.float64)
146
+
147
+ @property
148
+ def min_calculated_bearing_capacity(self) -> NDArray[np.float64]:
149
+ """Min calculated bearing capacity [kN]"""
150
+ return np.array(self._min_calculated_bearing_capacity).astype(np.float64)
151
+
152
+ @property
153
+ def net_design_bearing_capacity(self) -> NDArray[np.float64]:
154
+ """Net design bearing capacity [kN]"""
155
+ return np.array(self._net_design_bearing_capacity).astype(np.float64)
156
+
157
+ @property
158
+ def nominal_cpt(self) -> NDArray[np.str_]:
159
+ """Nominal cpt"""
160
+ return np.array(self._nominal_cpt).astype(str)
161
+
162
+ @property
163
+ def pile_tip_level(self) -> NDArray[np.float64]:
164
+ """Pile tip level [m w.r.t NAP]"""
165
+ return np.array(self._pile_tip_level).astype(np.float64)
166
+
167
+ @property
168
+ def variation_coefficient(self) -> NDArray[np.float64]:
169
+ """Variation coefficient [-]"""
170
+ return np.array(self._variation_coefficient).astype(np.float64)
171
+
172
+ @property
173
+ def xi_factor(self) -> NDArray[np.str_]:
174
+ """Xi factor"""
175
+ return np.array(self._xi_factor).astype(str)
176
+
177
+ @property
178
+ def xi_values(self) -> NDArray[np.float64]:
179
+ """Xi values [-]"""
180
+ return np.array(self._xi_values).astype(np.float64)
181
+
182
+ @cached_property
183
+ def to_pandas(self) -> pd.DataFrame:
75
184
  return pd.DataFrame(self.__dict__)
76
185
 
77
186
  def plot_variation_coefficient(
@@ -102,7 +211,7 @@ class SingleClusterData:
102
211
  """
103
212
  Plot the bearing capacity and variation coefficient in a subplot
104
213
 
105
- Notes
214
+ Note
106
215
  ------
107
216
  For the `Net bearing capacity` subplot there are two colors plotted:
108
217
  - orange: conservative bearing capacity
@@ -142,7 +251,7 @@ class SingleClusterData:
142
251
  """
143
252
  Plot the spacing checks in a subplot
144
253
 
145
- Notes
254
+ Note
146
255
  ------
147
256
  For the `spacing` subplot there are two colors plotted:
148
257
  - red: invalid spacing
@@ -199,7 +308,7 @@ class SingleClusterData:
199
308
  """
200
309
  Plot the xi factor in a subplot
201
310
 
202
- Notes
311
+ Note
203
312
  ------
204
313
  For the `xi factor` subplot there are two colors plotted:
205
314
  - olive: xi3
@@ -319,7 +428,7 @@ class SingleClusterResult:
319
428
  ],
320
429
  net_design_bearing_capacity=table["net_design_bearing_capacity"],
321
430
  nominal_cpt=table["nominal_cpt"],
322
- pile_tip_level=table["pile_tip_level"],
431
+ pile_tip_level=[round(elem, 2) for elem in table["pile_tip_level"]],
323
432
  variation_coefficient=table["variation_coefficient"],
324
433
  xi_factor=table["xi_factor"],
325
434
  xi_values=table["xi_values"],
@@ -390,7 +499,7 @@ class SingleClusterResult:
390
499
  - xi factor
391
500
  - centre to centre validation
392
501
 
393
- Notes
502
+ Note
394
503
  ------
395
504
  For the `Net bearing capacity` subplot there are two colors plotted:
396
505
  - orange: conservative bearing capacity
@@ -458,10 +567,45 @@ class GrouperResults:
458
567
  """
459
568
 
460
569
  clusters: List[SingleClusterResult]
570
+ multi_cpt_bearing_results: MultiCPTBearingResults
571
+
572
+ def __post_init__(self) -> None:
573
+ for cluster in self.clusters:
574
+ for cpt_name in cluster.cpt_names:
575
+ # check if the cpt names in the SingleClusterResults are also present
576
+ # in the MultiCPTBearingResults
577
+ if (
578
+ cpt_name
579
+ not in self.multi_cpt_bearing_results.cpt_results.cpt_results_dict.keys()
580
+ ):
581
+ raise ValueError(
582
+ "CPT names dont match between MultiCPTBearingResults object and GrouperResults. "
583
+ "Make sure that you use the same MultiCPTBearingResults as you generated "
584
+ "the subgroups/clusters with."
585
+ )
586
+
587
+ # Check that all the pile tip levels in the SingleClusterResults are
588
+ # also present in the MultiCPTBearingResults
589
+ for pile_tip_level in cluster.data.pile_tip_level:
590
+ if not np.isclose(
591
+ pile_tip_level,
592
+ self.multi_cpt_bearing_results.cpt_results.cpt_results_dict[
593
+ cpt_name
594
+ ].table.pile_tip_level_nap,
595
+ rtol=1e-2,
596
+ ).any():
597
+ raise ValueError(
598
+ "Pile tip levels dont match between MultiCPTBearingResults object and GrouperResults. "
599
+ "Make sure that you use the same MultiCPTBearingResults as you generated "
600
+ "the subgroups/clusters with."
601
+ )
461
602
 
462
603
  @classmethod
463
604
  def from_api_response(
464
- cls, response_dict: dict, pile_load_uls: float
605
+ cls,
606
+ response_dict: dict,
607
+ pile_load_uls: float,
608
+ multi_cpt_bearing_results: MultiCPTBearingResults,
465
609
  ) -> "GrouperResults":
466
610
  """
467
611
  Stores the response of the PileCore endpoint
@@ -473,12 +617,88 @@ class GrouperResults:
473
617
  The resulting response of a call to `get_groups_api_result()`
474
618
  pile_load_uls:
475
619
  ULS load in kN. Used to determine if a grouping configuration is valid.
620
+ multi_cpt_bearing_results:
621
+ The container that holds multiple SingleCPTBearingResults objects
476
622
  """
477
623
  results = [
478
624
  SingleClusterResult.from_api_response(item, pile_load_uls)
479
625
  for item in response_dict["sub_groups"]
480
626
  ]
481
- return cls(clusters=results)
627
+ return cls(
628
+ clusters=results, multi_cpt_bearing_results=multi_cpt_bearing_results
629
+ )
630
+
631
+ @cached_property
632
+ def max_bearing_results(self) -> "MaxBearingResults":
633
+ """
634
+ Get the results of the maximum net design bearing capacity (R_c_d_net) for every CPT.
635
+ """
636
+ max_bearing: Dict[str, Any] = {}
637
+
638
+ # iterate over single cpt result
639
+ for (
640
+ cpt_name,
641
+ _single_cpt_result,
642
+ ) in self.multi_cpt_bearing_results.cpt_results.cpt_results_dict.items():
643
+ single_cpt_result = deepcopy(_single_cpt_result)
644
+ max_bearing[cpt_name] = dict(
645
+ pile_head_level_nap=single_cpt_result.pile_head_level_nap,
646
+ soil_properties=single_cpt_result.soil_properties,
647
+ results_table=dict(
648
+ pile_tip_level_nap=single_cpt_result.table.pile_tip_level_nap,
649
+ R_c_d_net=single_cpt_result.table.R_c_d_net,
650
+ F_nk_d=single_cpt_result.table.F_nk_d,
651
+ origin=[f"CPT:{cpt_name}"]
652
+ * len(single_cpt_result.table.pile_tip_level_nap),
653
+ ),
654
+ )
655
+
656
+ # iterate over subgroups result
657
+ for cluster_idx, cluster in enumerate(self.clusters):
658
+ # iterate over cpts in subgroup
659
+ for cpt_name in cluster.cpt_names:
660
+ # iterate over pile tip levels in the cluster results for the cpt
661
+ for cluster_ptl_idx, ptl in enumerate(cluster.data.pile_tip_level):
662
+ # find corresponding pile tip level index in the max_bearing results
663
+ max_bearing_ptl_idx = np.abs(
664
+ max_bearing[cpt_name]["results_table"]["pile_tip_level_nap"]
665
+ - ptl
666
+ ).argmin()
667
+
668
+ # check bearing capacity
669
+ if cluster.data.net_design_bearing_capacity[
670
+ cluster_ptl_idx
671
+ ] > np.nan_to_num(
672
+ max_bearing[cpt_name]["results_table"]["R_c_d_net"][
673
+ max_bearing_ptl_idx
674
+ ]
675
+ ):
676
+ # replace data
677
+ max_bearing[cpt_name]["results_table"]["R_c_d_net"][
678
+ max_bearing_ptl_idx
679
+ ] = cluster.data.net_design_bearing_capacity[cluster_ptl_idx]
680
+ max_bearing[cpt_name]["results_table"]["F_nk_d"][
681
+ max_bearing_ptl_idx
682
+ ] = cluster.data.design_negative_friction[cluster_ptl_idx]
683
+ max_bearing[cpt_name]["results_table"]["origin"][
684
+ max_bearing_ptl_idx
685
+ ] = f"Group:{cluster_idx}"
686
+
687
+ return MaxBearingResults(
688
+ cpt_results_dict={
689
+ cpt_name: MaxBearingResult(
690
+ pile_head_level_nap=data["pile_head_level_nap"],
691
+ soil_properties=data["soil_properties"],
692
+ table=MaxBearingTable(
693
+ pile_tip_level_nap=data["results_table"]["pile_tip_level_nap"],
694
+ R_c_d_net=data["results_table"]["R_c_d_net"],
695
+ F_nk_d=data["results_table"]["F_nk_d"],
696
+ origin=data["results_table"]["origin"],
697
+ ),
698
+ )
699
+ for cpt_name, data in max_bearing.items()
700
+ }
701
+ )
482
702
 
483
703
  def map(
484
704
  self,
@@ -555,6 +775,9 @@ class GrouperResults:
555
775
  ) -> plt.Figure:
556
776
  """
557
777
  Plot a summary of the valid subgroups.
778
+
779
+ Note
780
+ -----
558
781
  Plot contains the:
559
782
 
560
783
  - cpts within a subgroup
@@ -135,7 +135,9 @@ class CPTGroupResultsTable:
135
135
  cpt_normative:
136
136
  The normative CPT. Can be "group average" if that was found to be the normative scenario.
137
137
  """
138
- self.pile_tip_level_nap = np.array(pile_tip_level_nap).astype(np.float64)
138
+ self.pile_tip_level_nap = (
139
+ np.array(pile_tip_level_nap).astype(np.float64).round(decimals=2)
140
+ )
139
141
  """The pile-tip level [m] w.r.t. NAP."""
140
142
  self.R_s_k = np.array(R_s_k).astype(np.float64)
141
143
  """The characteristic value of the shaft bearingcapacity [kN]."""
@@ -309,8 +311,7 @@ class SingleCPTBearingResultsContainer:
309
311
  cpt_results_dict:
310
312
  A dictionary that maps the cpt-names to SingleCPTBearingResults objects.
311
313
  """
312
- self.cpt_results_dict = cpt_results_dict
313
- """A dictionary that maps the cpt-names to SingleCPTBearingResults objects."""
314
+ self._cpt_results_dict = cpt_results_dict
314
315
 
315
316
  @classmethod
316
317
  def from_api_response(
@@ -341,6 +342,11 @@ class SingleCPTBearingResultsContainer:
341
342
 
342
343
  return self.get_cpt_results(test_id)
343
344
 
345
+ @property
346
+ def cpt_results_dict(self) -> Dict[str, SingleCPTBearingResults]:
347
+ """The dictionary that maps the cpt-names to SingleCPTBearingResults objects."""
348
+ return self._cpt_results_dict
349
+
344
350
  @property
345
351
  def test_ids(self) -> List[str]:
346
352
  """The test-ids of the CPTs."""