pyfebio 0.1.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 pyfebio might be problematic. Click here for more details.
- pyfebio/__init__.py +45 -0
- pyfebio/_types.py +95 -0
- pyfebio/boundary.py +119 -0
- pyfebio/constraints.py +41 -0
- pyfebio/contact.py +172 -0
- pyfebio/control.py +73 -0
- pyfebio/discrete.py +40 -0
- pyfebio/globals.py +12 -0
- pyfebio/include.py +5 -0
- pyfebio/initial.py +27 -0
- pyfebio/loaddata.py +51 -0
- pyfebio/loads.py +55 -0
- pyfebio/material.py +1191 -0
- pyfebio/mesh.py +354 -0
- pyfebio/meshadaptor.py +159 -0
- pyfebio/meshdata.py +52 -0
- pyfebio/meshdomains.py +65 -0
- pyfebio/model.py +144 -0
- pyfebio/module.py +14 -0
- pyfebio/output.py +298 -0
- pyfebio/py.typed +0 -0
- pyfebio/rigid.py +275 -0
- pyfebio/step.py +28 -0
- pyfebio-0.1.0.dist-info/METADATA +336 -0
- pyfebio-0.1.0.dist-info/RECORD +26 -0
- pyfebio-0.1.0.dist-info/WHEEL +4 -0
pyfebio/__init__.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from . import (
|
|
2
|
+
boundary,
|
|
3
|
+
constraints,
|
|
4
|
+
contact,
|
|
5
|
+
control,
|
|
6
|
+
discrete,
|
|
7
|
+
globals,
|
|
8
|
+
include,
|
|
9
|
+
initial,
|
|
10
|
+
loaddata,
|
|
11
|
+
loads,
|
|
12
|
+
material,
|
|
13
|
+
mesh,
|
|
14
|
+
meshadaptor,
|
|
15
|
+
meshdata,
|
|
16
|
+
meshdomains,
|
|
17
|
+
model,
|
|
18
|
+
module,
|
|
19
|
+
output,
|
|
20
|
+
rigid,
|
|
21
|
+
step,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"boundary",
|
|
26
|
+
"constraints",
|
|
27
|
+
"contact",
|
|
28
|
+
"control",
|
|
29
|
+
"discrete",
|
|
30
|
+
"globals",
|
|
31
|
+
"initial",
|
|
32
|
+
"loaddata",
|
|
33
|
+
"loads",
|
|
34
|
+
"material",
|
|
35
|
+
"mesh",
|
|
36
|
+
"meshdata",
|
|
37
|
+
"meshdomains",
|
|
38
|
+
"meshadaptor",
|
|
39
|
+
"model",
|
|
40
|
+
"module",
|
|
41
|
+
"output",
|
|
42
|
+
"rigid",
|
|
43
|
+
"step",
|
|
44
|
+
"include",
|
|
45
|
+
]
|
pyfebio/_types.py
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
from typing import Annotated
|
|
2
|
+
|
|
3
|
+
from pydantic import StringConstraints
|
|
4
|
+
|
|
5
|
+
StringFloatVec = Annotated[
|
|
6
|
+
str,
|
|
7
|
+
StringConstraints(
|
|
8
|
+
strip_whitespace=True,
|
|
9
|
+
pattern=r"^([+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?,)+([+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?)$",
|
|
10
|
+
),
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
StringFloatVec2 = Annotated[
|
|
15
|
+
str,
|
|
16
|
+
StringConstraints(
|
|
17
|
+
strip_whitespace=True,
|
|
18
|
+
pattern=r"^" + ",".join([r"[+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?"] * 2) + r"$",
|
|
19
|
+
),
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
StringFloatVec3 = Annotated[
|
|
23
|
+
str,
|
|
24
|
+
StringConstraints(
|
|
25
|
+
strip_whitespace=True,
|
|
26
|
+
pattern=r"^" + ",".join([r"[+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?"] * 3) + r"$",
|
|
27
|
+
),
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
StringFloatVec9 = Annotated[
|
|
32
|
+
str,
|
|
33
|
+
StringConstraints(
|
|
34
|
+
strip_whitespace=True,
|
|
35
|
+
pattern=r"^" + ",".join([r"[+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?"] * 9) + r"$",
|
|
36
|
+
),
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
StringUIntVec = Annotated[
|
|
40
|
+
str,
|
|
41
|
+
StringConstraints(
|
|
42
|
+
strip_whitespace=True,
|
|
43
|
+
pattern=r"^(?:\d+)(?:,(?:\d+))*$",
|
|
44
|
+
),
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
StringUIntVec2 = Annotated[
|
|
48
|
+
str,
|
|
49
|
+
StringConstraints(strip_whitespace=True, pattern=r"^" + ",".join([r"\d+"] * 2) + r"$"),
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
StringUIntVec3 = Annotated[
|
|
53
|
+
str,
|
|
54
|
+
StringConstraints(strip_whitespace=True, pattern=r"^" + ",".join([r"\d+"] * 3) + r"$"),
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
StringUIntVec4 = Annotated[
|
|
58
|
+
str,
|
|
59
|
+
StringConstraints(strip_whitespace=True, pattern=r"^" + ",".join([r"\d+"] * 4) + r"$"),
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
StringUIntVec6 = Annotated[
|
|
63
|
+
str,
|
|
64
|
+
StringConstraints(strip_whitespace=True, pattern=r"^" + ",".join([r"\d+"] * 6) + r"$"),
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
StringUIntVec8 = Annotated[
|
|
68
|
+
str,
|
|
69
|
+
StringConstraints(strip_whitespace=True, pattern=r"^" + ",".join([r"\d+"] * 8) + r"$"),
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
StringUIntVec9 = Annotated[
|
|
73
|
+
str,
|
|
74
|
+
StringConstraints(strip_whitespace=True, pattern=r"^" + ",".join([r"\d+"] * 9) + r"$"),
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
StringUIntVec10 = Annotated[
|
|
78
|
+
str,
|
|
79
|
+
StringConstraints(strip_whitespace=True, pattern=r"^" + ",".join([r"\d+"] * 10) + r"$"),
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
StringUIntVec15 = Annotated[
|
|
83
|
+
str,
|
|
84
|
+
StringConstraints(strip_whitespace=True, pattern=r"^" + ",".join([r"\d+"] * 15) + r"$"),
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
StringUIntVec20 = Annotated[
|
|
88
|
+
str,
|
|
89
|
+
StringConstraints(strip_whitespace=True, pattern=r"^" + ",".join([r"\d+"] * 20) + r"$"),
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
StringUIntVec27 = Annotated[
|
|
93
|
+
str,
|
|
94
|
+
StringConstraints(strip_whitespace=True, pattern=r"^" + ",".join([r"\d+"] * 27) + r"$"),
|
|
95
|
+
]
|
pyfebio/boundary.py
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
|
|
3
|
+
from pydantic_xml import BaseXmlModel, attr, element
|
|
4
|
+
|
|
5
|
+
from ._types import (
|
|
6
|
+
StringFloatVec3,
|
|
7
|
+
StringFloatVec9,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Value(BaseXmlModel, validate_assignment=True):
|
|
12
|
+
lc: int = attr()
|
|
13
|
+
text: float | StringFloatVec3 = 1.0
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class BCZeroDisplacement(BaseXmlModel, tag="bc", validate_assignment=True):
|
|
17
|
+
type: Literal["zero displacement"] = attr(default="zero displacement", frozen=True)
|
|
18
|
+
node_set: str = attr()
|
|
19
|
+
x_dof: Literal[0, 1] = element(default=0)
|
|
20
|
+
y_dof: Literal[0, 1] = element(default=0)
|
|
21
|
+
z_dof: Literal[0, 1] = element(default=0)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class BCZeroShellDisplacement(BaseXmlModel, tag="bc", validate_assignment=True):
|
|
25
|
+
type: Literal["zero shell displacement"] = attr(
|
|
26
|
+
default="zero shell displacement", frozen=True
|
|
27
|
+
)
|
|
28
|
+
node_set: str = attr()
|
|
29
|
+
sx_dof: Literal[0, 1] = element(default=0)
|
|
30
|
+
sy_dof: Literal[0, 1] = element(default=0)
|
|
31
|
+
sz_dof: Literal[0, 1] = element(default=0)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class BCZeroFluidPressure(BaseXmlModel, tag="bc", validate_assignment=True):
|
|
35
|
+
type: Literal["zero fluid pressure"] = attr(
|
|
36
|
+
default="zero fluid pressure", frozen=True
|
|
37
|
+
)
|
|
38
|
+
node_set: str = attr()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class BCPrescribedDisplacement(BaseXmlModel, tag="bc", validate_assignment=True):
|
|
42
|
+
type: Literal["prescribed displacement"] = attr(
|
|
43
|
+
default="prescribed displacement", frozen=True
|
|
44
|
+
)
|
|
45
|
+
node_set: str = attr()
|
|
46
|
+
dof: Literal["x", "y", "z"] = element()
|
|
47
|
+
value: Value = element()
|
|
48
|
+
relative: Literal[0, 1] = element(default=0)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class BCPrescribedShellDisplacement(BaseXmlModel, tag="bc", validate_assignment=True):
|
|
52
|
+
type: Literal["prescribed shell displacement"] = attr(
|
|
53
|
+
default="prescribed shell displacement", frozen=True
|
|
54
|
+
)
|
|
55
|
+
node_set: str = attr()
|
|
56
|
+
dof: Literal["sx", "sy", "sz"] = element()
|
|
57
|
+
value: Value = element()
|
|
58
|
+
relative: Literal[0, 1] = element(default=0)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class BCPrescribedFluidPressure(BaseXmlModel, tag="bc", validate_assignment=True):
|
|
62
|
+
type: Literal["prescribed fluid pressure"] = attr(
|
|
63
|
+
default="prescribed fluid pressure", frozen=True
|
|
64
|
+
)
|
|
65
|
+
node_set: str = attr()
|
|
66
|
+
value: Value = element()
|
|
67
|
+
relative: Literal[0, 1] = element(default=0)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class BCPrescribedDeformation(BaseXmlModel, tag="bc", validate_assignment=True):
|
|
71
|
+
type: Literal["prescribed deformation"] = attr(default="prescribed deformation")
|
|
72
|
+
node_set: str = attr()
|
|
73
|
+
scale: Value = element()
|
|
74
|
+
F: StringFloatVec9 = element(default="1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0")
|
|
75
|
+
relative: Literal[0, 1] = element(default=0)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class BCRigid(BaseXmlModel, tag="bc", validate_assignment=True):
|
|
79
|
+
type: Literal["rigid"] = attr(default="rigid", frozen=True)
|
|
80
|
+
node_set: str = attr()
|
|
81
|
+
rb: str = element()
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class BCRigidDeformation(BaseXmlModel, tag="bc", validate_assignment=True):
|
|
85
|
+
type: Literal["rigid deformation"] = attr(default="rigid deformation", frozen=True)
|
|
86
|
+
node_set: str = attr()
|
|
87
|
+
pos: StringFloatVec3 = element(default="0.0,0.0,0.0")
|
|
88
|
+
rot: Value = element()
|
|
89
|
+
relative: Literal[0, 1] = element(default=0)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class BCNormalDisplacement(BaseXmlModel, tag="bc", validate_assignment=True):
|
|
93
|
+
type: Literal["normal displacement"] = attr(
|
|
94
|
+
default="normal displacement", frozen=True
|
|
95
|
+
)
|
|
96
|
+
surface: str = attr()
|
|
97
|
+
scale: Value = element()
|
|
98
|
+
surface_hint: Literal[0, 1] = element(default=0)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
BoundaryConditionType = (
|
|
102
|
+
BCZeroDisplacement
|
|
103
|
+
| BCZeroShellDisplacement
|
|
104
|
+
| BCZeroFluidPressure
|
|
105
|
+
| BCPrescribedDisplacement
|
|
106
|
+
| BCPrescribedShellDisplacement
|
|
107
|
+
| BCPrescribedFluidPressure
|
|
108
|
+
| BCPrescribedDeformation
|
|
109
|
+
| BCRigid
|
|
110
|
+
| BCRigidDeformation
|
|
111
|
+
| BCNormalDisplacement
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class Boundary(BaseXmlModel, tag="Boundary", validate_assignment=True):
|
|
116
|
+
all_bcs: list[BoundaryConditionType] = element(default=[], tag="bc")
|
|
117
|
+
|
|
118
|
+
def add_bc(self, new_bc: BoundaryConditionType):
|
|
119
|
+
self.all_bcs.append(new_bc)
|
pyfebio/constraints.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from typing import Literal, Union
|
|
2
|
+
|
|
3
|
+
from pydantic_xml import BaseXmlModel, attr, element
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ConstraintSymmetryPlane(BaseXmlModel, validate_assignment=True):
|
|
7
|
+
type: Literal["symmetry plane"] = attr(default="symmetry plane", frozen=True)
|
|
8
|
+
laugon: Literal[0, 1] = element(default=1)
|
|
9
|
+
tol: float = element(default=0.1)
|
|
10
|
+
penalty: float = element(default=1)
|
|
11
|
+
rhs: float = element(default=0)
|
|
12
|
+
minaug: int = element(default=0)
|
|
13
|
+
maxaug: int = element(default=50)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ConstraintPrestrain(BaseXmlModel, validate_assignment=True):
|
|
17
|
+
type: Literal["prestrain"] = attr(default="prestrain", frozen=True)
|
|
18
|
+
update: Literal[0, 1] = element(default=1)
|
|
19
|
+
tolerance: Literal[0] | float = element(default=0)
|
|
20
|
+
min_iters: int = element(default=0)
|
|
21
|
+
max_iters: int = element(default=-1)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ConstraintInSituStretch(BaseXmlModel, validate_assignment=True):
|
|
25
|
+
type: Literal["in-situ stretch"] = attr(default="in-situ stretch", frozen=True)
|
|
26
|
+
update: Literal[0, 1] = element(default=1)
|
|
27
|
+
tolerance: Literal[0] | float = element(default=0)
|
|
28
|
+
min_iters: int = element(default=0)
|
|
29
|
+
max_iters: int = element(default=-1)
|
|
30
|
+
max_stretch: Literal[0] | float = element(default=0)
|
|
31
|
+
isochoric: Literal[0, 1] = element(default=1)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
ConstraintTypes = Union[ConstraintSymmetryPlane, ConstraintInSituStretch, ConstraintPrestrain]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class Constraints(BaseXmlModel, tag="Constraints", validate_assignment=True):
|
|
38
|
+
all_constraints: list[ConstraintTypes] = element(default=[], tag="constraint")
|
|
39
|
+
|
|
40
|
+
def add_constraint(self, new_constraint: ConstraintTypes):
|
|
41
|
+
self.all_constraints.append(new_constraint)
|
pyfebio/contact.py
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
|
|
3
|
+
from pydantic_xml import BaseXmlModel, attr, element
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class SlidingBase(BaseXmlModel, validate_assignment=True):
|
|
7
|
+
name: str | None = attr(default=None)
|
|
8
|
+
surface_pair: str = attr()
|
|
9
|
+
laugon: Literal["PENALTY", "AUGLAG"] = element(default="PENALTY")
|
|
10
|
+
two_pass: Literal[0, 1] = element(default=0)
|
|
11
|
+
penalty: float = element(default=1.0)
|
|
12
|
+
auto_penalty: Literal[0, 1] = element(default=0)
|
|
13
|
+
update_penalty: Literal[0, 1] = element(default=0)
|
|
14
|
+
tolerance: float = element(default=0.01)
|
|
15
|
+
gaptol: Literal[0] | float = element(default=0)
|
|
16
|
+
minaug: int = element(default=0)
|
|
17
|
+
maxaug: int = element(default=10)
|
|
18
|
+
search_tol: float = element(default=0.01)
|
|
19
|
+
search_radius: Literal[0] | float = element(default=0)
|
|
20
|
+
knmult: float = element(default=1.0)
|
|
21
|
+
seg_up: int = element(default=0)
|
|
22
|
+
node_reloc: Literal[0, 1] = element(default=0)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class SlidingElastic(SlidingBase):
|
|
26
|
+
type: Literal["sliding-elastic"] = attr(default="sliding-elastic")
|
|
27
|
+
symmetric_stiffness: Literal[0, 1] = element(default=1)
|
|
28
|
+
smooth_aug: int = element(default=0)
|
|
29
|
+
tension: Literal[0, 1] = element(default=0)
|
|
30
|
+
fric_coeff: Literal[0] | float = element(default=0)
|
|
31
|
+
flip_primary: Literal[0, 1] = element(default=0)
|
|
32
|
+
flip_secondary: Literal[0, 1] = element(default=0)
|
|
33
|
+
shell_bottom_primary: Literal[0, 1] = element(default=0)
|
|
34
|
+
shell_bottom_secondary: Literal[0, 1] = element(default=0)
|
|
35
|
+
search_radius: Literal[0] | float = element(default=1)
|
|
36
|
+
offset: Literal[0] | float = element(default=0)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class SlidingFacetOnFacet(SlidingBase):
|
|
40
|
+
type: Literal["sliding-facet-on-facet"] = attr(default="sliding-facet-on-facet")
|
|
41
|
+
smooth_aug: int = element(default=0)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class SlidingNodeOnFacet(SlidingBase):
|
|
45
|
+
type: Literal["sliding-node-on-facet"] = attr(default="sliding-node-on-facet")
|
|
46
|
+
fric_coeff: Literal[0] | float = element(default=0)
|
|
47
|
+
fric_penalty: Literal[0] | float = element(default=0)
|
|
48
|
+
ktmult: Literal[0] | float = element(default=0)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
SlidingContactType = SlidingElastic | SlidingFacetOnFacet | SlidingNodeOnFacet
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class ContactPotential(BaseXmlModel, validate_assignment=True):
|
|
55
|
+
type: Literal["contact potential"] = attr(default="contact potential", frozen=True)
|
|
56
|
+
name: str = attr()
|
|
57
|
+
surface_pair: str = attr()
|
|
58
|
+
kc: float = element(default=1e-6)
|
|
59
|
+
p: int = element(default=4)
|
|
60
|
+
R_in: float = element(default=0.01)
|
|
61
|
+
R_out: float = element(default=0.05)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class SlidingBiphasic(SlidingBase):
|
|
65
|
+
type: Literal["sliding-biphasic"] = attr(default="sliding-biphasic")
|
|
66
|
+
ptol: Literal[0] | float = element(default=0)
|
|
67
|
+
pressure_penalty: float = element(default=1)
|
|
68
|
+
symmetric_stiffness: Literal[0, 1] = element(default=1)
|
|
69
|
+
fric_coeff: Literal[0] | float = element(default=0)
|
|
70
|
+
contact_frac: float = element(default=0.0)
|
|
71
|
+
smooth_aug: int = element(default=0)
|
|
72
|
+
smooth_fls: int = element(default=0)
|
|
73
|
+
search_radius: Literal[0] | float = element(default=1)
|
|
74
|
+
flip_primary: Literal[0, 1] = element(default=0)
|
|
75
|
+
flip_secondary: Literal[0, 1] = element(default=0)
|
|
76
|
+
shell_bottom_primary: Literal[0, 1] = element(default=0)
|
|
77
|
+
shell_bottom_secondary: Literal[0, 1] = element(default=0)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class Sliding2(SlidingBase):
|
|
81
|
+
type: Literal["sliding2"] = attr(default="sliding2")
|
|
82
|
+
ptol: Literal[0] | float = element(default=0)
|
|
83
|
+
pressure_penalty: float = element(default=1)
|
|
84
|
+
symmetric_stiffness: Literal[0, 1] = element(default=1)
|
|
85
|
+
search_radius: Literal[0] | float = element(default=1)
|
|
86
|
+
smooth_aug: int = element(default=0)
|
|
87
|
+
dual_proj: Literal[0, 1] = element(default=1)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
SlidingBiphasicContactType = SlidingBiphasic | Sliding2
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class TiedBase(BaseXmlModel, validate_assignment=True):
|
|
94
|
+
name: str = attr()
|
|
95
|
+
surface_pair: str = attr()
|
|
96
|
+
laugon: Literal["PENALTY", "AUGLAG"] = element(default="PENALTY")
|
|
97
|
+
tolerance: float = element(default=0.1)
|
|
98
|
+
penalty: float = element(default=1)
|
|
99
|
+
knmult: float = element(default=1)
|
|
100
|
+
minaug: int = element(default=0)
|
|
101
|
+
maxaug: int = element(default=10)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class TiedElastic(TiedBase):
|
|
105
|
+
type: Literal["tied-elastic"] = attr(default="tied-elastic", frozen=True)
|
|
106
|
+
auto_penalty: Literal[0, 1] = element(default=0)
|
|
107
|
+
update_penalty: Literal[0, 1] = element(default=0)
|
|
108
|
+
two_pass: Literal[0, 1] = element(default=0)
|
|
109
|
+
search_tol: float = element(default=0.01)
|
|
110
|
+
search_radius: float = element(default=1)
|
|
111
|
+
gaptol: float = element(default=-1)
|
|
112
|
+
symmetric_stiffness: Literal[0, 1] = element(default=1)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class TiedFacetOnFacet(TiedBase):
|
|
116
|
+
type: Literal["tied-facet-on-facet"] = attr(
|
|
117
|
+
default="tied-facet-on-facet", frozen=True
|
|
118
|
+
)
|
|
119
|
+
tolerance: float = element(default=0.01)
|
|
120
|
+
search_tolerance: float = element(default=0.0001)
|
|
121
|
+
gap_offset: Literal[0, 1] = element(default=0)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class TiedNodeOnFacet(TiedBase):
|
|
125
|
+
type: Literal["tied-node-on-facet"] = attr(
|
|
126
|
+
default="tied-node-on-facet", frozen=True
|
|
127
|
+
)
|
|
128
|
+
tolerance: float = element(default=0.01)
|
|
129
|
+
search_tolerance: float = element(default=0.0001)
|
|
130
|
+
offset_shells: Literal[0, 1] = element(default=0)
|
|
131
|
+
max_distance: Literal[0] | float = element(deafult=0)
|
|
132
|
+
special: Literal[0, 1] = element(default=1)
|
|
133
|
+
node_reloc: Literal[0, 1] = element(default=0)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class TiedBiphasic(TiedBase):
|
|
137
|
+
type: Literal["tied-biphasic"] = attr(default="tied-biphasic", frozen=True)
|
|
138
|
+
gaptol: float = element(default=-1)
|
|
139
|
+
ptol: float = element(default=-1)
|
|
140
|
+
auto_penalty: Literal[0, 1] = element(default=0)
|
|
141
|
+
update_penalty: Literal[0, 1] = element(default=0)
|
|
142
|
+
two_pass: Literal[0, 1] = element(default=0)
|
|
143
|
+
search_tol: float = element(default=0.01)
|
|
144
|
+
search_radius: float = element(default=1)
|
|
145
|
+
knmult: float = element(default=1)
|
|
146
|
+
pressure_penalty: float = element(default=1)
|
|
147
|
+
symmetric_stiffness: Literal[0, 1] = element(default=1)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
ContactType = (
|
|
151
|
+
SlidingElastic
|
|
152
|
+
| SlidingFacetOnFacet
|
|
153
|
+
| SlidingNodeOnFacet
|
|
154
|
+
| SlidingBiphasic
|
|
155
|
+
| Sliding2
|
|
156
|
+
| ContactPotential
|
|
157
|
+
| TiedElastic
|
|
158
|
+
| TiedFacetOnFacet
|
|
159
|
+
| TiedNodeOnFacet
|
|
160
|
+
| TiedBiphasic
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
class Contact(BaseXmlModel, tag="Contact", validate_assignment=True):
|
|
165
|
+
all_contact_interfaces: list[ContactType] = element(default=[], tag="contact")
|
|
166
|
+
|
|
167
|
+
def add_contact(self, new_contact: ContactType):
|
|
168
|
+
if new_contact.name is None:
|
|
169
|
+
new_contact.name = (
|
|
170
|
+
f"{new_contact.type}_{len(self.all_contact_interfaces) + 1}"
|
|
171
|
+
)
|
|
172
|
+
self.all_contact_interfaces.append(new_contact)
|
pyfebio/control.py
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
|
|
3
|
+
from pydantic_xml import BaseXmlModel, attr, element
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class TimeStepValue(BaseXmlModel, validate_assignment=True):
|
|
7
|
+
lc: int | None = attr(default=None)
|
|
8
|
+
text: float = 1.0
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TimeStepper(BaseXmlModel, validate_assignment=True):
|
|
12
|
+
type: Literal["default"] = attr(default="default", frozen=True)
|
|
13
|
+
max_retries: int = element(default=5, ge=0)
|
|
14
|
+
opt_iter: int = element(default=11, ge=0)
|
|
15
|
+
dtmin: float = element(default=0.0, ge=0.0)
|
|
16
|
+
dtmax: TimeStepValue = element(default=TimeStepValue())
|
|
17
|
+
aggressiveness: Literal[0, 1] = element(default=0)
|
|
18
|
+
cutback: float = element(default=0.5, ge=0.0, le=1.0)
|
|
19
|
+
dtforce: Literal[0, 1] = element(default=0)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class LinearSolver(BaseXmlModel, validate_assignment=True):
|
|
23
|
+
type: Literal["pardiso", "mkl_dss"] = attr(default="pardiso")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class QuasiNewtonMethod(BaseXmlModel, validate_assignment=True):
|
|
27
|
+
type: Literal["BFGS", "Broyden", "Full Newton", "JFNK", "Modified Newton"] = attr(default="BFGS")
|
|
28
|
+
max_ups: int = element(default=10, ge=0)
|
|
29
|
+
max_buffer_size: int = element(default=0, ge=0)
|
|
30
|
+
cycle_buffer: Literal[0, 1] = element(default=1)
|
|
31
|
+
cmax: float = element(default=1.0e5)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class Solver(BaseXmlModel, validate_assignment=True, skip_empty=True):
|
|
35
|
+
"""
|
|
36
|
+
Class for Non-Linear Solver settings. Currently, only supporting
|
|
37
|
+
"solid" and "biphasic" analyses, and direct linear solvers "pardiso"
|
|
38
|
+
and "mkl_dss".
|
|
39
|
+
|
|
40
|
+
More nuanced parameters can be added as needed.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
type: Literal["solid", "biphasic"] = attr(default="solid")
|
|
44
|
+
dtol: float = element(default=0.001, gt=0)
|
|
45
|
+
etol: float = element(default=0.01, ge=0)
|
|
46
|
+
rtol: float = element(default=0, ge=0)
|
|
47
|
+
ptol: float | None = element(default=None)
|
|
48
|
+
lstol: float = element(default=0.9, ge=0)
|
|
49
|
+
lsmin: float = element(default=0.01, gt=0)
|
|
50
|
+
lsiter: int = element(default=5, ge=0)
|
|
51
|
+
max_refs: int = element(default=15, ge=0)
|
|
52
|
+
diverge_reform: Literal[0, 1] = element(default=1)
|
|
53
|
+
min_residual: float = element(default=1e-20, gt=0.0)
|
|
54
|
+
qn_method: QuasiNewtonMethod = element(default=QuasiNewtonMethod())
|
|
55
|
+
symmetric_stiffness: Literal["symmetric", "non-symmetric", "symmetric-structure"] = element(default="non-symmetric")
|
|
56
|
+
equation_scheme: Literal["staggered", "block"] = element(default="staggered")
|
|
57
|
+
equation_order: Literal["default", "reverse", "febio2"] = element(default="default")
|
|
58
|
+
optimize_bw: Literal[0, 1] = element(default=0)
|
|
59
|
+
linear_solver: LinearSolver = element(default=LinearSolver())
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class Control(BaseXmlModel, tag="Control", validate_assignment=True):
|
|
63
|
+
analysis: Literal["STATIC", "DYNAMIC", "STEADY-STATE", "TRANSIENT"] = element(default="STATIC")
|
|
64
|
+
time_steps: int = element(default=10)
|
|
65
|
+
step_size: float = element(default=0.1)
|
|
66
|
+
plot_zero_state: Literal[0, 1] = element(default=0)
|
|
67
|
+
plot_range: str = element(default="0,-1")
|
|
68
|
+
plot_level: Literal["PLOT_NEVER", "PLOT_MAJOR_ITRS", "PLOT_MINOR_ITRS", "PLOT_MUST_POINTS"] = element(default="PLOT_MAJOR_ITRS")
|
|
69
|
+
plot_stride: int = element(default=1)
|
|
70
|
+
output_stride: int = element(default=1)
|
|
71
|
+
adaptor_re_solve: int = element(default=1)
|
|
72
|
+
time_stepper: TimeStepper | None = element(default=TimeStepper())
|
|
73
|
+
solver: Solver = element(default=Solver())
|
pyfebio/discrete.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
|
|
3
|
+
from pydantic_xml import BaseXmlModel, attr, element
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Spring(BaseXmlModel, tag="discrete_material", validate_assignment=True):
|
|
7
|
+
id: int = attr()
|
|
8
|
+
name: str = attr()
|
|
9
|
+
type: str = attr(default="linear spring", frozen=True)
|
|
10
|
+
E: float = element(default=1.0)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class NonlinearSpringForce(BaseXmlModel, tag="force", validate_assignment=True):
|
|
14
|
+
type: Literal["math"] = attr(default="math", frozen=True)
|
|
15
|
+
math: str = element()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class NonlinearSpring(BaseXmlModel, tag="discrete_material", validate_assignment=True):
|
|
19
|
+
id: int = attr()
|
|
20
|
+
name: str = attr()
|
|
21
|
+
type: str = attr(default="nonlinear spring", frozen=True)
|
|
22
|
+
scale: float = element(default=1.0)
|
|
23
|
+
measure: Literal["strain"] = element(default="strain", frozen=True)
|
|
24
|
+
force: NonlinearSpringForce = element()
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class DiscreteEntry(BaseXmlModel, tag="discrete", validate_assignment=True):
|
|
28
|
+
dmat: int = attr()
|
|
29
|
+
discrete_set: str = attr()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Discrete(BaseXmlModel, validate_assignment=True):
|
|
33
|
+
discrete_materials: list[NonlinearSpring | Spring] = element(default=[])
|
|
34
|
+
discrete_elements: list[DiscreteEntry] = element(default=[])
|
|
35
|
+
|
|
36
|
+
def add_discrete_material(self, new_material: NonlinearSpring | Spring):
|
|
37
|
+
self.discrete_materials.append(new_material)
|
|
38
|
+
|
|
39
|
+
def add_discrete_element(self, new_element: DiscreteEntry):
|
|
40
|
+
self.discrete_elements.append(new_element)
|
pyfebio/globals.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from pydantic_xml import BaseXmlModel, element
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Constants(BaseXmlModel, validate_assignment=True):
|
|
5
|
+
T: float = element(default=298)
|
|
6
|
+
P: float = element(default=0)
|
|
7
|
+
R: float = element(default=8.314e-6)
|
|
8
|
+
Fc: float = element(default=96485e-9)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Globals(BaseXmlModel, validate_assignment=True):
|
|
12
|
+
constants: Constants = element(default=Constants(), tag="Constants")
|
pyfebio/include.py
ADDED
pyfebio/initial.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
|
|
3
|
+
from pydantic_xml import BaseXmlModel, attr, element
|
|
4
|
+
|
|
5
|
+
from ._types import (
|
|
6
|
+
StringFloatVec3,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class InitialVelocity(BaseXmlModel, validate_assignment=True):
|
|
11
|
+
type: Literal["velocity", "shell_velocity", "initial fluid velocity"] = attr()
|
|
12
|
+
node_set: str = attr()
|
|
13
|
+
value: StringFloatVec3 = element(default="0.0,0.0,0.0")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class InitialPrestrain(BaseXmlModel, validate_assignment=True):
|
|
17
|
+
type: Literal["prestrain"] = attr(default="prestrain", frozen=True)
|
|
18
|
+
node_set: str = attr()
|
|
19
|
+
init: Literal[0, 1] = element(default=1)
|
|
20
|
+
reset: Literal[0, 1] = element(default=1)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class Initial(BaseXmlModel, validate_assignment=True):
|
|
24
|
+
all_initial_conditions: list[InitialVelocity | InitialPrestrain] = element(default=[], tag="ic")
|
|
25
|
+
|
|
26
|
+
def add_initial_condition(self, new_initial_condition: InitialVelocity | InitialPrestrain):
|
|
27
|
+
self.all_initial_conditions.append(new_initial_condition)
|
pyfebio/loaddata.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
|
|
3
|
+
from pydantic_xml import BaseXmlModel, attr, element
|
|
4
|
+
|
|
5
|
+
from ._types import (
|
|
6
|
+
StringFloatVec2,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class CurvePoints(BaseXmlModel, validate_assignment=True):
|
|
11
|
+
points: list[StringFloatVec2] = element(default=[], tag="pt")
|
|
12
|
+
|
|
13
|
+
def add_point(self, new_point: StringFloatVec2):
|
|
14
|
+
self.points.append(new_point)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class LoadCurve(BaseXmlModel, tag="load_controller", validate_assignment=True):
|
|
18
|
+
id: int = attr()
|
|
19
|
+
type: Literal["loadcurve"] = attr(default="loadcurve", frozen=True)
|
|
20
|
+
interpolate: Literal["LINEAR", "STEP", "SMOOTH"] = element(default="LINEAR")
|
|
21
|
+
extend: Literal["CONSTANT", "EXTRAPOLATE", "REPEAT", "REPEAT OFFSET"] = element(default="CONSTANT")
|
|
22
|
+
points: CurvePoints = element()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class PIDController(BaseXmlModel, validate_assignment=True):
|
|
26
|
+
id: int = attr()
|
|
27
|
+
type: Literal["PID"] = attr(default="PID", frozen=True)
|
|
28
|
+
var: str = element()
|
|
29
|
+
target: float = element()
|
|
30
|
+
Kp: float = element()
|
|
31
|
+
Kd: float = element()
|
|
32
|
+
Ki: float = element()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class MathController(BaseXmlModel, validate_assignment=True):
|
|
36
|
+
id: int = attr()
|
|
37
|
+
type: Literal["math"] = attr(default="math", frozen=True)
|
|
38
|
+
math: str = element()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class LoadData(BaseXmlModel, validate_assignment=True):
|
|
42
|
+
load_controllers: list[LoadCurve | PIDController | MathController] = element(default=[], tag="load_controller")
|
|
43
|
+
|
|
44
|
+
def add_load_curve(self, new_load_curve: LoadCurve):
|
|
45
|
+
self.load_controllers.append(new_load_curve)
|
|
46
|
+
|
|
47
|
+
def add_pid_controller(self, new_pid_controller: PIDController):
|
|
48
|
+
self.load_controllers.append(new_pid_controller)
|
|
49
|
+
|
|
50
|
+
def add_math_controller(self, new_math_controller: MathController):
|
|
51
|
+
self.load_controllers.append(new_math_controller)
|