Download model/MWT.py from OneScience-Group/CFD_Benchmark: direct link, hf CLI and curl.
- Browser
- Download file 7.45 kB
-
https://huggingface.co/OneScience-Group/CFD_Benchmark/resolve/main/model/MWT.py
- Command line
-
hf download hf://OneScience-Group/CFD_Benchmark/model/MWT.py
-
curl -L -o MWT.py https://huggingface.co/OneScience-Group/CFD_Benchmark/resolve/main/model/MWT.py
7.45 kB
| import torch | |
| import math | |
| import torch.nn as nn | |
| import numpy as np | |
| import torch.nn.functional as F | |
| from timm.layers import trunc_normal_ | |
| from onescience.modules.fourier.MultiWaveletTransform import ( | |
| MultiWaveletTransform1D, | |
| MultiWaveletTransform2D, | |
| MultiWaveletTransform3D, | |
| ) | |
| from onescience.modules.mlp.MLP import StandardMLP | |
| from onescience.modules.embedding import timestep_embedding, unified_pos_embedding | |
| from onescience.modules.fourier.geo_spectral import GeoSpectralConv2d, IPHI | |
| MultiWaveletTransformList = [ | |
| None, | |
| MultiWaveletTransform1D, | |
| MultiWaveletTransform2D, | |
| MultiWaveletTransform3D, | |
| ] | |
| class Model(nn.Module): | |
| # this model requires H = W = Z and H, W, Z is the power of two | |
| def __init__( | |
| self, args, device, alpha=2, L=0, c=1, base="legendre", s1=128, s2=128 | |
| ): | |
| super(Model, self).__init__() | |
| self.__name__ = "MWT" | |
| self.args = args | |
| self.k = args.mwt_k | |
| self.WMT_dim = c * self.k**2 | |
| if args.geotype == "structured_1D": | |
| self.WMT_dim = c * self.k | |
| self.c = c | |
| self.s1 = s1 | |
| self.s2 = s2 | |
| ## embedding | |
| if ( | |
| args.unified_pos and args.geotype != "unstructured" | |
| ): # only for structured mesh | |
| self.pos = unified_pos_embedding(args.shapelist, args.ref, device=device) | |
| self.preprocess = StandardMLP( | |
| input_dim=args.fun_dim + args.ref ** len(args.shapelist), | |
| output_dim=self.WMT_dim, | |
| hidden_dims=[args.n_hidden * 2], | |
| activation=args.act, | |
| use_bias=True | |
| ) | |
| else: | |
| self.preprocess = StandardMLP( | |
| input_dim=args.fun_dim + args.space_dim, | |
| output_dim=self.WMT_dim, | |
| hidden_dims=[args.n_hidden * 2], | |
| activation=args.act, | |
| use_bias=True | |
| ) | |
| if args.time_input: | |
| self.time_fc = nn.Sequential( | |
| nn.Linear(self.WMT_dim, args.n_hidden), | |
| nn.SiLU(), | |
| nn.Linear(args.n_hidden, self.WMT_dim), | |
| ) | |
| # geometry projection | |
| if self.args.geotype == "unstructured": | |
| self.fftproject_in = GeoSpectralConv2d( | |
| in_channels=self.WMT_dim, | |
| out_channels=self.WMT_dim, | |
| modes1=args.modes, | |
| modes2=args.modes, | |
| s1=s1, | |
| s2=s2 | |
| ) | |
| self.fftproject_out = GeoSpectralConv2d( | |
| in_channels=self.WMT_dim, | |
| out_channels=self.WMT_dim, | |
| modes1=args.modes, | |
| modes2=args.modes, | |
| s1=s1, | |
| s2=s2 | |
| ) | |
| self.iphi = IPHI() | |
| self.augmented_resolution = [s1, s2] | |
| self.padding = [(16 - size % 16) % 16 for size in [s1, s2]] | |
| else: | |
| target = 2 ** (math.ceil(np.log2(max(args.shapelist)))) | |
| self.padding = [(target - size) for size in args.shapelist] | |
| self.augmented_resolution = [target for _ in range(len(self.padding))] | |
| dim = len(self.padding) | |
| transform_class = MultiWaveletTransformList[dim] | |
| self.spectral_layers = nn.ModuleList( | |
| [ | |
| transform_class( | |
| k=self.k, | |
| alpha=alpha, | |
| L=L, | |
| c=c, | |
| base=base | |
| ) | |
| for _ in range(args.n_layers) | |
| ] | |
| ) | |
| # projectors | |
| self.fc1 = nn.Linear(self.WMT_dim, args.n_hidden) | |
| self.fc2 = nn.Linear(args.n_hidden, args.out_dim) | |
| def structured_geo(self, x, fx, T=None): | |
| B, N, _ = x.shape | |
| if self.args.unified_pos: | |
| x = self.pos.repeat(x.shape[0], 1, 1) | |
| if fx is not None: | |
| fx = torch.cat((x, fx), -1) | |
| fx = self.preprocess(fx) | |
| else: | |
| fx = self.preprocess(x) | |
| if T is not None: | |
| Time_emb = timestep_embedding(T, self.WMT_dim) | |
| Time_emb = self.time_fc(Time_emb) | |
| if Time_emb.ndim == 2: | |
| Time_emb = Time_emb.unsqueeze(1) | |
| fx = fx + Time_emb | |
| x = fx.permute(0, 2, 1).reshape(B, self.WMT_dim, *self.args.shapelist) | |
| if not all(item == 0 for item in self.padding): | |
| if len(self.args.shapelist) == 2: | |
| x = F.pad(x, [0, self.padding[1], 0, self.padding[0]]) | |
| elif len(self.args.shapelist) == 3: | |
| x = F.pad( | |
| x, [0, self.padding[2], 0, self.padding[1], 0, self.padding[0]] | |
| ) | |
| x = ( | |
| x.reshape(B, self.WMT_dim, -1) | |
| .permute(0, 2, 1) | |
| .contiguous() | |
| .reshape( | |
| B, | |
| *self.augmented_resolution, | |
| self.c, | |
| self.k**2 if self.args.geotype != "structured_1D" else self.k | |
| ) | |
| ) | |
| for i in range(self.args.n_layers): | |
| x = self.spectral_layers[i](x) | |
| if i < self.args.n_layers - 1: | |
| x = F.gelu(x) | |
| x = ( | |
| x.reshape(B, -1, self.WMT_dim) | |
| .permute(0, 2, 1) | |
| .contiguous() | |
| .reshape(B, self.WMT_dim, *self.augmented_resolution) | |
| ) | |
| if not all(item == 0 for item in self.padding): | |
| if len(self.args.shapelist) == 2: | |
| x = x[..., : -self.padding[0], : -self.padding[1]] | |
| elif len(self.args.shapelist) == 3: | |
| x = x[..., : -self.padding[0], : -self.padding[1], : -self.padding[2]] | |
| x = x.reshape(B, self.WMT_dim, -1).permute(0, 2, 1) | |
| x = self.fc1(x) | |
| x = F.gelu(x) | |
| x = self.fc2(x) | |
| return x | |
| def unstructured_geo(self, x, fx, T=None): | |
| B, N, _ = x.shape | |
| original_pos = x | |
| if fx is not None: | |
| fx = torch.cat((x, fx), -1) | |
| fx = self.preprocess(fx) | |
| else: | |
| fx = self.preprocess(x) | |
| if T is not None: | |
| Time_emb = timestep_embedding(T, self.WMT_dim) | |
| Time_emb = self.time_fc(Time_emb) | |
| if Time_emb.ndim == 2: | |
| Time_emb = Time_emb.unsqueeze(1) | |
| fx = fx + Time_emb | |
| x = self.fftproject_in( | |
| fx.permute(0, 2, 1), x_in=original_pos, iphi=self.iphi, code=None | |
| ) | |
| x = ( | |
| x.reshape(B, self.WMT_dim, -1) | |
| .permute(0, 2, 1) | |
| .contiguous() | |
| .reshape(B, *self.augmented_resolution, self.c, self.k**2) | |
| ) | |
| for i in range(self.args.n_layers): | |
| x = self.spectral_layers[i](x) | |
| if i < self.args.n_layers - 1: | |
| x = F.gelu(x) | |
| x = ( | |
| x.reshape(B, -1, self.WMT_dim) | |
| .permute(0, 2, 1) | |
| .contiguous() | |
| .reshape(B, self.WMT_dim, *self.augmented_resolution) | |
| ) | |
| x = self.fftproject_out( | |
| x, x_out=original_pos, iphi=self.iphi, code=None | |
| ).permute(0, 2, 1) | |
| x = self.fc1(x) | |
| x = F.gelu(x) | |
| x = self.fc2(x) | |
| return x | |
| def forward(self, x, fx, T=None, geo=None): | |
| if self.args.geotype == "unstructured": | |
| return self.unstructured_geo(x, fx, T) | |
| else: | |
| return self.structured_geo(x, fx, T) | |