oILAB
Loading...
Searching...
No Matches
inverse_design_core.py
Go to the documentation of this file.
1from dataclasses import dataclass
2import numpy as np
3from fractions import Fraction
4
5
6# ------------------------------------------------------------
7# Utilities for Fraction-based linear algebra
8# ------------------------------------------------------------
9def frac_array(x):
10 return np.array(x, dtype=object)
11
12
14 if isinstance(x, Fraction):
15 return x
16 return Fraction(x).limit_denominator()
17
18
19def frac_dot(a, b):
20 return sum(to_fraction(ai) * to_fraction(bi) for ai, bi in zip(a, b))
21
22
23def frac_outer(a, b):
24 return np.array([[to_fraction(ai) * to_fraction(bj) for bj in b] for ai in a], dtype=object)
25
26
27def frac_abs(x):
28 return abs(to_fraction(x))
29
30
32 return np.array([[float(to_fraction(x)) for x in row] for row in M], dtype=float)
33
34
35def inv2_frac(M):
36 """
37 Exact inverse of 2x2 matrix with Fraction entries.
38 """
39 a, b = M[0, 0], M[0, 1]
40 c, d = M[1, 0], M[1, 1]
41
42 det = a * d - b * c
43 if det == 0:
44 raise ValueError("Matrix is singular.")
45
46 inv = frac_array([
47 [ d / det, -b / det],
48 [-c / det, a / det],
49 ])
50 return inv
51
52
53# ------------------------------------------------------------
54# Geometry helpers
55# ------------------------------------------------------------
57 """
58 Compute primitive integer vector orthogonal to l = (l1, l2):
59 m = (l2, -l1)
60 """
61 l1, l2 = l
62 return frac_array([l2, -l1])
63
64
65# ------------------------------------------------------------
66# Main result container
67# ------------------------------------------------------------
68@dataclass
70 Q: np.ndarray
71 Qinv: np.ndarray
72 F: np.ndarray
73 l3u: np.ndarray
74
75
76# ------------------------------------------------------------
77# Main routine
78# ------------------------------------------------------------
79def run_inverse_design(A, b1u, b2u, b3u, l1u, l2u, beta):
80 """
81 Compute deformation gradient F from Burgers vectors and line directions.
82
83 Parameters
84 ----------
85 A : np.ndarray (2x2)
86 Structure matrix of reference lattice.
87 b1u, b2u, b3u : arrays (Fraction)
88 Burgers vectors in lattice coordinates.
89 l1u, l2u : arrays (Fraction)
90 Line vectors in lattice coordinates.
91 beta : Fraction
92 Network factor (1 or 3).
93
94 Returns
95 -------
96 InverseDesignResult
97 """
98
99 # Ensure Fraction arrays
100 b1u = frac_array(b1u)
101 b2u = frac_array(b2u)
102 b3u = frac_array(b3u)
103 l1u = frac_array(l1u)
104 l2u = frac_array(l2u)
105 beta = to_fraction(beta)
106
107 # Third line direction
108 l3u = -(l1u + l2u)
109
110 B = [b1u, b2u, b3u]
111 L = [l1u, l2u, l3u]
112
113 # Orthogonal vectors
114 mbar = [primitive_orthogonal(li) for li in L]
115
116 # z^i values
117 z1 = frac_abs(frac_dot(L[1], mbar[0]))
118 z2 = frac_abs(frac_dot(L[2], mbar[1]))
119 z3 = frac_abs(frac_dot(L[0], mbar[2]))
120 Z = [z1, z2, z3]
121
122 if any(z == 0 for z in Z):
123 raise ValueError("Degenerate configuration: line vectors are collinear.")
124
125 # Build Q
126 Q = frac_array([
127 [Fraction(1, 1), Fraction(0, 1)],
128 [Fraction(0, 1), Fraction(1, 1)],
129 ])
130
131 for i in range(3):
132 Q -= frac_outer(B[i], mbar[i]) / (beta * Z[i])
133
134 # Inverse in exact arithmetic
135 Qinv = inv2_frac(Q)
136
137 # Convert to float for F
138 Qinv_f = frac_to_float_matrix(Qinv)
139
140 # Compute F
141 Ainv = np.linalg.inv(A)
142 F = A @ Qinv_f @ Ainv
143
144 return InverseDesignResult(
145 Q=Q,
146 Qinv=Qinv,
147 F=F,
148 l3u=l3u,
149 )
150
151
152# ------------------------------------------------------------
153# Debug / printing utilities (optional)
154# ------------------------------------------------------------
155def print_fraction_matrix(name, M):
156 print(f"\n{name} =")
157 for row in M:
158 print(" ", [str(x) for x in row])
Definition range.h:11