|
| 1 | +#Protoype for the 2D bond-based analytic stiffness matrix including fracture |
| 2 | +# using a pre-crack square plate |
| 3 | +#@author Patrick Diehl (patrickdiehl@lsu.edu) |
| 4 | +#@date September 2020 |
| 5 | +import numpy as np |
| 6 | +from scipy import linalg |
| 7 | +from shapely.geometry import LineString |
| 8 | +import matplotlib.pyplot as plt |
| 9 | +import matplotlib as mpl |
| 10 | +import sys |
| 11 | +import pickle |
| 12 | +from matplotlib import rc |
| 13 | +rc('font',**{'family':'sans-serif','sans-serif':['Helvetica']}) |
| 14 | +rc('text', usetex=True) |
| 15 | +rc('font', size=14) |
| 16 | + |
| 17 | +np.set_printoptions(precision=4) |
| 18 | +#mpl.style.use('seaborn') |
| 19 | + |
| 20 | +class Compute: |
| 21 | + |
| 22 | + nodes = [] |
| 23 | + neighbors = [] |
| 24 | + |
| 25 | + # Config |
| 26 | + E=4000 |
| 27 | + G=E/(2*(1+1/3)) |
| 28 | + beta=10 |
| 29 | + C=300000000 |
| 30 | + rbar=np.sqrt(0.5/beta) |
| 31 | + |
| 32 | + def __init__(self,h,delta_factor,iter): |
| 33 | + # Generate the mesh |
| 34 | + self.h = h |
| 35 | + self.delta_factor = delta_factor |
| 36 | + self.delta = self.delta_factor*h |
| 37 | + n = int(15/self.h) + 1 |
| 38 | + self.fix = [] |
| 39 | + self.loadT = [] |
| 40 | + self.loadB = [] |
| 41 | + self.z = [] |
| 42 | + self.iter = iter |
| 43 | + |
| 44 | + #Generate grid |
| 45 | + index = 0 |
| 46 | + |
| 47 | + for i in range(0,n): |
| 48 | + for j in range(0,n): |
| 49 | + self.nodes.append([i*h,j*h]) |
| 50 | + |
| 51 | + if j*h < self.delta and i * h < 13 * self.delta : |
| 52 | + self.loadB.append(index) |
| 53 | + #plt.scatter(i*h,j*h) |
| 54 | + |
| 55 | + if j * h > 15 + h - self.delta and i * h < 13 * self.delta: |
| 56 | + self.loadT.append(index) |
| 57 | + #plt.scatter(i*h,j*h) |
| 58 | + |
| 59 | + if j*h < self.delta and i * h > 15 + h - self.delta: |
| 60 | + self.fix.append(index) |
| 61 | + #plt.scatter(i*h,j*h) |
| 62 | + |
| 63 | + if j * h > 15 + h - self.delta and i * h > 15 + h - self.delta: |
| 64 | + self.fix.append(index) |
| 65 | + #plt.scatter(i*h,j*h) |
| 66 | + |
| 67 | + index += 1 |
| 68 | + |
| 69 | + |
| 70 | + #plt.show() |
| 71 | + #sys.exit(1) |
| 72 | + |
| 73 | + self.fix = np.sort(self.fix) |
| 74 | + |
| 75 | + self.nodes = np.array(self.nodes) |
| 76 | + |
| 77 | + self.V = np.empty(len(self.nodes)) |
| 78 | + self.V.fill(h*h) |
| 79 | + |
| 80 | + self.d = np.zeros(len(self.nodes)) |
| 81 | + |
| 82 | + self.VB = np.pi * self.delta * self.delta |
| 83 | + # Search neighbors |
| 84 | + self.searchNeighbors() |
| 85 | + |
| 86 | + self.f = np.zeros(2*len(self.nodes)) |
| 87 | + |
| 88 | + if self.iter == 1: |
| 89 | + |
| 90 | + # Initialize |
| 91 | + self.uCurrent = np.zeros(2*len(self.nodes)).reshape((len(self.nodes),2)) |
| 92 | + |
| 93 | + else: |
| 94 | + filehandler = open("bond-based-2d-plate-"+str(self.h)+"-"+str(self.delta_factor)+"-"+str(self.iter-1)+"-displacement.npy", "rb") |
| 95 | + #self.nodes += np.load(filehandler) |
| 96 | + self.uCurrent = np.load(filehandler) |
| 97 | + |
| 98 | + |
| 99 | + |
| 100 | + #Apply the load to the body force vector |
| 101 | + self.b = np.zeros(2*len(self.nodes)) |
| 102 | + self.b2 = np.zeros(2*len(self.nodes)) |
| 103 | + self.b3 = np.zeros(2*len(self.nodes)) |
| 104 | + for i in range(0,len(self.nodes)): |
| 105 | + if i in self.loadT: |
| 106 | + self.b[2*i+1] = 4e3 / (2*self.delta*self.delta) |
| 107 | + self.b2[2*i+1] = 4e5 / (2*self.delta*self.delta) |
| 108 | + self.b3[2*i+1] = 4e6 / (2*self.delta*self.delta) |
| 109 | + if i in self.loadB: |
| 110 | + self.b[2*i+1] = -(4e3) / (2*self.delta*self.delta) |
| 111 | + self.b2[2*i+1] = -(4e5) / (2*self.delta*self.delta) |
| 112 | + self.b3[2*i+1] = -(4e6) / (2*self.delta*self.delta) |
| 113 | + |
| 114 | + print("Matrix size "+str(2*len(self.nodes))+"x"+str(2*len(self.nodes))) |
| 115 | + |
| 116 | + |
| 117 | + def searchNeighbors(self): |
| 118 | + left = np.array([0,7.5]) |
| 119 | + right = np.array([7.5,7.5]) |
| 120 | + neighbor = [] |
| 121 | + |
| 122 | + |
| 123 | + #fig = plt.gcf() |
| 124 | + #fig.set_size_inches(4,50) |
| 125 | + |
| 126 | + for i in range(0,len(self.nodes)): |
| 127 | + self.neighbors.append([]) |
| 128 | + for j in range(0,len(self.nodes)): |
| 129 | + if i != j and self.length(j,i) <= self.delta: |
| 130 | + if not self.intersect(left,right,self.nodes[i],self.nodes[j]): |
| 131 | + self.neighbors[i].append(j) |
| 132 | + #plt.plot([self.nodes[i][0],self.nodes[j][0]],[self.nodes[i][1],self.nodes[j][1]],c="#91A3B0",alpha=0.15) |
| 133 | + neighbor.append(len(self.neighbors[i])) |
| 134 | + |
| 135 | + #plt.scatter(self.nodes[:,0],self.nodes[:,1],c=neighbor) |
| 136 | + #plt.xlabel("Position $x$",fontsize = 30) |
| 137 | + #plt.ylabel("Position $y$",fontsize = 30) |
| 138 | + #clb = plt.colorbar() |
| 139 | + #clb.set_label(r'$B_\delta(x)$',labelpad=5) |
| 140 | + #plt.show() |
| 141 | + #sys.exit() |
| 142 | + |
| 143 | + def L(self,i,j): |
| 144 | + r = np.sqrt(self.length(i,j)) * self.S(i,j) |
| 145 | + return (2./self.VB) * self.w(self.length(i,j))/self.delta * self.f1(r) / self.length(i,j) * self.e(i,j) * self.V[j] |
| 146 | + |
| 147 | + |
| 148 | + def residual(self,iter): |
| 149 | + self.f.fill(0) |
| 150 | + self.f += self.b * (iter)+ self.b * 7 + 13 * self.b3 + 1 * self.b2 |
| 151 | + |
| 152 | + for i in range(0,len(self.nodes)): |
| 153 | + for j in self.neighbors[i]: |
| 154 | + if not i in self.fix: |
| 155 | + tmp = self.L(i,j) |
| 156 | + self.f[2*i] += tmp[0] |
| 157 | + self.f[2*i+1] += tmp[1] |
| 158 | + |
| 159 | + self.damage(i,j) |
| 160 | + |
| 161 | + def damage(self,i,j): |
| 162 | + z = self.d[i] |
| 163 | + sr = 0 |
| 164 | + sij = self.S(i,j) |
| 165 | + rij = self.length(i,j) |
| 166 | + |
| 167 | + if rij > 1e-12: |
| 168 | + sr = np.abs(sij) / (self.rbar / np.sqrt(rij) ) |
| 169 | + if z < sr : |
| 170 | + z = sr |
| 171 | + |
| 172 | + self.d[i] = z |
| 173 | + |
| 174 | + |
| 175 | + def length(self,i,j): |
| 176 | + return np.sqrt((self.nodes[j][0]-self.nodes[i][0]) * (self.nodes[j][0]-self.nodes[i][0]) + (self.nodes[j][1]-self.nodes[i][1]) * (self.nodes[j][1]-self.nodes[i][1]) ) |
| 177 | + |
| 178 | + def S(self,i,j): |
| 179 | + return np.dot((self.uCurrent[j] - self.uCurrent[i]) / self.length(i,j), self.e(i,j)) |
| 180 | + |
| 181 | + def w(self,r): |
| 182 | + return 1 |
| 183 | + |
| 184 | + def e(self,i,j): |
| 185 | + return (self.nodes[j]-self.nodes[i]) / self.length(i,j) |
| 186 | + |
| 187 | + def f1(self,r): |
| 188 | + return 2*r*self.C*self.beta* np.exp(-self.beta * r * r ) |
| 189 | + |
| 190 | + def f2(self,r): |
| 191 | + return 2*self.C*self.beta*np.exp(-r*r*self.beta)-4*self.C*r*r*self.beta*self.beta*np.exp(-r*r*self.beta) |
| 192 | + |
| 193 | + def A(self,i,j): |
| 194 | + r = np.sqrt(self.length(i,j)) * self.S(i,j) |
| 195 | + return (2./self.VB) * self.w(self.length(i,j))/self.delta * self.f2(r) * ( 1. / self.length(i,j)) * self.E(i,j) |
| 196 | + |
| 197 | + |
| 198 | + def assemblymatrix(self): |
| 199 | + self.matrix = np.zeros((2*len(self.nodes),2*len(self.nodes)),dtype=np.double) |
| 200 | + for i in range(0,len(self.nodes)): |
| 201 | + if not i in self.fix: |
| 202 | + for j in self.neighbors[i]: |
| 203 | + tmp = self.A(i,j) |
| 204 | + |
| 205 | + #Set the matrix entries for the neighbors |
| 206 | + self.matrix[i*2][j*2] += tmp[0,0] |
| 207 | + self.matrix[i*2][j*2+1] += tmp[0,1] |
| 208 | + self.matrix[i*2+1][j*2] += tmp[1,0] |
| 209 | + self.matrix[i*2+1][j*2+1] += tmp[1,1] |
| 210 | + #set the matrix entries for the node it self |
| 211 | + self.matrix[i*2][i*2] -= tmp[0,0] |
| 212 | + self.matrix[i*2][i*2+1] -= tmp[0,1] |
| 213 | + self.matrix[i*2+1][i*2] -= tmp[1,0] |
| 214 | + self.matrix[i*2+1][i*2+1] -= tmp[1,1] |
| 215 | + |
| 216 | + def E(self,i,j): |
| 217 | + return np.tensordot(self.e(i,j),self.e(j,i),axes=0) |
| 218 | + |
| 219 | + def intersect(self,A,B,C,D): |
| 220 | + line = LineString([(A[0], A[1]), (B[0], B[1])]) |
| 221 | + other = LineString([(C[0], C[1]), (D[0], D[1])]) |
| 222 | + return line.intersects(other) |
| 223 | + |
| 224 | + def solve(self,maxIt,epsilion): |
| 225 | + |
| 226 | + for iter in range(1,maxIt+1): |
| 227 | + |
| 228 | + print(" ##### Load step: " + str(iter+self.iter) + " #####") |
| 229 | + self.residual(iter) |
| 230 | + print("Residual with intial guess",np.linalg.norm(self.f)) |
| 231 | + |
| 232 | + |
| 233 | + residual = np.finfo(np.float).max |
| 234 | + |
| 235 | + it = 1 |
| 236 | + while(residual > epsilion): |
| 237 | + |
| 238 | + self.assemblymatrix() |
| 239 | + |
| 240 | + b = np.copy(self.f) |
| 241 | + |
| 242 | + for i in range(0,len(self.fix)): |
| 243 | + |
| 244 | + index = 2* self.fix[len(self.fix)-1-i] |
| 245 | + b = np.delete(b,index+1) |
| 246 | + b = np.delete(b,index) |
| 247 | + self.matrix = np.delete(self.matrix,index+1,1) |
| 248 | + self.matrix = np.delete(self.matrix,index+1,0) |
| 249 | + self.matrix = np.delete(self.matrix,index,1) |
| 250 | + self.matrix = np.delete(self.matrix,index,0) |
| 251 | + |
| 252 | + |
| 253 | + #print("Con:" + str(np.linalg.cond(self.matrix))+" Det: "+str(np.linalg.det(self.matrix))) |
| 254 | + |
| 255 | + #res = linalg.solve(self.matrix,b) |
| 256 | + |
| 257 | + inv = linalg.inv(self.matrix) |
| 258 | + |
| 259 | + res = inv.dot(b) |
| 260 | + |
| 261 | + |
| 262 | + unew = np.zeros(2*len(self.nodes)).reshape((len(self.nodes),2)) |
| 263 | + j = 0 |
| 264 | + for i in range(0,len(self.uCurrent)): |
| 265 | + if not i in self.fix: |
| 266 | + unew[i] = np.array([res[2*j],res[2*j+1]]) |
| 267 | + j += 1 |
| 268 | + |
| 269 | + |
| 270 | + |
| 271 | + self.uCurrent += unew |
| 272 | + |
| 273 | + |
| 274 | + |
| 275 | + self.residual(iter) |
| 276 | + residual = np.linalg.norm(self.f) |
| 277 | + print("Iteration ",it," Residual: ",residual) |
| 278 | + it += 1 |
| 279 | + |
| 280 | + self.plot(iter) |
| 281 | + self.dump(iter) |
| 282 | + |
| 283 | + def plot(self,iter): |
| 284 | + step = iter + self.iter |
| 285 | + # Plot u_x |
| 286 | + plt.scatter(self.nodes[:,0]+self.uCurrent[:,0],self.nodes[:,1]+self.uCurrent[:,1],c=abs(self.uCurrent[:,0])) |
| 287 | + ax = plt.gca() |
| 288 | + ax.set_facecolor('#F0F8FF') |
| 289 | + v = np.linspace(min(abs(self.uCurrent[:,0])), max(abs(self.uCurrent[:,0])), 10, endpoint=True) |
| 290 | + clb = plt.colorbar(ticks=v) |
| 291 | + clb.set_label(r'Displacement $ u_x $',labelpad=5) |
| 292 | + plt.xlabel("Position $x$") |
| 293 | + plt.ylabel("Position $y$") |
| 294 | + plt.savefig("bond-based-2d-plate-u-x-"+str(self.h)+"-"+str(self.delta_factor)+"-"+str(step)+".pdf",bbox_inches='tight') |
| 295 | + plt.clf() |
| 296 | + # Plot u_y |
| 297 | + plt.scatter(self.nodes[:,0]+self.uCurrent[:,0],self.nodes[:,1]+self.uCurrent[:,1],c=self.uCurrent[:,1]) |
| 298 | + ax = plt.gca() |
| 299 | + ax.set_facecolor('#F0F8FF') |
| 300 | + v = np.linspace(min(self.uCurrent[:,1]), max(self.uCurrent[:,1]), 10, endpoint=True) |
| 301 | + clb = plt.colorbar(ticks=v) |
| 302 | + clb.set_label(r'Displacement $ u_y $',labelpad=5) |
| 303 | + plt.xlabel("Position $x$") |
| 304 | + plt.ylabel("Position $y$") |
| 305 | + plt.savefig("bond-based-2d-plate-u-y-"+str(self.h)+"-"+str(self.delta_factor)+"-"+str(step)+".pdf",bbox_inches='tight') |
| 306 | + plt.clf() |
| 307 | + # Plot damage |
| 308 | + plt.scatter(self.nodes[:,0]+self.uCurrent[:,0],self.nodes[:,1]+self.uCurrent[:,1],c=self.d) |
| 309 | + ax = plt.gca() |
| 310 | + ax.set_facecolor('#F0F8FF') |
| 311 | + v = np.linspace(min(self.d), max(self.d), 10, endpoint=True) |
| 312 | + clb = plt.colorbar(ticks=v) |
| 313 | + clb.set_label(r'Damage',labelpad=5) |
| 314 | + plt.xlabel("Position $x$") |
| 315 | + plt.ylabel("Position $y$") |
| 316 | + plt.savefig("bond-based-2d-plate-d-"+str(self.h)+"-"+str(self.delta_factor)+"-"+str(step)+".pdf",bbox_inches='tight') |
| 317 | + plt.clf() |
| 318 | + |
| 319 | + def dump(self,iter): |
| 320 | + step = iter + self.iter |
| 321 | + filehandler = open("bond-based-2d-plate-"+str(self.h)+"-"+str(self.delta_factor)+"-"+str(step)+"-displacement.npy", "wb") |
| 322 | + np.save(filehandler, self.uCurrent) |
| 323 | + filehandler = open("bond-based-2d-plate-"+str(self.h)+"-"+str(self.delta_factor)+"-"+str(step)+"-damage.npy", "wb") |
| 324 | + np.save(filehandler,self.d) |
| 325 | + filehandler = open("bond-based-2d-plate-"+str(self.h)+"-"+str(self.delta_factor)+"-"+str(step)+"-b.npy", "wb") |
| 326 | + np.save(filehandler,self.b) |
| 327 | + filehandler = open("bond-based-2d-plate-"+str(self.h)+"-"+str(self.delta_factor)+"-"+str(step)+"-f.npy", "wb") |
| 328 | + np.save(filehandler,self.f) |
| 329 | + |
| 330 | + |
| 331 | +if __name__=="__main__": |
| 332 | + |
| 333 | + c = Compute(float(sys.argv[1]),int(sys.argv[2]),int(sys.argv[3])) |
| 334 | + c.solve(100,1e-3) |
| 335 | + #c.plot() |
0 commit comments