├── 2Dcrystal ├── Crystal_2D_data └── NN2D.py ├── 3DTaylor ├── NN3D.py └── Taylor3D ├── README.md └── VUMAT └── Learnedmultiscale.for /2Dcrystal/Crystal_2D_data: -------------------------------------------------------------------------------- 1 | To download the 2D crystal data (2GB) please use the following link: 2 | 3 | https://www.dropbox.com/s/kkv0m4tax6na3mo/Cubic2D16grain64gridPlasticityBiased_randomdtwalk10Sample6000.mat?dl=0 4 | -------------------------------------------------------------------------------- /2Dcrystal/NN2D.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.utils.data 3 | import torch.nn as nn 4 | import torch.optim as optim 5 | import torch.nn.functional as F 6 | 7 | import numpy as np 8 | import scipy.io 9 | import h5py 10 | 11 | import matplotlib.pyplot as plt 12 | import pickle 13 | import tensorly as tl 14 | from tensorly.decomposition import tucker 15 | from tensorly import tucker_to_tensor 16 | 17 | class LpLoss(object): 18 | def __init__(self, d=2, p=2, size_average=True, reduction=True): 19 | super(LpLoss, self).__init__() 20 | 21 | # Dimension and Lp-norm type are postive 22 | assert d > 0 and p > 0 23 | 24 | self.d = d 25 | self.p = p 26 | self.reduction = reduction 27 | self.size_average = size_average 28 | 29 | def abs(self, x, y): 30 | num_examples = x.size()[0] 31 | 32 | # Assume uniform mesh 33 | h = 1.0 / (x.size()[1] - 1.0) 34 | 35 | all_norms = (h ** (self.d / self.p)) * torch.norm(x.view(num_examples, -1) - y.view(num_examples, -1), self.p, 36 | 1) 37 | 38 | if self.reduction: 39 | if self.size_average: 40 | return torch.mean(all_norms) 41 | else: 42 | return torch.sum(all_norms) 43 | 44 | return all_norms 45 | 46 | def rel(self, x, y): 47 | num_examples = x.size()[0] 48 | 49 | diff_norms = torch.norm(x.view(num_examples, -1) - y.view(num_examples, -1), self.p, 1) 50 | y_norms = torch.norm(y.view(num_examples, -1), self.p, 1) 51 | 52 | if self.reduction: 53 | if self.size_average: 54 | return torch.mean(diff_norms / y_norms) 55 | else: 56 | return torch.sum(diff_norms / y_norms) 57 | 58 | return diff_norms / y_norms 59 | 60 | def forward(self, x, y): 61 | return self.rel(x, y) 62 | 63 | def __call__(self, x, y): 64 | return self.forward(x, y) 65 | 66 | 67 | class PCA(object): 68 | def __init__(self, x, dim, subtract_mean=True): 69 | super(PCA, self).__init__() 70 | 71 | # Input size 72 | x_size = list(x.size()) 73 | 74 | # Input data is a matrix 75 | assert len(x_size) == 2 76 | 77 | # Reducing dimension is less than the minimum of the 78 | # number of observations and the feature dimension 79 | assert dim <= min(x_size) 80 | 81 | self.reduced_dim = dim 82 | 83 | if subtract_mean: 84 | self.x_mean = torch.mean(x, dim=0).view(1, -1) 85 | else: 86 | self.x_mean = torch.zeros((x_size[1],), dtype=x.dtype, layout=x.layout, device=x.device) 87 | 88 | # SVD 89 | U, S, V = torch.svd(x - self.x_mean) 90 | V = V.t() 91 | 92 | # Flip sign to ensure deterministic output 93 | max_abs_cols = torch.argmax(torch.abs(U), dim=0) 94 | signs = torch.sign(U[max_abs_cols, range(U.size()[1])]).view(-1, 1) 95 | V *= signs 96 | 97 | self.W = V.t()[:, 0:self.reduced_dim] 98 | self.sing_vals = S.view(-1, ) 99 | 100 | def cuda(self): 101 | self.W = self.W.cuda() 102 | self.x_mean = self.x_mean.cuda() 103 | self.sing_vals = self.sing_vals.cuda() 104 | 105 | def encode(self, x): 106 | return (x - self.x_mean).mm(self.W) 107 | 108 | def decode(self, x): 109 | return x.mm(self.W.t()) + self.x_mean 110 | 111 | def forward(self, x): 112 | return self.decode(self.encode(x)) 113 | 114 | def __call__(self, x): 115 | return self.forward(x) 116 | 117 | 118 | class LeastSquares(object): 119 | def __init__(self, x, y, bias=False, lam=0.0, cuda=True): 120 | super(LeastSquares, self).__init__() 121 | 122 | self.bias = bias 123 | self.cuda = cuda 124 | 125 | # Input sizes 126 | x_size = list(x.size()) 127 | y_size = list(y.size()) 128 | 129 | # Input data are matricies 130 | assert len(x_size) == 2 and len(y_size) == 2 131 | 132 | # Numer of observations match 133 | assert x_size[0] == y_size[0] 134 | 135 | x = x.cpu().numpy() 136 | y = y.cpu().numpy() 137 | 138 | if bias: 139 | x = np.append(x, np.ones((x_size[0], 1)), axis=1) 140 | 141 | if lam <= 0.0: 142 | self.W = torch.from_numpy(np.linalg.lstsq(x, y, rcond=None)[0]) 143 | else: 144 | myid = lam * np.identity(x.shape[1]) 145 | if bias: 146 | myid[x.shape[1] - 1, x.shape[1] - 1] = 0 147 | 148 | self.W = torch.from_numpy(np.linalg.solve(x.T.dot(x) + myid, x.T.dot(y))) 149 | 150 | self.W = self.W.type(torch.FloatTensor) 151 | if cuda: 152 | self.W = self.W.cuda() 153 | 154 | def forward(self, x): 155 | if self.bias: 156 | ones = torch.ones((x.size()[0], 1)).type(torch.FloatTensor) 157 | if self.cuda: 158 | ones = ones.cuda() 159 | 160 | return torch.cat((x, ones), dim=1).mm(self.W) 161 | 162 | return x.mm(self.W) 163 | 164 | def __call__(self, x): 165 | return self.forward(x) 166 | 167 | 168 | class DenseNet(nn.Module): 169 | def __init__(self, layers, nonlinearity): 170 | super(DenseNet, self).__init__() 171 | 172 | self.n_layers = len(layers) - 1 173 | 174 | assert self.n_layers >= 1 175 | 176 | self.layers = nn.ModuleList() 177 | 178 | for j in range(self.n_layers): 179 | self.layers.append(nn.Linear(layers[j], layers[j + 1])) 180 | 181 | if j != self.n_layers - 1: 182 | self.layers.append(nonlinearity()) 183 | 184 | def forward(self, x): 185 | for _, l in enumerate(self.layers): 186 | x = l(x) 187 | 188 | return x 189 | 190 | 191 | class UnitGaussianNormalizer(object): 192 | def __init__(self, x, zeroone_first=True): 193 | super(UnitGaussianNormalizer, self).__init__() 194 | 195 | self.zeroone_first = zeroone_first 196 | 197 | if self.zeroone_first: 198 | self.min = torch.min(x, 0)[0].view(-1, ) 199 | self.max = torch.max(x, 0)[0].view(-1, ) 200 | 201 | s = x.size() 202 | x = ((x.view(s[0], -1) - self.min) / (self.max - self.min)).view(s) 203 | 204 | self.mean = torch.mean(x, 0).view(-1, ) 205 | self.std = torch.std(x, 0).view(-1, ) 206 | 207 | def encode(self, x): 208 | s = x.size() 209 | 210 | x = x.view(s[0], -1) 211 | 212 | if self.zeroone_first: 213 | x = (x - self.min) / (self.max - self.min) 214 | 215 | x = (x - self.mean) / self.std 216 | 217 | x = x.view(s) 218 | 219 | return x 220 | 221 | def decode(self, x): 222 | s = x.size() 223 | 224 | x = x.view(s[0], -1) 225 | 226 | x = (x * self.std) + self.mean 227 | 228 | if self.zeroone_first: 229 | x = (x * (self.max - self.min)) + self.min 230 | 231 | x = x.view(s) 232 | 233 | return x 234 | 235 | 236 | class MatReader(object): 237 | def __init__(self, file_path, to_torch=True, to_cuda=False, to_float=True): 238 | super(MatReader, self).__init__() 239 | 240 | self.to_torch = to_torch 241 | self.to_cuda = to_cuda 242 | self.to_float = to_float 243 | 244 | self.file_path = file_path 245 | 246 | self.data = None 247 | self.old_mat = None 248 | self._load_file() 249 | 250 | def _load_file(self): 251 | try: 252 | self.data = scipy.io.loadmat(self.file_path) 253 | self.old_mat = True 254 | except: 255 | self.data = h5py.File(self.file_path) 256 | self.old_mat = False 257 | 258 | def load_file(self, file_path): 259 | self.file_path = file_path 260 | self._load_file() 261 | 262 | def read_field(self, field): 263 | x = self.data[field] 264 | 265 | if not self.old_mat: 266 | x = x[()] 267 | x = np.transpose(x, axes=range(len(x.shape) - 1, -1, -1)) 268 | 269 | if self.to_float: 270 | x = x.astype(np.float32) 271 | 272 | if self.to_torch: 273 | x = torch.from_numpy(x) 274 | 275 | if self.to_cuda: 276 | x = x.cuda() 277 | 278 | return x 279 | 280 | def set_cuda(self, to_cuda): 281 | self.to_cuda = to_cuda 282 | 283 | def set_torch(self, to_torch): 284 | self.to_torch = to_torch 285 | 286 | def set_float(self, to_float): 287 | self.to_float = to_float 288 | 289 | class PCA_3d(object): 290 | def __init__(self, x, dim): 291 | super(PCA_3d, self).__init__() 292 | 293 | # Input size 294 | x_size = list(x.size()) 295 | 296 | # Reducing dimension is less than the minimum of the 297 | # number of observations and the feature dimension 298 | #assert dim <= min(x_size) 299 | 300 | self.reduced_dim = dim 301 | 302 | # SVD for 3 inputs 303 | U1, S1, V1 = torch.svd(x[:, :, 0]) 304 | U2, S2, V2 = torch.svd(x[:, :, 1]) 305 | U3, S3, V3 = torch.svd(x[:, :, 2]) 306 | V1 = V1.t() 307 | V2 = V2.t() 308 | V3 = V3.t() 309 | 310 | # Flip sign to ensure deterministic output 311 | max_abs_cols_1 = torch.argmax(torch.abs(U1), dim=0) 312 | max_abs_cols_2 = torch.argmax(torch.abs(U2), dim=0) 313 | max_abs_cols_3 = torch.argmax(torch.abs(U3), dim=0) 314 | 315 | signs_1 = torch.sign(U1[max_abs_cols_1, range(U1.size()[1])]).view(-1, 1) 316 | signs_2 = torch.sign(U2[max_abs_cols_2, range(U2.size()[1])]).view(-1, 1) 317 | signs_3 = torch.sign(U3[max_abs_cols_3, range(U3.size()[1])]).view(-1, 1) 318 | 319 | V1 *= signs_1 320 | V2 *= signs_2 321 | V3 *= signs_3 322 | 323 | self.W1 = V1.t()[:, 0:self.reduced_dim] 324 | self.W2 = V2.t()[:, 0:self.reduced_dim] 325 | self.W3 = V3.t()[:, 0:self.reduced_dim] 326 | 327 | def cuda(self): 328 | self.W1 = self.W1.cuda() 329 | self.W2 = self.W2.cuda() 330 | self.W3 = self.W3.cuda() 331 | 332 | def encode(self, x): 333 | x1 = x[:,:,0].mm(self.W1) 334 | x2 = x[:,:,1].mm(self.W2) 335 | x3 = x[:,:,2].mm(self.W3) 336 | x = torch.cat((x1.unsqueeze(2),x2.unsqueeze(2),x3.unsqueeze(2)),2) 337 | return x 338 | 339 | def decode(self, x): 340 | x1 = x[:,:,0].mm(self.W1.t()) 341 | x2 = x[:,:,1].mm(self.W2.t()) 342 | x3 = x[:,:,2].mm(self.W3.t()) 343 | x = torch.cat((x1.unsqueeze(2),x2.unsqueeze(2),x3.unsqueeze(2)),2) 344 | return x 345 | 346 | def forward(self, x): 347 | return self.decode(self.encode(x)) 348 | 349 | def __call__(self, x): 350 | return self.forward(x) 351 | class UnitGaussianNormalizer_3d(object): 352 | def __init__(self, x, zeroone_first=True): 353 | super(UnitGaussianNormalizer_3d, self).__init__() 354 | x1 = x[:,:,0] 355 | x2 = x[:,:,1] 356 | x3 = x[:,:,2] 357 | self.zeroone_first = zeroone_first 358 | 359 | if self.zeroone_first: 360 | self.min_x1 = torch.min(x1, 0)[0].view(-1, ) 361 | self.min_x2 = torch.min(x1, 0)[0].view(-1, ) 362 | self.min_x3 = torch.min(x3, 0)[0].view(-1, ) 363 | 364 | self.max_x1 = torch.max(x2, 0)[0].view(-1, ) 365 | self.max_x2 = torch.max(x2, 0)[0].view(-1, ) 366 | self.max_x3 = torch.max(x2, 0)[0].view(-1, ) 367 | 368 | s = x1.size() 369 | x1 = ((x1.view(s[0], -1) - self.min_x1) / (self.max_x1 - self.min_x1)).view(s) 370 | x2 = ((x2.view(s[0], -1) - self.min_x2) / (self.max_x2 - self.min_x2)).view(s) 371 | x3 = ((x3.view(s[0], -1) - self.min_x3) / (self.max_x3 - self.min_x3)).view(s) 372 | 373 | self.mean_x1 = torch.mean(x1, 0).view(-1, ) 374 | self.mean_x2 = torch.mean(x2, 0).view(-1, ) 375 | self.mean_x3 = torch.mean(x3, 0).view(-1, ) 376 | 377 | self.std_x1 = torch.std(x1, 0).view(-1, ) 378 | self.std_x2 = torch.std(x2, 0).view(-1, ) 379 | self.std_x3 = torch.std(x3, 0).view(-1, ) 380 | 381 | def encode(self, x): 382 | x1 = x[:,:,0] 383 | x2 = x[:,:,1] 384 | x3 = x[:,:,2] 385 | s = x1.size() 386 | 387 | x1 = x1.view(s[0], -1) 388 | x2 = x2.view(s[0], -1) 389 | x3 = x3.view(s[0], -1) 390 | 391 | if self.zeroone_first: 392 | x1 = (x1 - self.min_x1) / (self.max_x1 - self.min_x1) 393 | x2 = (x2 - self.min_x2) / (self.max_x2 - self.min_x2) 394 | x3 = (x3 - self.min_x3) / (self.max_x3 - self.min_x3) 395 | 396 | x1 = (x1 - self.mean_x1) / self.std_x1 397 | x2 = (x2 - self.mean_x2) / self.std_x2 398 | x3 = (x3 - self.mean_x3) / self.std_x3 399 | 400 | 401 | x1 = x1.view(s) 402 | x2 = x2.view(s) 403 | x3 = x3.view(s) 404 | x = torch.cat((x1.unsqueeze(2),x2.unsqueeze(2),x3.unsqueeze(2)),2) 405 | 406 | return x 407 | 408 | def decode(self, x): 409 | x1 = x[:,:,0] 410 | x2 = x[:,:,1] 411 | x3 = x[:,:,2] 412 | s = x1.size() 413 | 414 | x1 = x1.view(s[0], -1) 415 | x2 = x2.view(s[0], -1) 416 | x3 = x3.view(s[0], -1) 417 | 418 | x1 = (x1 * self.std_x1) + self.mean_x1 419 | x2 = (x2 * self.std_x2) + self.mean_x2 420 | x3 = (x3 * self.std_x3) + self.mean_x3 421 | 422 | if self.zeroone_first: 423 | x1 = (x1 * (self.max_x1 - self.min_x1)) + self.min_x1 424 | x2 = (x2 * (self.max_x2 - self.min_x2)) + self.min_x2 425 | x3 = (x3 * (self.max_x3 - self.min_x3)) + self.min_x3 426 | 427 | x1 = x1.view(s) 428 | x2 = x2.view(s) 429 | x3 = x3.view(s) 430 | x = torch.cat((x1.unsqueeze(2),x2.unsqueeze(2),x3.unsqueeze(2)),2) 431 | return x 432 | class DenseNet_tensor(nn.Module): 433 | def __init__(self, ten_layers, layers, nonlinearity): 434 | super(DenseNet_tensor, self).__init__() 435 | # =========== change 3d tensor to 1d scalar ================# 436 | self.n_ten = len(ten_layers)-1 437 | self.ten_layers = nn.ModuleList() 438 | for k in range(self.n_ten): 439 | self.ten_layers.append(nn.Linear(ten_layers[k], ten_layers[k+1])) 440 | self.ten_layers.append(nonlinearity()) 441 | 442 | self.n_layers = len(layers) - 1 443 | assert self.n_layers >= 1 444 | self.layers = nn.ModuleList() 445 | for j in range(self.n_layers): 446 | self.layers.append(nn.Linear(layers[j], layers[j + 1])) 447 | 448 | if j != self.n_layers - 1: 449 | self.layers.append(nonlinearity()) 450 | 451 | def forward(self, x): 452 | for _, m in enumerate(self.ten_layers): 453 | x = m(x) 454 | x = x.squeeze(2) 455 | for _, l in enumerate(self.layers): 456 | x = l(x) 457 | 458 | return x 459 | ########### TO CHANGE ###################################### 460 | USE_CUDA = True 461 | TRAIN_PATH = r'~\Crystal2D.mat' 462 | 463 | Ntotal = 5986 464 | train_size = 3200 465 | test_start = 4000 466 | 467 | N_test = 800 468 | 469 | F11_FIELD = 'F11_field' 470 | F22_FIELD = 'F22_field' 471 | F12_FIELD = 'F12_field' 472 | 473 | SIG11_FIELD = 'sig11_field' 474 | SIG22_FIELD = 'sig22_field' 475 | SIG12_FIELD = 'sig12_field' 476 | 477 | grid_size =64 # Only for plotting 478 | 479 | loss_func = LpLoss() 480 | ######### Preprocessing data #################### 481 | 482 | data_loader = MatReader(TRAIN_PATH) 483 | data_F11 = data_loader.read_field(F11_FIELD).contiguous().view(Ntotal, -1) 484 | data_F22 = data_loader.read_field(F22_FIELD).contiguous().view(Ntotal, -1) 485 | data_F12 = data_loader.read_field(F12_FIELD).contiguous().view(Ntotal, -1) 486 | data_F11 = data_F11[:,0::10] 487 | data_F22 = data_F22[:,0::10] 488 | data_F12 = data_F12[:,0::10] 489 | data_input = torch.cat((data_F11.unsqueeze(2),data_F22.unsqueeze(2),data_F12.unsqueeze(2)),2) 490 | 491 | 492 | data_S11 = data_loader.read_field(SIG11_FIELD).contiguous().view(Ntotal, -1) 493 | data_S22 = data_loader.read_field(SIG22_FIELD).contiguous().view(Ntotal, -1) 494 | data_S12 = data_loader.read_field(SIG12_FIELD).contiguous().view(Ntotal, -1) 495 | data_output = torch.cat((data_S11.unsqueeze(2),data_S22.unsqueeze(2),data_S12.unsqueeze(2)),2) 496 | 497 | data_F11 = data_F11 - 1.0 498 | data_F22 = data_F22 - 1.0 499 | 500 | 501 | #============================ PCA on output and input data ====================================# 502 | x_train = data_input[0:train_size,:,:] 503 | y_train = data_output[0:train_size,:,:] 504 | 505 | x_test = data_input[test_start:Ntotal,:,:] 506 | y_test = data_output[test_start:Ntotal,:,:] 507 | # Reduced dimension of inputs 508 | d1 = 60 509 | # Reduced dimension of outputs 510 | d2 = 60 511 | 512 | NeuroArchi = [d1*3, 1000, 1000, 1000,1000, d2*3] 513 | #TensorArchi = [3,256,256,256,1] 514 | # Perform PCA on the CPU (can be a memory bottleneck for the GPU) 515 | 516 | x_pca = PCA_3d(x_train, d1) 517 | 518 | y_pca = PCA_3d(y_train, d2) 519 | 520 | # Move data and models to the GPU 521 | if USE_CUDA: 522 | x_train = x_train.cuda() 523 | x_test = x_test.cuda() 524 | y_train = y_train.cuda() 525 | y_test = y_test.cuda() 526 | 527 | x_pca.cuda() 528 | y_pca.cuda() 529 | 530 | 531 | 532 | x_train_enc = x_pca.encode(x_train) 533 | x_test_enc = x_pca.encode(x_test) 534 | 535 | y_train_enc = y_pca.encode(y_train) 536 | y_test_enc = y_pca.encode(y_test) 537 | 538 | 539 | net = DenseNet(NeuroArchi, nn.SELU) 540 | 541 | if USE_CUDA: 542 | net.cuda() 543 | 544 | # Number of training epochs 545 | epochs = 500 546 | 547 | # Optimizer and learning rate scheduler 548 | optimizer = torch.optim.Adam(net.parameters(), lr=0.0001) 549 | scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, epochs, 1e-6) 550 | 551 | # Batch size 552 | b_size = 16 553 | 554 | # Wrap traning data in loader 555 | train_loader = torch.utils.data.DataLoader(torch.utils.data.TensorDataset(x_train_enc, y_train_enc), batch_size=b_size, 556 | shuffle=True) 557 | x_test_enc = x_test_enc.view(-1, d1*3) 558 | 559 | # Train neural net 560 | train_err = np.zeros((epochs,)) 561 | test_err = np.zeros((epochs,)) 562 | for ep in range(epochs): 563 | scheduler.step() 564 | train_loss = 0.0 565 | for x, y in train_loader: 566 | optimizer.zero_grad() 567 | x = x.view(-1, d1*3) 568 | #loss = F.mse_loss(net(x), y) 569 | y_train = y_pca.decode(net(x).view(-1,d2,3)) 570 | y_true = y_pca.decode(y) 571 | #y_true = y_true.view(-1,d2*3) 572 | loss = loss_func(y_train,y_true) 573 | loss.backward() 574 | train_loss = train_loss + loss.item() 575 | 576 | optimizer.step() 577 | 578 | #test_err[ep] = F.mse_loss(net(x_test_enc), y_test_enc).item() 579 | y_test_approx = y_pca.decode(net(x_test_enc).view(-1,d2,3).detach()) 580 | test_err[ep] = loss_func(y_test_approx, y_test).item() 581 | #train_err[ep] = F.mse_loss(net(x_train_enc), y_train_enc).item() 582 | train_err[ep] = train_loss/len(train_loader) 583 | print(ep, train_err[ep], test_err[ep]) 584 | if train_err[ep] <= 0.01: 585 | break 586 | 587 | 588 | y_test_approx = y_pca.decode(net(x_test_enc).view(-1,d2,3).detach()) 589 | y_train_approx = y_pca.decode(net(x_train_enc.view(-1, d1*3)).view(-1,d2,3).detach()) 590 | y_train = data_output[0:train_size,:,:] 591 | 592 | print('Relative approximation error (NN):\t', loss_func(y_test_approx, y_test).item()) 593 | 594 | # Plot 595 | 596 | r = np.random.randint(N_test) 597 | 598 | xtruth = x_train[r,:].cpu().numpy() 599 | truth = y_train[r, :,:].cpu().numpy() 600 | approx = y_train_approx[r, :,:].cpu().numpy() 601 | 602 | plt.figure("y_test") 603 | plt.plot(truth[:,0]) 604 | plt.plot(approx[:,0],'k--') 605 | plt.plot(truth[:,1]) 606 | plt.plot(approx[:,1],'k--') 607 | plt.plot(truth[:,2]) 608 | plt.plot(approx[:,2],'k--') 609 | 610 | plt.show() 611 | 612 | plt.figure() 613 | plt.plot(range(1, epochs + 1, 1), train_err, 'r-', label='Train Error') 614 | plt.plot(range(1, epochs + 1, 1), test_err, 'b-', label='Test Error') 615 | plt.legend() 616 | -------------------------------------------------------------------------------- /3DTaylor/NN3D.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.utils.data 3 | import torch.nn as nn 4 | import torch.optim as optim 5 | import torch.nn.functional as F 6 | 7 | import numpy as np 8 | import scipy.io 9 | import h5py 10 | 11 | import matplotlib.pyplot as plt 12 | import pickle 13 | 14 | 15 | class LpLoss(object): 16 | def __init__(self, d=2, p=2, size_average=True, reduction=True): 17 | super(LpLoss, self).__init__() 18 | 19 | # Dimension and Lp-norm type are postive 20 | assert d > 0 and p > 0 21 | 22 | self.d = d 23 | self.p = p 24 | self.reduction = reduction 25 | self.size_average = size_average 26 | 27 | def abs(self, x, y): 28 | num_examples = x.size()[0] 29 | 30 | # Assume uniform mesh 31 | h = 1.0 / (x.size()[1] - 1.0) 32 | 33 | all_norms = (h ** (self.d / self.p)) * torch.norm(x.view(num_examples, -1) - y.view(num_examples, -1), self.p, 34 | 1) 35 | 36 | if self.reduction: 37 | if self.size_average: 38 | return torch.mean(all_norms) 39 | else: 40 | return torch.sum(all_norms) 41 | 42 | return all_norms 43 | 44 | def rel(self, x, y): 45 | num_examples = x.size()[0] 46 | 47 | diff_norms = torch.norm(x.view(num_examples, -1) - y.view(num_examples, -1), self.p, 1) 48 | y_norms = torch.norm(y.view(num_examples, -1), self.p, 1) 49 | 50 | if self.reduction: 51 | if self.size_average: 52 | return torch.mean(diff_norms / y_norms) 53 | else: 54 | return torch.sum(diff_norms / y_norms) 55 | 56 | return diff_norms / y_norms 57 | 58 | def forward(self, x, y): 59 | return self.rel(x, y) 60 | 61 | def __call__(self, x, y): 62 | return self.forward(x, y) 63 | 64 | 65 | class PCA(object): 66 | def __init__(self, x, dim, subtract_mean=True): 67 | super(PCA, self).__init__() 68 | 69 | # Input size 70 | x_size = list(x.size()) 71 | 72 | # Input data is a matrix 73 | assert len(x_size) == 2 74 | 75 | # Reducing dimension is less than the minimum of the 76 | # number of observations and the feature dimension 77 | assert dim <= min(x_size) 78 | 79 | self.reduced_dim = dim 80 | 81 | if subtract_mean: 82 | self.x_mean = torch.mean(x, dim=0).view(1, -1) 83 | else: 84 | self.x_mean = torch.zeros((x_size[1],), dtype=x.dtype, layout=x.layout, device=x.device) 85 | 86 | # SVD 87 | U, S, V = torch.svd(x - self.x_mean) 88 | V = V.t() 89 | 90 | # Flip sign to ensure deterministic output 91 | max_abs_cols = torch.argmax(torch.abs(U), dim=0) 92 | signs = torch.sign(U[max_abs_cols, range(U.size()[1])]).view(-1, 1) 93 | V *= signs 94 | 95 | self.W = V.t()[:, 0:self.reduced_dim] 96 | self.sing_vals = S.view(-1, ) 97 | 98 | def cuda(self): 99 | self.W = self.W.cuda() 100 | self.x_mean = self.x_mean.cuda() 101 | self.sing_vals = self.sing_vals.cuda() 102 | 103 | def encode(self, x): 104 | return (x - self.x_mean).mm(self.W) 105 | 106 | def decode(self, x): 107 | return x.mm(self.W.t()) + self.x_mean 108 | 109 | def forward(self, x): 110 | return self.decode(self.encode(x)) 111 | 112 | def __call__(self, x): 113 | return self.forward(x) 114 | 115 | 116 | class LeastSquares(object): 117 | def __init__(self, x, y, bias=False, lam=0.0, cuda=True): 118 | super(LeastSquares, self).__init__() 119 | 120 | self.bias = bias 121 | self.cuda = cuda 122 | 123 | # Input sizes 124 | x_size = list(x.size()) 125 | y_size = list(y.size()) 126 | 127 | # Input data are matricies 128 | assert len(x_size) == 2 and len(y_size) == 2 129 | 130 | # Numer of observations match 131 | assert x_size[0] == y_size[0] 132 | 133 | x = x.cpu().numpy() 134 | y = y.cpu().numpy() 135 | 136 | if bias: 137 | x = np.append(x, np.ones((x_size[0], 1)), axis=1) 138 | 139 | if lam <= 0.0: 140 | self.W = torch.from_numpy(np.linalg.lstsq(x, y, rcond=None)[0]) 141 | else: 142 | myid = lam * np.identity(x.shape[1]) 143 | if bias: 144 | myid[x.shape[1] - 1, x.shape[1] - 1] = 0 145 | 146 | self.W = torch.from_numpy(np.linalg.solve(x.T.dot(x) + myid, x.T.dot(y))) 147 | 148 | self.W = self.W.type(torch.FloatTensor) 149 | if cuda: 150 | self.W = self.W.cuda() 151 | 152 | def forward(self, x): 153 | if self.bias: 154 | ones = torch.ones((x.size()[0], 1)).type(torch.FloatTensor) 155 | if self.cuda: 156 | ones = ones.cuda() 157 | 158 | return torch.cat((x, ones), dim=1).mm(self.W) 159 | 160 | return x.mm(self.W) 161 | 162 | def __call__(self, x): 163 | return self.forward(x) 164 | 165 | 166 | class DenseNet(nn.Module): 167 | def __init__(self, layers, nonlinearity): 168 | super(DenseNet, self).__init__() 169 | 170 | self.n_layers = len(layers) - 1 171 | 172 | assert self.n_layers >= 1 173 | 174 | self.layers = nn.ModuleList() 175 | 176 | for j in range(self.n_layers): 177 | self.layers.append(nn.Linear(layers[j], layers[j + 1])) 178 | 179 | if j != self.n_layers - 1: 180 | self.layers.append(nonlinearity()) 181 | 182 | def forward(self, x): 183 | for _, l in enumerate(self.layers): 184 | x = l(x) 185 | 186 | return x 187 | 188 | 189 | class UnitGaussianNormalizer(object): 190 | def __init__(self, x, zeroone_first=True): 191 | super(UnitGaussianNormalizer, self).__init__() 192 | 193 | self.zeroone_first = zeroone_first 194 | 195 | if self.zeroone_first: 196 | self.min = torch.min(x, 0)[0].view(-1, ) 197 | self.max = torch.max(x, 0)[0].view(-1, ) 198 | 199 | s = x.size() 200 | x = ((x.view(s[0], -1) - self.min) / (self.max - self.min)).view(s) 201 | 202 | self.mean = torch.mean(x, 0).view(-1, ) 203 | self.std = torch.std(x, 0).view(-1, ) 204 | 205 | def encode(self, x): 206 | s = x.size() 207 | 208 | x = x.view(s[0], -1) 209 | 210 | if self.zeroone_first: 211 | x = (x - self.min) / (self.max - self.min) 212 | 213 | x = (x - self.mean) / self.std 214 | 215 | x = x.view(s) 216 | 217 | return x 218 | 219 | def decode(self, x): 220 | s = x.size() 221 | 222 | x = x.view(s[0], -1) 223 | 224 | x = (x * self.std) + self.mean 225 | 226 | if self.zeroone_first: 227 | x = (x * (self.max - self.min)) + self.min 228 | 229 | x = x.view(s) 230 | 231 | return x 232 | 233 | 234 | class MatReader(object): 235 | def __init__(self, file_path, to_torch=True, to_cuda=False, to_float=True): 236 | super(MatReader, self).__init__() 237 | 238 | self.to_torch = to_torch 239 | self.to_cuda = to_cuda 240 | self.to_float = to_float 241 | 242 | self.file_path = file_path 243 | 244 | self.data = None 245 | self.old_mat = None 246 | self._load_file() 247 | 248 | def _load_file(self): 249 | try: 250 | self.data = scipy.io.loadmat(self.file_path) 251 | self.old_mat = True 252 | except: 253 | self.data = h5py.File(self.file_path) 254 | self.old_mat = False 255 | 256 | def load_file(self, file_path): 257 | self.file_path = file_path 258 | self._load_file() 259 | 260 | def read_field(self, field): 261 | x = self.data[field] 262 | 263 | if not self.old_mat: 264 | x = x[()] 265 | x = np.transpose(x, axes=range(len(x.shape) - 1, -1, -1)) 266 | 267 | if self.to_float: 268 | x = x.astype(np.float32) 269 | 270 | if self.to_torch: 271 | x = torch.from_numpy(x) 272 | 273 | if self.to_cuda: 274 | x = x.cuda() 275 | 276 | return x 277 | 278 | def set_cuda(self, to_cuda): 279 | self.to_cuda = to_cuda 280 | 281 | def set_torch(self, to_torch): 282 | self.to_torch = to_torch 283 | 284 | def set_float(self, to_float): 285 | self.to_float = to_float 286 | 287 | class PCA_3d(object): 288 | def __init__(self, x, dim): 289 | super(PCA_3d, self).__init__() 290 | 291 | # Input size 292 | x_size = list(x.size()) 293 | 294 | # Reducing dimension is less than the minimum of the 295 | # number of observations and the feature dimension 296 | #assert dim <= min(x_size) 297 | 298 | self.reduced_dim = dim 299 | 300 | # SVD for 3 inputs 301 | U1, S1, V1 = torch.svd(x[:, :, 0]) 302 | U2, S2, V2 = torch.svd(x[:, :, 1]) 303 | U3, S3, V3 = torch.svd(x[:, :, 2]) 304 | U4, S4, V4 = torch.svd(x[:, :, 3]) 305 | U5, S5, V5 = torch.svd(x[:, :, 4]) 306 | U6, S6, V6 = torch.svd(x[:, :, 5]) 307 | V1 = V1.t() 308 | V2 = V2.t() 309 | V3 = V3.t() 310 | V4 = V4.t() 311 | V5 = V5.t() 312 | V6 = V6.t() 313 | 314 | # Flip sign to ensure deterministic output 315 | max_abs_cols_1 = torch.argmax(torch.abs(U1), dim=0) 316 | max_abs_cols_2 = torch.argmax(torch.abs(U2), dim=0) 317 | max_abs_cols_3 = torch.argmax(torch.abs(U3), dim=0) 318 | max_abs_cols_4 = torch.argmax(torch.abs(U4), dim=0) 319 | max_abs_cols_5 = torch.argmax(torch.abs(U5), dim=0) 320 | max_abs_cols_6 = torch.argmax(torch.abs(U6), dim=0) 321 | 322 | signs_1 = torch.sign(U1[max_abs_cols_1, range(U1.size()[1])]).view(-1, 1) 323 | signs_2 = torch.sign(U2[max_abs_cols_2, range(U2.size()[1])]).view(-1, 1) 324 | signs_3 = torch.sign(U3[max_abs_cols_3, range(U3.size()[1])]).view(-1, 1) 325 | signs_4 = torch.sign(U4[max_abs_cols_4, range(U4.size()[1])]).view(-1, 1) 326 | signs_5 = torch.sign(U5[max_abs_cols_5, range(U5.size()[1])]).view(-1, 1) 327 | signs_6 = torch.sign(U6[max_abs_cols_6, range(U6.size()[1])]).view(-1, 1) 328 | 329 | V1 *= signs_1 330 | V2 *= signs_2 331 | V3 *= signs_3 332 | V4 *= signs_4 333 | V5 *= signs_5 334 | V6 *= signs_6 335 | 336 | self.W1 = V1.t()[:, 0:self.reduced_dim] 337 | self.W2 = V2.t()[:, 0:self.reduced_dim] 338 | self.W3 = V3.t()[:, 0:self.reduced_dim] 339 | 340 | self.W4 = V4.t()[:, 0:self.reduced_dim] 341 | self.W5 = V5.t()[:, 0:self.reduced_dim] 342 | self.W6 = V6.t()[:, 0:self.reduced_dim] 343 | 344 | 345 | def cuda(self): 346 | self.W1 = self.W1.cuda() 347 | self.W2 = self.W2.cuda() 348 | self.W3 = self.W3.cuda() 349 | self.W4 = self.W4.cuda() 350 | self.W5 = self.W5.cuda() 351 | self.W6 = self.W6.cuda() 352 | 353 | def encode(self, x): 354 | x1 = x[:,:,0].mm(self.W1) 355 | x2 = x[:,:,1].mm(self.W2) 356 | x3 = x[:,:,2].mm(self.W3) 357 | x4 = x[:,:,3].mm(self.W4) 358 | x5 = x[:,:,4].mm(self.W5) 359 | x6 = x[:,:,5].mm(self.W6) 360 | x = torch.cat((x1.unsqueeze(2),x2.unsqueeze(2),x3.unsqueeze(2),x4.unsqueeze(2),x5.unsqueeze(2),x6.unsqueeze(2)),2) 361 | return x 362 | 363 | def decode(self, x): 364 | x1 = x[:,:,0].mm(self.W1.t()) 365 | x2 = x[:,:,1].mm(self.W2.t()) 366 | x3 = x[:,:,2].mm(self.W3.t()) 367 | x4 = x[:,:,3].mm(self.W4.t()) 368 | x5 = x[:,:,4].mm(self.W5.t()) 369 | x6 = x[:,:,5].mm(self.W6.t()) 370 | x = torch.cat((x1.unsqueeze(2),x2.unsqueeze(2),x3.unsqueeze(2),x4.unsqueeze(2),x5.unsqueeze(2),x6.unsqueeze(2)),2) 371 | return x 372 | 373 | def forward(self, x): 374 | return self.decode(self.encode(x)) 375 | 376 | def __call__(self, x): 377 | return self.forward(x) 378 | 379 | class UnitGaussianNormalizer_3d(object): 380 | def __init__(self, x, zeroone_first=True): 381 | super(UnitGaussianNormalizer_3d, self).__init__() 382 | x1 = x[:,:,0] 383 | x2 = x[:,:,1] 384 | x3 = x[:,:,2] 385 | self.zeroone_first = zeroone_first 386 | 387 | if self.zeroone_first: 388 | self.min_x1 = torch.min(x1, 0)[0].view(-1, ) 389 | self.min_x2 = torch.min(x1, 0)[0].view(-1, ) 390 | self.min_x3 = torch.min(x3, 0)[0].view(-1, ) 391 | 392 | self.max_x1 = torch.max(x2, 0)[0].view(-1, ) 393 | self.max_x2 = torch.max(x2, 0)[0].view(-1, ) 394 | self.max_x3 = torch.max(x2, 0)[0].view(-1, ) 395 | 396 | s = x1.size() 397 | x1 = ((x1.view(s[0], -1) - self.min_x1) / (self.max_x1 - self.min_x1)).view(s) 398 | x2 = ((x2.view(s[0], -1) - self.min_x2) / (self.max_x2 - self.min_x2)).view(s) 399 | x3 = ((x3.view(s[0], -1) - self.min_x3) / (self.max_x3 - self.min_x3)).view(s) 400 | 401 | self.mean_x1 = torch.mean(x1, 0).view(-1, ) 402 | self.mean_x2 = torch.mean(x2, 0).view(-1, ) 403 | self.mean_x3 = torch.mean(x3, 0).view(-1, ) 404 | 405 | self.std_x1 = torch.std(x1, 0).view(-1, ) 406 | self.std_x2 = torch.std(x2, 0).view(-1, ) 407 | self.std_x3 = torch.std(x3, 0).view(-1, ) 408 | 409 | def encode(self, x): 410 | x1 = x[:,:,0] 411 | x2 = x[:,:,1] 412 | x3 = x[:,:,2] 413 | s = x1.size() 414 | 415 | x1 = x1.view(s[0], -1) 416 | x2 = x2.view(s[0], -1) 417 | x3 = x3.view(s[0], -1) 418 | 419 | if self.zeroone_first: 420 | x1 = (x1 - self.min_x1) / (self.max_x1 - self.min_x1) 421 | x2 = (x2 - self.min_x2) / (self.max_x2 - self.min_x2) 422 | x3 = (x3 - self.min_x3) / (self.max_x3 - self.min_x3) 423 | 424 | x1 = (x1 - self.mean_x1) / self.std_x1 425 | x2 = (x2 - self.mean_x2) / self.std_x2 426 | x3 = (x3 - self.mean_x3) / self.std_x3 427 | 428 | 429 | x1 = x1.view(s) 430 | x2 = x2.view(s) 431 | x3 = x3.view(s) 432 | x = torch.cat((x1.unsqueeze(2),x2.unsqueeze(2),x3.unsqueeze(2)),2) 433 | 434 | return x 435 | 436 | def decode(self, x): 437 | x1 = x[:,:,0] 438 | x2 = x[:,:,1] 439 | x3 = x[:,:,2] 440 | s = x1.size() 441 | 442 | x1 = x1.view(s[0], -1) 443 | x2 = x2.view(s[0], -1) 444 | x3 = x3.view(s[0], -1) 445 | 446 | x1 = (x1 * self.std_x1) + self.mean_x1 447 | x2 = (x2 * self.std_x2) + self.mean_x2 448 | x3 = (x3 * self.std_x3) + self.mean_x3 449 | 450 | if self.zeroone_first: 451 | x1 = (x1 * (self.max_x1 - self.min_x1)) + self.min_x1 452 | x2 = (x2 * (self.max_x2 - self.min_x2)) + self.min_x2 453 | x3 = (x3 * (self.max_x3 - self.min_x3)) + self.min_x3 454 | 455 | x1 = x1.view(s) 456 | x2 = x2.view(s) 457 | x3 = x3.view(s) 458 | x = torch.cat((x1.unsqueeze(2),x2.unsqueeze(2),x3.unsqueeze(2)),2) 459 | return x 460 | class DenseNet_tensor(nn.Module): 461 | def __init__(self, ten_layers, layers, nonlinearity): 462 | super(DenseNet_tensor, self).__init__() 463 | # =========== change 3d tensor to 1d scalar ================# 464 | self.n_ten = len(ten_layers)-1 465 | self.ten_layers = nn.ModuleList() 466 | for k in range(self.n_ten): 467 | self.ten_layers.append(nn.Linear(ten_layers[k], ten_layers[k+1])) 468 | self.ten_layers.append(nonlinearity()) 469 | 470 | self.n_layers = len(layers) - 1 471 | assert self.n_layers >= 1 472 | self.layers = nn.ModuleList() 473 | for j in range(self.n_layers): 474 | self.layers.append(nn.Linear(layers[j], layers[j + 1])) 475 | 476 | if j != self.n_layers - 1: 477 | self.layers.append(nonlinearity()) 478 | 479 | def forward(self, x): 480 | for _, m in enumerate(self.ten_layers): 481 | x = m(x) 482 | x = x.squeeze(2) 483 | for _, l in enumerate(self.layers): 484 | x = l(x) 485 | 486 | return x 487 | ########### TO CHANGE ###################################### 488 | USE_CUDA = True 489 | TRAIN_PATH = 'Taylor3D.mat' 490 | 491 | Ntotal = 18841 492 | train_size = 18000 493 | test_start = 18001 494 | 495 | N_test = Ntotal-test_start 496 | 497 | F11_FIELD = 'F11_field' 498 | F22_FIELD = 'F22_field' 499 | F12_FIELD = 'F12_field' 500 | F13_FIELD = 'F13_field' 501 | F23_FIELD = 'F23_field' 502 | F33_FIELD = 'F33_field' 503 | 504 | SIG_FIELD = 'sig11_field' 505 | 506 | SIG11_FIELD = 'sig11_field' 507 | SIG22_FIELD = 'sig22_field' 508 | SIG12_FIELD = 'sig12_field' 509 | SIG13_FIELD = 'sig13_field' 510 | SIG23_FIELD = 'sig23_field' 511 | SIG33_FIELD = 'sig33_field' 512 | 513 | 514 | 515 | grid_size =64 # Only for plotting 516 | 517 | loss_func = LpLoss() 518 | ######### Preprocessing data #################### 519 | temp = torch.zeros(Ntotal,1) 520 | 521 | data_loader = MatReader(TRAIN_PATH) 522 | data_F11 = data_loader.read_field(F11_FIELD).contiguous().view(Ntotal, -1) 523 | data_F22 = data_loader.read_field(F22_FIELD).contiguous().view(Ntotal, -1) 524 | data_F12 = data_loader.read_field(F12_FIELD).contiguous().view(Ntotal, -1) 525 | data_F13 = data_loader.read_field(F13_FIELD).contiguous().view(Ntotal, -1) 526 | data_F23 = data_loader.read_field(F23_FIELD).contiguous().view(Ntotal, -1) 527 | data_F33 = data_loader.read_field(F33_FIELD).contiguous().view(Ntotal, -1) 528 | 529 | data_F11 = torch.cat((temp+1,data_F11),1) 530 | data_F22 = torch.cat((temp+1,data_F22),1) 531 | data_F33 = torch.cat((temp+1,data_F33),1) 532 | data_F12 = torch.cat((temp,data_F12),1) 533 | data_F13 = torch.cat((temp,data_F13),1) 534 | data_F23 = torch.cat((temp,data_F23),1) 535 | 536 | #data_F11 = data_F11 - 1.0 537 | #data_F22 = data_F22 - 1.0 538 | #data_F33 = data_F33 - 1.0 539 | 540 | #data_F11 = data_F11[:,0::10] 541 | #data_F22 = data_F22[:,0::10] 542 | #data_F12 = data_F12[:,0::10] 543 | #data_F13 = data_F13[:,0::10] 544 | #data_F23 = data_F23[:,0::10] 545 | #data_F33 = data_F33[:,0::10] 546 | 547 | data_S11 = data_loader.read_field(SIG11_FIELD).contiguous().view(Ntotal, -1) 548 | data_S22 = data_loader.read_field(SIG22_FIELD).contiguous().view(Ntotal, -1) 549 | data_S12 = data_loader.read_field(SIG12_FIELD).contiguous().view(Ntotal, -1) 550 | data_S13 = data_loader.read_field(SIG13_FIELD).contiguous().view(Ntotal, -1) 551 | data_S23 = data_loader.read_field(SIG23_FIELD).contiguous().view(Ntotal, -1) 552 | data_S33 = data_loader.read_field(SIG33_FIELD).contiguous().view(Ntotal, -1) 553 | 554 | data_S11 = torch.cat((temp,data_S11),1) 555 | data_S22 = torch.cat((temp,data_S22),1) 556 | data_S13 = torch.cat((temp,data_S13),1) 557 | data_S12 = torch.cat((temp,data_S12),1) 558 | data_S23 = torch.cat((temp,data_S23),1) 559 | data_S33 = torch.cat((temp,data_S33),1) 560 | 561 | data_input = torch.cat((data_F11.unsqueeze(2),data_F22.unsqueeze(2),data_F33.unsqueeze(2),data_F12.unsqueeze(2),data_F23.unsqueeze(2),data_F13.unsqueeze(2)),2) 562 | 563 | data_output = torch.cat((data_S11.unsqueeze(2),data_S22.unsqueeze(2),data_S33.unsqueeze(2),data_S12.unsqueeze(2),data_S23.unsqueeze(2),data_S13.unsqueeze(2)),2) 564 | 565 | #============================ PCA on output and input data ====================================# 566 | x_train = data_input[0:train_size,:,:] 567 | y_train = data_output[0:train_size,:] 568 | 569 | x_test = data_input[test_start:Ntotal,:,:] 570 | y_test = data_output[test_start:Ntotal,:] 571 | # Reduced dimension of inputs 572 | d1 = 100 573 | # Reduced dimension of outputs 574 | d2 = 100 575 | 576 | NeuroArchi = [d1*6, 1000, 1000, 1000,1000, d2*6] 577 | #TensorArchi = [3,256,256,256,1] 578 | # Perform PCA on the CPU (can be a memory bottleneck for the GPU) 579 | 580 | x_pca = PCA_3d(x_train, d1) 581 | 582 | y_pca = PCA_3d(y_train, d2) 583 | 584 | #y_pca = PCA(y_train, d2, subtract_mean=False) 585 | 586 | # Move data and models to the GPU 587 | if USE_CUDA: 588 | x_train = x_train.cuda() 589 | x_test = x_test.cuda() 590 | y_train = y_train.cuda() 591 | y_test = y_test.cuda() 592 | 593 | x_pca.cuda() 594 | y_pca.cuda() 595 | 596 | x_train_enc = x_pca.encode(x_train) 597 | x_test_enc = x_pca.encode(x_test) 598 | 599 | y_train_enc = y_pca.encode(y_train) 600 | y_test_enc = y_pca.encode(y_test) 601 | 602 | 603 | net = DenseNet(NeuroArchi, nn.SELU) 604 | 605 | if USE_CUDA: 606 | net.cuda() 607 | 608 | # Number of training epochs 609 | epochs = 1500 610 | 611 | # Optimizer and learning rate scheduler 612 | optimizer = torch.optim.Adam(net.parameters(), lr=0.0001) 613 | scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, epochs, 1e-6) 614 | 615 | # Batch size 616 | b_size = 16 617 | 618 | # Wrap traning data in loader 619 | train_loader = torch.utils.data.DataLoader(torch.utils.data.TensorDataset(x_train_enc, y_train_enc), batch_size=b_size, 620 | shuffle=True) 621 | x_test_enc = x_test_enc.view(-1, d1*6) 622 | # Train neural net 623 | 624 | train_err = np.zeros((epochs,)) 625 | test_err = np.zeros((epochs,)) 626 | for ep in range(epochs): 627 | scheduler.step() 628 | train_loss = 0.0 629 | for x, y in train_loader: 630 | optimizer.zero_grad() 631 | x = x.view(-1, d1*6) 632 | #loss = F.mse_loss(net(x), y) 633 | y_train = y_pca.decode(net(x).view(-1,d2,6)) 634 | y_true = y_pca.decode(y) 635 | loss = loss_func(y_train,y_true) 636 | loss.backward() 637 | train_loss = train_loss + loss.item() 638 | 639 | optimizer.step() 640 | 641 | #test_err[ep] = F.mse_loss(net(x_test_enc), y_test_enc).item() 642 | y_test_approx = y_pca.decode(net(x_test_enc).view(-1,d2,6).detach()) 643 | test_err[ep] = loss_func(y_test_approx, y_test).item() 644 | #train_err[ep] = F.mse_loss(net(x_train_enc), y_train_enc).item() 645 | train_err[ep] = train_loss/len(train_loader) 646 | print(ep, train_err[ep], test_err[ep]) 647 | if train_err[ep] <= 0.01: 648 | break 649 | 650 | 651 | y_test_approx = y_pca.decode(net(x_test_enc).view(-1,d2,6).detach()) 652 | print('Relative approximation error (NN):\t', loss_func(y_test_approx, y_test).item()) 653 | 654 | torch.save(net,'Taylor3D') 655 | 656 | xpca_W1 = x_pca.W1.detach().cpu().numpy() 657 | xpca_W2 = x_pca.W2.detach().cpu().numpy() 658 | xpca_W3 = x_pca.W3.detach().cpu().numpy() 659 | xpca_W4 = x_pca.W4.detach().cpu().numpy() 660 | xpca_W5 = x_pca.W5.detach().cpu().numpy() 661 | xpca_W6 = x_pca.W6.detach().cpu().numpy() 662 | 663 | ypca_W1 = y_pca.W1.detach().cpu().numpy() 664 | ypca_W2 = y_pca.W2.detach().cpu().numpy() 665 | ypca_W3 = y_pca.W3.detach().cpu().numpy() 666 | ypca_W4 = y_pca.W4.detach().cpu().numpy() 667 | ypca_W5 = y_pca.W5.detach().cpu().numpy() 668 | ypca_W6 = y_pca.W6.detach().cpu().numpy() 669 | 670 | 671 | np.savetxt('xpca_Taylor_W1.txt', xpca_W1.transpose(), delimiter=' ') 672 | np.savetxt('xpca_Taylor_W2.txt', xpca_W2.transpose(), delimiter=' ') 673 | np.savetxt('xpca_Taylor_W3.txt', xpca_W3.transpose(), delimiter=' ') 674 | np.savetxt('xpca_Taylor_W4.txt', xpca_W4.transpose(), delimiter=' ') 675 | np.savetxt('xpca_Taylor_W5.txt', xpca_W5.transpose(), delimiter=' ') 676 | np.savetxt('xpca_Taylor_W6.txt', xpca_W6.transpose(), delimiter=' ') 677 | 678 | 679 | np.savetxt('ypca_Taylor_W1.txt', ypca_W1.transpose(), delimiter=' ') 680 | np.savetxt('ypca_Taylor_W2.txt', ypca_W2.transpose(), delimiter=' ') 681 | np.savetxt('ypca_Taylor_W3.txt', ypca_W3.transpose(), delimiter=' ') 682 | np.savetxt('ypca_Taylor_W4.txt', ypca_W4.transpose(), delimiter=' ') 683 | np.savetxt('ypca_Taylor_W5.txt', ypca_W5.transpose(), delimiter=' ') 684 | np.savetxt('ypca_Taylor_W6.txt', ypca_W6.transpose(), delimiter=' ') 685 | 686 | 687 | params = net.state_dict() 688 | layer_1_weight = params['layers.0.weight'].detach().cpu().numpy() 689 | layer_2_weight = params['layers.2.weight'].detach().cpu().numpy() 690 | layer_3_weight = params['layers.4.weight'].detach().cpu().numpy() 691 | layer_4_weight = params['layers.6.weight'].detach().cpu().numpy() 692 | layer_5_weight = params['layers.8.weight'].detach().cpu().numpy() 693 | 694 | np.savetxt('layer_1_Taylor_weight.txt', layer_1_weight.transpose(), delimiter=' ') 695 | np.savetxt('layer_2_Taylor_weight.txt', layer_2_weight.transpose(), delimiter=' ') 696 | np.savetxt('layer_3_Taylor_weight.txt', layer_3_weight.transpose(), delimiter=' ') 697 | np.savetxt('layer_4_Taylor_weight.txt', layer_4_weight.transpose(), delimiter=' ') 698 | np.savetxt('layer_5_Taylor_weight.txt', layer_5_weight.transpose(), delimiter=' ') 699 | 700 | layer_1_bias = params['layers.0.bias'].detach().cpu().numpy() 701 | layer_2_bias = params['layers.2.bias'].detach().cpu().numpy() 702 | layer_3_bias = params['layers.4.bias'].detach().cpu().numpy() 703 | layer_4_bias = params['layers.6.bias'].detach().cpu().numpy() 704 | layer_5_bias = params['layers.8.bias'].detach().cpu().numpy() 705 | 706 | np.savetxt('layer_1_Taylor_bias.txt', layer_1_bias.transpose(), delimiter=' ') 707 | np.savetxt('layer_2_Taylor_bias.txt', layer_2_bias.transpose(), delimiter=' ') 708 | np.savetxt('layer_3_Taylor_bias.txt', layer_3_bias.transpose(), delimiter=' ') 709 | np.savetxt('layer_4_Taylor_bias.txt', layer_4_bias.transpose(), delimiter=' ') 710 | np.savetxt('layer_5_Taylor_bias.txt', layer_5_bias.transpose(), delimiter=' ') 711 | 712 | -------------------------------------------------------------------------------- /3DTaylor/Taylor3D: -------------------------------------------------------------------------------- 1 | To download the data please use the following link: 2 | https://www.dropbox.com/scl/fi/nckzk9abaks0y41zaig5m/Taylor3Dcorrect.mat?rlkey=7949uad1y6bzg4goh9fxfhei9&dl=0 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Learning_based_multiscale 2 | 3 | Data and scripts for the paper: Learning-based multiscale method and its application toinelastic by Burigede Liu, Nikola Kovachki, Zongyi Li, Kamyar Azizzadenesheli, Anima Anandkumar, Andrew Stuart and Kaushik Bhattacharya. 4 | 5 | For further questions/discussions please contact BGL@caltech.edu 6 | -------------------------------------------------------------------------------- /VUMAT/Learnedmultiscale.for: -------------------------------------------------------------------------------- 1 | module class_strain 2 | implicit none 3 | save 4 | integer :: pipi 5 | real :: pipipi 6 | integer :: iter_control = 0 7 | real, dimension (201,100) :: xpca_W1 8 | real, dimension (201,100) :: xpca_W2 9 | real, dimension (201,100) :: xpca_W3 10 | real, dimension (201,100) :: xpca_W4 11 | real, dimension (201,100) :: xpca_W5 12 | real, dimension (201,100) :: xpca_W6 13 | 14 | real, dimension (201,100) :: ypca_W1 15 | real, dimension (201,100) :: ypca_W2 16 | real, dimension (201,100) :: ypca_W3 17 | real, dimension (201,100) :: ypca_W4 18 | real, dimension (201,100) :: ypca_W5 19 | real, dimension (201,100) :: ypca_W6 20 | 21 | type strain_path 22 | INTEGER :: num_step 23 | INTEGER :: nblock 24 | real(8), DIMENSION(:,:), allocatable :: e11_path ! NxM matrix N for each block m for total steps 25 | real(8), DIMENSION(:,:), allocatable :: e22_path 26 | real(8), DIMENSION(:,:), allocatable :: e12_path 27 | real(8), DIMENSION(:,:), allocatable :: e13_path 28 | real(8), DIMENSION(:,:), allocatable :: e23_path 29 | real(8), DIMENSION(:,:), allocatable :: e33_path 30 | 31 | 32 | end type strain_path 33 | 34 | 35 | type stress_path 36 | INTEGER :: num_step 37 | INTEGER :: nblock 38 | real(8), DIMENSION(:,:), allocatable :: sig11_path ! NxM matrix N for each block m for total steps 39 | real(8), DIMENSION(:,:), allocatable :: sig22_path 40 | real(8), DIMENSION(:,:), allocatable :: sig12_path 41 | real(8), DIMENSION(:,:), allocatable :: sig33_path 42 | real(8), DIMENSION(:,:), allocatable :: sig13_path 43 | real(8), DIMENSION(:,:), allocatable :: sig23_path 44 | 45 | end type stress_path 46 | 47 | type PCA_type 48 | integer :: yin_width 49 | integer :: xout_width 50 | real(8), DIMENSION(:,:), allocatable :: xPCA_W1 51 | real(8), DIMENSION(:,:), allocatable :: xPCA_W2 52 | real(8), DIMENSION(:,:), allocatable :: xPCA_W3 53 | 54 | real(8), DIMENSION(:,:), allocatable :: yPCA_W1 55 | real(8), DIMENSION(:,:), allocatable :: yPCA_W2 56 | real(8), DIMENSION(:,:), allocatable :: yPCA_W3 57 | real(8), DIMENSION(:,:), allocatable :: yPCA_W4 58 | end type PCA_type 59 | contains 60 | 61 | end module class_strain 62 | 63 | module class_layer 64 | implicit none 65 | save 66 | real, dimension (1000,600) :: weight1 67 | real, dimension (1000) :: bias1 68 | 69 | real, dimension (1000,1000) :: weight2 70 | real, dimension (1000) :: bias2 71 | 72 | real, dimension (1000,1000) :: weight3 73 | real, dimension (1000) :: bias3 74 | 75 | real, dimension (1000,1000) :: weight4 76 | real, dimension (1000) :: bias4 77 | 78 | real, dimension (600,1000) :: weight5 79 | real, dimension (600) :: bias5 80 | 81 | real(8) :: scale = 1.0507009873554804934193349852946 ! https://pytorch.org/docs/stable/nn.html selu! 82 | real(8) :: alpha = 1.6732632423543772848170429916717 83 | 84 | end module class_layer 85 | 86 | 87 | module class_net 88 | use class_strain 89 | use class_layer 90 | implicit none 91 | save 92 | contains 93 | 94 | SUBROUTINE forward(strain_,stress_) 95 | type(strain_path), intent(in) :: strain_ 96 | type(stress_path), intent(out) :: stress_ 97 | 98 | real(8) :: net_input_1(strain_%nblock,100) 99 | real(8) :: net_input_2(strain_%nblock,100) 100 | real(8) :: net_input_3(strain_%nblock,100) 101 | real(8) :: net_input_4(strain_%nblock,100) 102 | real(8) :: net_input_5(strain_%nblock,100) 103 | real(8) :: net_input_6(strain_%nblock,100) 104 | 105 | 106 | real(8) :: net_input(600) 107 | 108 | real(8) :: net_output_1(strain_%nblock,100) 109 | real(8) :: net_output_2(strain_%nblock,100) 110 | real(8) :: net_output_3(strain_%nblock,100) 111 | real(8) :: net_output_4(strain_%nblock,100) 112 | real(8) :: net_output_5(strain_%nblock,100) 113 | real(8) :: net_output_6(strain_%nblock,100) 114 | 115 | 116 | real(8) :: layer_1_out(1000) 117 | real(8) :: layer_2_out(1000) 118 | real(8) :: layer_3_out(1000) 119 | real(8) :: layer_4_out(1000) 120 | real(8) :: layer_5_out(600) 121 | 122 | real(8) :: net_output(600) 123 | integer :: d1,d2, i,j 124 | 125 | d1 = 600 126 | d2 = 600 127 | 128 | allocate(stress_%sig11_path(strain_%nblock,strain_%num_step)) 129 | allocate(stress_%sig22_path(strain_%nblock,strain_%num_step)) 130 | allocate(stress_%sig33_path(strain_%nblock,strain_%num_step)) 131 | allocate(stress_%sig12_path(strain_%nblock,strain_%num_step)) 132 | allocate(stress_%sig13_path(strain_%nblock,strain_%num_step)) 133 | allocate(stress_%sig23_path(strain_%nblock,strain_%num_step)) 134 | 135 | 136 | net_input_1 = MATMUL(strain_%e11_path,xPCA_W1) 137 | net_input_2 = MATMUL(strain_%e22_path,xPCA_W2) 138 | net_input_3 = MATMUL(strain_%e33_path,xPCA_W3) 139 | net_input_4 = MATMUL(strain_%e12_path,xPCA_W4) 140 | net_input_5 = MATMUL(strain_%e23_path,xPCA_W5) 141 | net_input_6 = MATMUL(strain_%e13_path,xPCA_W6) 142 | 143 | do i = 1,strain_%nblock 144 | !print *, "i", i 145 | net_input(1:d1:6)=reshape(net_input_1(i,:),(/100/)) 146 | net_input(2:d1:6)=reshape(net_input_2(i,:),(/100/)) 147 | net_input(3:d1:6)=reshape(net_input_3(i,:),(/100/)) 148 | net_input(4:d1:6)=reshape(net_input_4(i,:),(/100/)) 149 | net_input(5:d1:6)=reshape(net_input_5(i,:),(/100/)) 150 | net_input(6:d1:6)=reshape(net_input_6(i,:),(/100/)) 151 | 152 | layer_1_out = MATMUL(weight1, net_input) + bias1 153 | 154 | do j = 1, 1000 155 | layer_1_out(j) = scale * (max(0d0, layer_1_out(j))+min(0d0,alpha*(exp(layer_1_out(j))-1d0))) 156 | enddo 157 | 158 | layer_2_out = MATMUL(weight2, layer_1_out) + bias2 159 | 160 | do j = 1, 1000 161 | layer_2_out(j) = scale * (max(0d0, layer_2_out(j))+min(0d0,alpha*(exp(layer_2_out(j))-1d0))) 162 | enddo 163 | 164 | layer_3_out = MATMUL(weight3, layer_2_out) + bias3 165 | 166 | do j = 1, 1000 167 | layer_3_out(j) = scale * (max(0d0, layer_3_out(j))+min(0d0,alpha*(exp(layer_3_out(j))-1d0))) 168 | enddo 169 | 170 | layer_4_out = MATMUL(weight4, layer_3_out) + bias4 171 | 172 | do j = 1, 1000 173 | layer_4_out(j) = scale * (max(0d0, layer_4_out(j))+min(0d0,alpha*(exp(layer_4_out(j))-1d0))) 174 | enddo 175 | 176 | layer_5_out = MATMUL(weight5, layer_4_out) + bias5 177 | 178 | net_output = layer_5_out 179 | 180 | net_output_1(i,:) = net_output(1:d2:6) 181 | net_output_2(i,:) = net_output(2:d2:6) 182 | net_output_3(i,:) = net_output(3:d2:6) 183 | net_output_4(i,:) = net_output(4:d2:6) 184 | net_output_5(i,:) = net_output(5:d2:6) 185 | net_output_6(i,:) = net_output(6:d2:6) 186 | 187 | enddo 188 | stress_%sig11_path = MATMUL(net_output_1,transpose(yPCA_W1)) 189 | stress_%sig22_path = MATMUL(net_output_2,transpose(yPCA_W2)) 190 | stress_%sig33_path = MATMUL(net_output_3,transpose(yPCA_W3)) 191 | stress_%sig12_path = MATMUL(net_output_4,transpose(yPCA_W4)) 192 | stress_%sig23_path = MATMUL(net_output_5,transpose(yPCA_W5)) 193 | stress_%sig13_path = MATMUL(net_output_6,transpose(yPCA_W6)) 194 | 195 | end SUBROUTINE forward 196 | 197 | end module class_net 198 | 199 | subroutine vumat( 200 | C Read only (unmodifiable)variables - 201 | 1 nblock, ndir, nshr, nstatev, nfieldv, nprops, lanneal, 202 | 2 stepTime, totalTime, dt, cmname, coordMp, charLength, 203 | 3 props, density, strainInc, relSpinInc, 204 | 4 tempOld, stretchOld, defgradOld, fieldOld, 205 | 5 stressOld, stateOld, enerInternOld, enerInelasOld, 206 | 6 tempNew, stretchNew, defgradNew, fieldNew, 207 | C Write only (modifiable) variables - 208 | 7 stressNew, stateNew, enerInternNew, enerInelasNew ) 209 | C 210 | use class_strain 211 | use class_layer 212 | use class_net 213 | include 'vaba_param.inc' 214 | C 215 | dimension props(nprops), density(nblock), coordMp(nblock,*), 216 | 1 charLength(nblock), strainInc(nblock,ndir+nshr), 217 | 2 relSpinInc(nblock,nshr), tempOld(nblock), 218 | 3 stretchOld(nblock,ndir+nshr), 219 | 4 defgradOld(nblock,ndir+nshr+nshr), 220 | 5 fieldOld(nblock,nfieldv), stressOld(nblock,ndir+nshr), 221 | 6 stateOld(nblock,nstatev), enerInternOld(nblock), 222 | 7 enerInelasOld(nblock), tempNew(nblock), 223 | 8 stretchNew(nblock,ndir+nshr), 224 | 8 defgradNew(nblock,ndir+nshr+nshr), 225 | 9 fieldNew(nblock,nfieldv), 226 | 1 stressNew(nblock,ndir+nshr), stateNew(nblock,nstatev), 227 | 2 enerInternNew(nblock), enerInelasNew(nblock) 228 | C 229 | character*80 cmname 230 | C 231 | 232 | dimension ep3(3,3),dep3(3,3),et3(3,3),det3(3,3),xiden(3,3), 233 | * sig3(3,3), f(3,3), sigma_dev(3,3), e3(3,3), strain_elas(3,3) 234 | 235 | parameter(zero=0d0,one=1d0,half=0.5d0,two=2d0,three=3d0) 236 | INTEGER :: in_width, out_width, n_layers 237 | real(8), DIMENSION(2) :: input 238 | real(8), DIMENSION(2) :: output 239 | real(8), DIMENSION(2) :: bias 240 | real(8), DIMENSION(2,2) :: weights 241 | real(8), DIMENSION(nblock,6) :: F_new 242 | real(8), DIMENSION(nblock,6) :: F_old 243 | 244 | 245 | C==============================================================================C 246 | CCC==================== Initialize strain path ================================C 247 | INTEGER :: total_steps 248 | type(strain_path) :: strain_all 249 | type(stress_path) :: stress_all 250 | CCC==================== Initialize PCA ======================================CCC 251 | !type(PCA_type) :: PCA_all 252 | 253 | !type(layer) :: xlayer_1, xlayer_2, xlayer_3, xlayer_4, xlayer_5 254 | !type(net) :: test_net 255 | integer :: iter 256 | integer :: n_element=225,max_block=136 257 | integer :: block_k=1 258 | character(len=5) :: charI 259 | !save strain_all 260 | !save iter 261 | 262 | xiden(1,1)=one 263 | xiden(2,1)=zero 264 | xiden(3,1)=zero 265 | xiden(1,2)=zero 266 | xiden(2,2)=one 267 | xiden(3,2)=zero 268 | xiden(1,3)=zero 269 | xiden(2,3)=zero 270 | xiden(3,3)=one 271 | 272 | !print *, "iter", iter 273 | 274 | total_steps = 201 275 | 276 | 277 | strain_all%num_step = total_steps 278 | strain_all%nblock = nblock 279 | allocate(strain_all%e11_path(nblock,total_steps)) 280 | allocate(strain_all%e22_path(nblock,total_steps)) 281 | allocate(strain_all%e33_path(nblock,total_steps)) 282 | allocate(strain_all%e12_path(nblock,total_steps)) 283 | allocate(strain_all%e23_path(nblock,total_steps)) 284 | allocate(strain_all%e13_path(nblock,total_steps)) 285 | 286 | 287 | if (iter_control.eq.zero) then 288 | open (1, file = 'xpca_Taylor_W1.txt', status = 'old') 289 | read(1,*) xpca_W1 290 | close(1) 291 | 292 | open (2, file = 'xpca_Taylor_W2.txt', status = 'old') 293 | read(2,*) xPCA_W2 294 | close(2) 295 | 296 | open (3, file = 'xpca_Taylor_W3.txt', status = 'old') 297 | read(3,*) xPCA_W3 298 | close(3) 299 | 300 | open (4, file = 'xpca_Taylor_W4.txt', status = 'old') 301 | read(4,*) xPCA_W4 302 | close(4) 303 | 304 | open (5, file = 'xpca_Taylor_W5.txt', status = 'old') 305 | read(5,*) xPCA_W5 306 | close(5) 307 | 308 | open (6, file = 'xpca_Taylor_W6.txt', status = 'old') 309 | read(6,*) xPCA_W6 310 | close(6) 311 | 312 | open (7, file = 'ypca_Taylor_W1.txt', status = 'old') 313 | read(7,*) yPCA_W1 314 | close(7) 315 | 316 | open (8, file = 'ypca_Taylor_W2.txt', status = 'old') 317 | read(8,*) yPCA_W2 318 | close(8) 319 | 320 | open (9, file = 'ypca_Taylor_W3.txt', status = 'old') 321 | read(9,*) yPCA_W3 322 | close(9) 323 | 324 | open (10, file = 'ypca_Taylor_W4.txt', status = 'old') 325 | read(10,*) yPCA_W4 326 | close(10) 327 | 328 | open (10, file = 'ypca_Taylor_W5.txt', status = 'old') 329 | read(10,*) yPCA_W5 330 | close(10) 331 | 332 | open (10, file = 'ypca_Taylor_W6.txt', status = 'old') 333 | read(10,*) yPCA_W6 334 | close(10) 335 | 336 | open (1, file = 'layer_1_Taylor_weight.txt', status = 'old') 337 | read(1,*) weight1 338 | close(1) 339 | 340 | open (2, file = 'layer_1_Taylor_bias.txt', status = 'old') 341 | read(2,*) bias1 342 | close(2) 343 | 344 | open (1, file = 'layer_2_Taylor_weight.txt', status = 'old') 345 | read(1,*) weight2 346 | close(1) 347 | 348 | open (2, file = 'layer_2_Taylor_bias.txt', status = 'old') 349 | read(2,*) bias2 350 | close(2) 351 | 352 | open (1, file = 'layer_3_Taylor_weight.txt', status = 'old') 353 | read(1,*) weight3 354 | close(1) 355 | 356 | open (2, file = 'layer_3_Taylor_bias.txt', status = 'old') 357 | read(2,*) bias3 358 | close(2) 359 | 360 | 361 | open (1, file = 'layer_4_Taylor_weight.txt', status = 'old') 362 | read(1,*) weight4 363 | close(1) 364 | 365 | open (2, file = 'layer_4_Taylor_bias.txt', status = 'old') 366 | read(2,*) bias4 367 | close(2) 368 | 369 | open (1, file = 'layer_5_Taylor_weight.txt', status = 'old') 370 | read(1,*) weight5 371 | close(1) 372 | 373 | open (2, file = 'layer_5_Taylor_bias.txt', status = 'old') 374 | read(2,*) bias5 375 | close(2) 376 | 377 | !print *,"init here" 378 | !print *, iter 379 | iter_control = iter_control + 1 380 | endif 381 | 382 | !print *, "iter_control", iter_control 383 | do km = 1, nblock 384 | iter = stateOld(km,7) 385 | 386 | !print *, 'iter_start' , iter 387 | 388 | 389 | F_new(km,1) = stretchNew(km,1) 390 | F_new(km,2) = stretchNew(km,2) 391 | F_new(km,3) = stretchNew(km,3) 392 | F_new(km,4) = stretchNew(km,4) 393 | F_new(km,5) = stretchNew(km,5) 394 | F_new(km,6) = stretchNew(km,6) 395 | 396 | !print *, stretchNew(km,1) 397 | 398 | if (iter.eq.zero) then 399 | F_old(km,1) = 1.0 400 | F_old(km,2) = 1.0 401 | F_old(km,3) = 1.0 402 | F_old(km,4) = 0.0 403 | F_old(km,5) = 0.0 404 | F_old(km,6) = 0.0 405 | else 406 | F_old(km,1) = stateOld(km,1) 407 | F_old(km,2) = stateOld(km,2) 408 | F_old(km,3) = stateOld(km,3) 409 | F_old(km,4) = stateOld(km,4) 410 | F_old(km,5) = stateOld(km,5) 411 | F_old(km,6) = stateOld(km,6) 412 | endif 413 | 414 | do j = 1,total_steps 415 | if (iter.eq.zero) then 416 | strain_all%e11_path(km,j) = 1.0 417 | strain_all%e22_path(km,j) = 1.0 418 | strain_all%e33_path(km,j) = 1.0 419 | strain_all%e12_path(km,j) = 0.0 420 | strain_all%e23_path(km,j) = 0.0 421 | strain_all%e13_path(km,j) = 0.0 422 | else 423 | strain_all%e11_path(km,j) = stateOld(km,j+7) 424 | strain_all%e22_path(km,j) = stateOld(km,j+7+total_steps) 425 | strain_all%e33_path(km,j) = stateOld(km,j+7+2*total_steps) 426 | strain_all%e12_path(km,j) = stateOld(km,j+7+3*total_steps) 427 | strain_all%e23_path(km,j) = stateOld(km,j+7+4*total_steps) 428 | strain_all%e13_path(km,j) = stateOld(km,j+7+5*total_steps) 429 | endif 430 | enddo 431 | 432 | do j = iter+1, total_steps 433 | strain_all%e11_path(km,j) = F_old(km,1)+(F_new(km,1)-F_old(km,1))*(j-(iter+1)) 434 | strain_all%e22_path(km,j) = F_old(km,2)+(F_new(km,2)-F_old(km,2))*(j-(iter+1)) 435 | strain_all%e33_path(km,j) = F_old(km,3)+(F_new(km,3)-F_old(km,3))*(j-(iter+1)) 436 | strain_all%e12_path(km,j) = F_old(km,4)+(F_new(km,4)-F_old(km,4))*(j-(iter+1)) 437 | strain_all%e23_path(km,j) = F_old(km,5)+(F_new(km,5)-F_old(km,5))*(j-(iter+1)) 438 | strain_all%e13_path(km,j) = F_old(km,6)+(F_new(km,6)-F_old(km,6))*(j-(iter+1)) 439 | enddo 440 | 441 | do j = 1, total_steps 442 | stateNew(km,j+7) = strain_all%e11_path(km,j) 443 | stateNew(km,j+7+total_steps) = strain_all%e22_path(km,j) 444 | stateNew(km,j+7+2*total_steps) = strain_all%e33_path(km,j) 445 | stateNew(km,j+7+3*total_steps) = strain_all%e12_path(km,j) 446 | stateNew(km,j+7+4*total_steps) = strain_all%e23_path(km,j) 447 | stateNew(km,j+7+5*total_steps) = strain_all%e13_path(km,j) 448 | enddo 449 | 450 | iter = iter + 1 451 | !print *, "total_steps" 452 | !!print *, total_steps 453 | !print *, 'iter_end' , iter 454 | !print *, "e11" 455 | !print *, strain_all%e11_path 456 | stateNew(km,7) = iter 457 | 458 | f(1,1) = F_new(km,1) 459 | f(2,2) = F_new(km,2) 460 | f(3,3) = F_new(km,3) 461 | f(1,2) = F_new(km,4) 462 | f(2,3) = F_new(km,5) 463 | f(1,3) = F_new(km,6) 464 | f(2,1) = f(1,2) 465 | f(3,2) = f(2,3) 466 | f(3,1) = f(1,3) 467 | 468 | detF = f(1,1)*(f(2,2)*f(3,3)-f(2,3)*f(3,2)) 469 | detF = detF - f(1,2)*(f(2,1)*f(3,3)-f(2,3)*f(3,1)) 470 | detF = detF + f(1,3)*(f(2,1)*f(3,2)-f(2,2)*f(3,1)) 471 | 472 | do mm = 1,3 473 | do nn = 1,3 474 | f(mm,nn) = f(mm,nn)/detF 475 | enddo 476 | enddo 477 | 478 | strain_elas = MATMUL(transpose(f), f) 479 | strain_elas = half*(strain_elas - xiden) 480 | 481 | stateNew(km, 1214) = zero 482 | do m = 1,2 483 | do n = 1,2 484 | stateNew(km, 1214) = stateNew(km, 1214) + strain_elas(m,n)*strain_elas(m,n) 485 | enddo 486 | enddo 487 | stateNew(km,1214) = sqrt(stateNew(km,1214)) 488 | stateNew(km,1215) = detF - one 489 | enddo 490 | 491 | call forward(strain_all,stress_all) 492 | 493 | !open(2, file = 'C:\ABAQUS_WORK\stress11.txt') 494 | !do i=1,201 495 | !write(2,*) stress_all%sig11_path(1,i), stress_all%sig22_path(1,i), stress_all%sig12_path(1,i) 496 | !end do 497 | 498 | !print *, "Fnew", F_new(8,2); 499 | !print *, "Fold", F_old(8,2); 500 | !print *, "strain 11" 501 | !print *, strain_all%e11_path(8,:) 502 | !print *, "strain 22" 503 | !print *, strain_all%e22_path(8,:) 504 | !print *, "strain 12" 505 | !print *, strain_all%e12_path(8,:) 506 | 507 | c print *, "here" 508 | !print *, "e11path" 509 | !print *, strain_all%e11_path 510 | 511 | !print *, "e22path" 512 | !print *, strain_all%e22_path 513 | 514 | 515 | !print *, "e33path" 516 | !print *, strain_all%e33_path 517 | 518 | !print *, "e12path" 519 | !print *, strain_all%e12_path 520 | 521 | !print *, "e23path" 522 | !print *, strain_all%e23_path 523 | 524 | !print *, "e13path" 525 | !print *, strain_all%e12_path 526 | 527 | stressNew(:,1) = 1000.0*stress_all%sig11_path(:,iter+1) 528 | stressNew(:,2) = 1000.0*stress_all%sig22_path(:,iter+1) 529 | stressNew(:,3) = 1000.0*stress_all%sig33_path(:,iter+1) 530 | stressNew(:,4) = 1000.0*stress_all%sig12_path(:,iter+1) 531 | stressNew(:,5) = 1000.0*stress_all%sig23_path(:,iter+1) 532 | stressNew(:,6) = 1000.0*stress_all%sig13_path(:,iter+1) 533 | 534 | !print *, "stressNew" 535 | !print *, stressNew 536 | 537 | c print *, "stress 11" 538 | c print *, stressNew(:,1) 539 | 540 | c print *, "stress 22" 541 | c print *, stressNew(:,2) 542 | 543 | c print *, "stress 12" 544 | c print *, stressNew(:,4) 545 | 546 | 547 | c print *, "stress 33" 548 | c print *, stressNew(:,3) 549 | 550 | 551 | 552 | stateNew(:,1) = F_new(:,1) 553 | stateNew(:,2) = F_new(:,2) 554 | stateNew(:,3) = F_new(:,3) 555 | stateNew(:,4) = F_new(:,4) 556 | stateNew(:,5) = F_new(:,5) 557 | stateNew(:,6) = F_new(:,6) 558 | c print *, "=========" 559 | c print *, "iteration" 560 | c print *, iter 561 | 562 | return 563 | end 564 | 565 | 566 | --------------------------------------------------------------------------------