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 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
@@ -0,0 +1,5 @@
1
+ from pydantic_xml import BaseXmlModel
2
+
3
+
4
+ class Include(BaseXmlModel, tag="Include", validate_assignment=True):
5
+ text: str
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)