diff --git a/PARCtorch/PARCv2.py b/PARCtorch/PARCv2.py index 4955dab..cafd667 100644 --- a/PARCtorch/PARCv2.py +++ b/PARCtorch/PARCv2.py @@ -1,6 +1,6 @@ import torch -from PARCtorch.utilities.unet import UNet +from PARCtorch.models.unet import UNet from PARCtorch.differentiator.finitedifference import FiniteDifference from differentiator.differentiator import ADRDifferentiator from integrator.rk4 import RK4 diff --git a/PARCtorch/data/dataset.py b/PARCtorch/data/dataset.py index f3dfcb8..968f2f4 100644 --- a/PARCtorch/data/dataset.py +++ b/PARCtorch/data/dataset.py @@ -7,7 +7,7 @@ from tqdm import tqdm from the_well.data import WellDataset -# TODO: Wipe out this entire file. Instead, implement the following classes: +# TODO: Wipe out this entire file. Instead, implement the following classes under PARCtorch/datasets/dataset.py: # class Dataset(torch.utils.data.Dataset): # class RegularMeshDataset(Dataset): # class IrregularMeshDataset(Dataset): diff --git a/PARCtorch/utilities/__init__.py b/PARCtorch/datasets/__init__.py similarity index 100% rename from PARCtorch/utilities/__init__.py rename to PARCtorch/datasets/__init__.py diff --git a/PARCtorch/demos/README.md b/PARCtorch/datasets/dataset.py similarity index 100% rename from PARCtorch/demos/README.md rename to PARCtorch/datasets/dataset.py diff --git a/PARCtorch/datasets/navier_stokes.py b/PARCtorch/datasets/navier_stokes.py new file mode 100644 index 0000000..5257845 --- /dev/null +++ b/PARCtorch/datasets/navier_stokes.py @@ -0,0 +1,50 @@ +from PARCtorch.data.dataset import GenericPhysicsDataset +from PARCtorch.utils.common import CACHE_DIR + +from PARCtorch.datasets.utils import download, extract_zip + +import os + + +class NavierStokes(GenericPhysicsDataset): + + """ + Navier-Stokes data set. TODO: More details + + Args: + split: Expected data split. Can be `train`, `test` TODO + data_dir: Directory to read/write data. Defaults to None, in which case, + data will be stored in `CACHE_DIR/datasets/NavierStokes`. + If the data does not exist in the specified directory, + it will be automatically downloaded. + future_steps: Number of timesteps in the future the model will predict. + Must be between 1 (single step prediction) and TODO (default). + """ + + url = "https://zenodo.org/records/13909869/files/NavierStokes.zip?download=1" + + def __init__( + self, split=None, data_dir=None, future_steps=2, + ): + super().__init__() + + # Set up data directory + if data_dir is None: + data_dir = os.path.join(CACHE_DIR, 'datasets', 'NavierStokes') + self.data_dir = data_dir + self.zip_dir = os.path.join(self.data_dir, 'NavierStokes.zip') + + if not os.path.exists(self.data_dir): + os.makedirs(self.data_dir) + + # Download and unzip data if it doesn't exist already. + self.download(force=False) + + from pathlib import Path + filelist = Path(self.data_dir).glob('*.*') + + + def download(self, force=False): + if not os.path.exists(self.zip_dir): + download(self.url, self.zip_dir) + extract_zip(self.zip_dir, self.data_dir) diff --git a/PARCtorch/datasets/utils.py b/PARCtorch/datasets/utils.py new file mode 100644 index 0000000..98bf4fc --- /dev/null +++ b/PARCtorch/datasets/utils.py @@ -0,0 +1,46 @@ +import os +import requests +import zipfile +from io import BytesIO +from tqdm import tqdm +from pathlib import Path + + +def download(url, target_path, chunk_size=1024): + """ + Downloads a file from the specified URL and saves it to the target_path. + """ + print(f"Downloading a file from {url}") + if os.path.exists(target_path): + print(f"Found a cached data in {target_path}. Aborting the download.") + print( + "If you want to re-download the data, please remove the cached data and try again." + ) + return target_path + + response = requests.get(url, stream=True) + response.raise_for_status() + + total_size = int(response.headers.get("content-length", 0)) + progress = tqdm(total=total_size, unit="B", unit_scale=True, desc=f"Downloading to {target_path}") + + with open(target_path, "wb") as f: + for chunk in response.iter_content(chunk_size=chunk_size): + if chunk: # filter out keep-alive chunks + f.write(chunk) + progress.update(len(chunk)) + progress.close() + + print(f"Download complete. File saved to {target_path}") + return target_path + + +def extract_zip(zip_path, target_folder): + """ + Extracts the contents of a ZIP file at zip_path into the target folder. + """ + Path(target_folder).mkdir(parents=True, exist_ok=True) + print(f"Extracting contents to {target_folder} ...") + with zipfile.ZipFile(zip_path, "r") as zip_ref: + zip_ref.extractall(target_folder) + print("Extraction complete.") diff --git a/PARCtorch/differentiator/mappingandrecon.py b/PARCtorch/differentiator/mappingandrecon.py index 37ff900..f13f57a 100644 --- a/PARCtorch/differentiator/mappingandrecon.py +++ b/PARCtorch/differentiator/mappingandrecon.py @@ -3,8 +3,8 @@ import torch.nn as nn # Import custom utilities -from PARCtorch.utilities.spade import SPADEGeneratorUnit -from PARCtorch.utilities.resnet import ResNet +from PARCtorch.models.spade import SPADEGeneratorUnit +from PARCtorch.models.resnet import ResNet class MappingAndRecon(nn.Module): diff --git a/PARCtorch/integrator/datadrivenintegrator.py b/PARCtorch/integrator/datadrivenintegrator.py index 02fdbe9..b956ee0 100644 --- a/PARCtorch/integrator/datadrivenintegrator.py +++ b/PARCtorch/integrator/datadrivenintegrator.py @@ -1,7 +1,7 @@ import torch.nn as nn import torch.nn.functional as F -from PARCtorch.utilities.spade import SPADEGeneratorUnit -from PARCtorch.utilities.resnet import ResNet +from PARCtorch.models.spade import SPADEGeneratorUnit +from PARCtorch.models.resnet import ResNet class DataDrivenIntegrator(nn.Module): diff --git a/PARCtorch/integrator/poisson.py b/PARCtorch/integrator/poisson.py index d613242..1eb1519 100644 --- a/PARCtorch/integrator/poisson.py +++ b/PARCtorch/integrator/poisson.py @@ -3,7 +3,7 @@ import torch import torch.nn as nn import torch.nn.functional as F -from PARCtorch.utilities.resnet import ResNet +from PARCtorch.models.resnet import ResNet class Poisson(nn.Module): diff --git a/PARCtorch/misc/README.md b/PARCtorch/models/README.md similarity index 100% rename from PARCtorch/misc/README.md rename to PARCtorch/models/README.md diff --git a/PARCtorch/utilities/README.md b/PARCtorch/models/__init__.py similarity index 100% rename from PARCtorch/utilities/README.md rename to PARCtorch/models/__init__.py diff --git a/PARCtorch/utilities/resnet.py b/PARCtorch/models/resnet.py similarity index 100% rename from PARCtorch/utilities/resnet.py rename to PARCtorch/models/resnet.py diff --git a/PARCtorch/utilities/spade.py b/PARCtorch/models/spade.py similarity index 100% rename from PARCtorch/utilities/spade.py rename to PARCtorch/models/spade.py diff --git a/PARCtorch/utilities/unet.py b/PARCtorch/models/unet.py similarity index 100% rename from PARCtorch/utilities/unet.py rename to PARCtorch/models/unet.py diff --git a/PARCtorch/scripts/ns_slurm.py b/PARCtorch/scripts/ns_slurm.py index 99e4a5e..b5374cc 100644 --- a/PARCtorch/scripts/ns_slurm.py +++ b/PARCtorch/scripts/ns_slurm.py @@ -39,13 +39,13 @@ # --------------------------- from data.normalization import compute_min_max from data.dataset import GenericPhysicsDataset, custom_collate_fn -from utilities.viz import visualize_channels +from PARCtorch.utils.viz import visualize_channels from PARCtorch.PARCv2 import PARCv2 from PARCtorch.differentiator.differentiator import Differentiator from PARCtorch.differentiator.finitedifference import FiniteDifference from PARCtorch.integrator.integrator import Integrator from PARCtorch.integrator.heun import Heun -from PARCtorch.utilities.unet import UNet +from PARCtorch.models.unet import UNet # --------------------------- diff --git a/PARCtorch/utils/__init__.py b/PARCtorch/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/PARCtorch/utils/common.py b/PARCtorch/utils/common.py new file mode 100644 index 0000000..d801c3b --- /dev/null +++ b/PARCtorch/utils/common.py @@ -0,0 +1,4 @@ +from pathlib import Path + + +CACHE_DIR = Path.home() / ".parc" \ No newline at end of file diff --git a/PARCtorch/utilities/load.py b/PARCtorch/utils/load.py similarity index 100% rename from PARCtorch/utilities/load.py rename to PARCtorch/utils/load.py diff --git a/PARCtorch/utilities/viz.py b/PARCtorch/utils/viz.py similarity index 100% rename from PARCtorch/utilities/viz.py rename to PARCtorch/utils/viz.py diff --git a/PARCtorch/demos/Burgers.ipynb b/examples/Burgers.ipynb similarity index 100% rename from PARCtorch/demos/Burgers.ipynb rename to examples/Burgers.ipynb diff --git a/PARCtorch/demos/EnergeticMaterials.ipynb b/examples/EnergeticMaterials.ipynb similarity index 100% rename from PARCtorch/demos/EnergeticMaterials.ipynb rename to examples/EnergeticMaterials.ipynb diff --git a/PARCtorch/demos/NavierStokes.ipynb b/examples/NavierStokes.ipynb similarity index 50% rename from PARCtorch/demos/NavierStokes.ipynb rename to examples/NavierStokes.ipynb index f78dac9..0a823d5 100644 --- a/PARCtorch/demos/NavierStokes.ipynb +++ b/examples/NavierStokes.ipynb @@ -7,9 +7,9 @@ "
\n", "

Physics Aware Recurrent Convolutional Neural Network (PARC): Navier-Stokes Demo

\n", "
\n", - " \"Image\n", - " \"Image\n", - " \"Image\n", + " \"Image\n", + " \"Image\n", + " \"Image\n", "
\n", "
\n", "

A customizable framework to embed physics in Deep Learning. PARC's formulation is inspired by Advection-Diffusion-Reaction processes and uses an Inductive Bias approach to constrain the Neural Network.

\n", @@ -61,6 +61,393 @@ "Happy Modeling!" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Download & Prepare Data\n", + "PARCtorch comes with a built-in dataset containing Navier-Stokes simulations. The following script will allow you to access the dataset." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "tensor(300)\n", + "tensor([ True, False, True, True, True, True, False, True])\n", + "tensor([False, False, False, False, True, True, False, True])\n", + "0\n", + "Variable time-independent scalar\n", + "0\n", + "Variable time-dependent scalar field\n", + "torch.Size([8, 39, 128, 256])\n" + ] + }, + { + "data": { + "text/plain": [ + "tensor([ -64.7932, 1491.8637, -35.3208, 4.4460, 53.8535, 123.9229,\n", + " 2062.4870, 269.5076], dtype=torch.float64)" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import torch\n", + "from PARCtorch.utils.common import CACHE_DIR\n", + "\n", + "from PARCtorch.datasets.utils import download, extract_zip\n", + "\n", + "import os\n", + "from pathlib import Path\n", + "import numpy as np\n", + "\n", + "class Data:\n", + " def __init__(self, data=None, traj_varying=False, time_varying=False, space_varying=False):\n", + " self.traj_varying = traj_varying\n", + " self.time_varying = time_varying\n", + " self.space_varying = space_varying\n", + " self.data = torch.as_tensor(data)\n", + " # TODO: assert(len(data.shape) >= traj_varying + time_varying + space_varying)\n", + "\n", + " @classmethod\n", + " def __torch_function__(self, func, types, args=(), kwargs=None):\n", + " # Forward any torch function to self.data\n", + " if kwargs is None:\n", + " kwargs = {}\n", + " args = tuple(a.data if isinstance(a, Data) else a for a in args)\n", + " return func(*args, **kwargs)\n", + " \n", + "\n", + " def __getitem__(self, index):\n", + " return self.data[index]\n", + " \n", + " def __eq__(self, other):\n", + " return self.data == other\n", + " \n", + " def __ne__(self, other):\n", + " return self.data != other\n", + " \n", + " def __lt__(self, other):\n", + " return self.data < other\n", + " \n", + " def __le__(self, other):\n", + " return self.data <= other\n", + " \n", + " def __gt__(self, other):\n", + " return self.data > other\n", + " \n", + " def __ge__(self, other):\n", + " return self.data >= other\n", + " \n", + " def __len__(self):\n", + " if self.data is None:\n", + " return 0\n", + " return len(self.data)\n", + " \n", + " def __repr__(self):\n", + " return f\"\"\n", + " \n", + " @property\n", + " def shape(self):\n", + " return self.data.shape\n", + " \n", + "\n", + " @property\n", + " def rank(self):\n", + " if self.data is None:\n", + " return -1\n", + " \n", + " rank = len(self.data.shape) - self.traj_varying - self.time_varying\n", + " if isinstance(self.space_varying, list):\n", + " rank -= sum(self.space_varying)\n", + " else:\n", + " rank -= self.space_varying\n", + "\n", + " return rank\n", + "\n", + " \n", + " @property\n", + " def type(self):\n", + " type_str = ''\n", + " if self.traj_varying:\n", + " type_str = 'Variable'\n", + " else:\n", + " type_str = 'Constant'\n", + " \n", + " if self.time_varying:\n", + " type_str += ' time-dependent'\n", + " else:\n", + " type_str += ' time-independent'\n", + " \n", + " rank = self.rank\n", + " if rank == 0:\n", + " type_str += ' scalar'\n", + " elif rank == 1:\n", + " type_str += ' vector'\n", + " else:\n", + " type_str += f' rank-{rank} tensor'\n", + "\n", + " if any(self.space_varying):\n", + " type_str += ' field'\n", + "\n", + " return type_str\n", + " \n", + "\n", + "\n", + "class Dataset(torch.utils.data.Dataset):\n", + " '''\n", + " Data is \n", + " '''\n", + " url = \"https://zenodo.org/records/13909869/files/NavierStokes.zip?download=1\"\n", + " def __init__(\n", + " self,\n", + " ):\n", + "\n", + " super().__init__()\n", + "\n", + " \n", + " # TODO: https://github.com/baeklab/PARCtorch/blob/main/tests/conftest.py\n", + " self.dataset_name = '' # dataset name\n", + " self.grid_type = 'cartesian' # type of grid. Can only be 'cartesian' at the moment. TODO: 'mesh'\n", + " self.n_spatial_dims = 1 # spatial dimensions\n", + " self.dimensions = {}\n", + " self.boundary_conditions = {}\n", + " self.constants = {} # physics parameters that are constant across all samples\n", + " self.data = {} # \n", + "\n", + " self.filelist = {}\n", + " \n", + "\n", + " # Set up data directory\n", + " data_dir = None\n", + " if data_dir is None:\n", + " data_dir = os.path.join(CACHE_DIR, 'datasets', 'NavierStokes')\n", + " self.data_dir = data_dir\n", + " self.zip_dir = os.path.join(self.data_dir, 'NavierStokes.zip')\n", + "\n", + " if not os.path.exists(self.data_dir):\n", + " os.makedirs(self.data_dir)\n", + "\n", + " # Download and unzip data if it doesn't exist already.\n", + " self.download(force=False)\n", + "\n", + " # Read data\n", + " self.load()\n", + "\n", + " \n", + " # TODO: Lazy loading (Future; low priority)\n", + " pass\n", + "\n", + " # number of trajectories or simulation instances\n", + " @property\n", + " def n_trajectories(self):\n", + " return len(self.filelist)\n", + " \n", + " def __len__(self):\n", + " return self.n_trajectories\n", + " \n", + " def download(self, force=False):\n", + " if not os.path.exists(self.zip_dir):\n", + " download(self.url, self.zip_dir)\n", + " extract_zip(self.zip_dir, self.data_dir)\n", + "\n", + " def load(self, data_dir=None):\n", + " if data_dir is None:\n", + " data_dir = self.data_dir\n", + "\n", + " filelist = Path(data_dir).glob('test/*.npy')\n", + " \n", + " \n", + " self.dataset_name = 'Navier Stokes'\n", + " self.grid_type = 'cartesian'\n", + " self.n_spatial_dims = 2\n", + " self.dimensions = {\n", + " 'time': Data(torch.linspace(0,1,39)),\n", + " 'x': Data(torch.linspace(0,1,256)),\n", + " 'y': Data(torch.linspace(0,1,128)),\n", + " }\n", + " # self.constants = {}\n", + " # self.boundary_conditions = {}\n", + "\n", + " self.filelist = []\n", + " reynolds_numbers = []\n", + " pressure_fields = []\n", + " velocity_fields = []\n", + " for filepath in filelist:\n", + " reynolds_numbers.append( int(filepath.stem.split('_')[-1]) )\n", + " fields = np.load(filepath)\n", + " pressure_fields.append(fields[:,0,:,:])\n", + " velocity_fields.append(fields[:,2:,:,:])\n", + " self.filelist.append(filepath)\n", + " \n", + " self.data = {\n", + " 'Reynolds Number': Data(\n", + " torch.tensor(reynolds_numbers),\n", + " traj_varying=True,\n", + " time_varying=False,\n", + " space_varying=[False, False],\n", + " ),\n", + " 'Pressure': Data(\n", + " torch.tensor(pressure_fields),\n", + " traj_varying=True,\n", + " time_varying=True,\n", + " space_varying=[True, True],\n", + " ),\n", + " 'Velocity': Data(\n", + " torch.tensor(velocity_fields),\n", + " traj_varying=True,\n", + " time_varying=True,\n", + " space_varying=[True, True],\n", + " ),\n", + " }\n", + "\n", + " \n", + "\n", + " # def __getitem__(self):\n", + " \n", + "\n", + " # def normalize(self):\n", + "\n", + " # train_ds = ds.filter( torch.reduce_sum(ds.data['morphology'], dim=[1,2]) < 100 )\n", + "\n", + " def filter(self, mask):\n", + " '''\n", + " train = ds.filter( ds[ds.physics_parameters[0]] < 1000 )\n", + " test = ds.filter( ds.meta.physics_parameters[0] >= 1000 )\n", + " '''\n", + " assert( len(mask.shape) == 1 ) # TODO: error message\n", + " assert( len(mask) == self.n_trajectories ) # TODO: error message\n", + "\n", + " indices = torch.nonzero(mask).squeeze().tolist()\n", + " print(indices)\n", + " ds = Dataset() # TODO: Copy constructor\n", + " ds.filelist = [self.filelist[i] for i in indices] # TODO: Deep copy?\n", + " ds.data = {key: self.data[key][indices] for key in self.data.keys()} # TODO: Deep copy?\n", + " ds.grid_type = self.grid_type\n", + " ds.n_spatial_dims = self.n_spatial_dims\n", + " ds.data_dir = self.data_dir\n", + " ds.dimensions = self.dimensions\n", + " ds.boundary_conditions = self.boundary_conditions\n", + " ds.constants = self.constants\n", + " return ds\n", + " \n", + "\n", + "ds = Dataset()\n", + "print(ds.data['Reynolds Number'])\n", + "print(ds.data['Reynolds Number'][0])\n", + "print(ds.data['Reynolds Number'] < 1000)\n", + "print(ds.data['Reynolds Number'] < torch.tensor([1,2,3,4,1000,1000,1000,1000]))\n", + "print(ds.data['Reynolds Number'].rank)\n", + "print(ds.data['Reynolds Number'].type)\n", + "\n", + "print(ds.data['Pressure'].rank)\n", + "print(ds.data['Pressure'].type)\n", + "print(ds.data['Pressure'].shape)\n", + "torch.mean(ds.data['Pressure'], dim=[1,2,3])" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0, 2, 6]\n", + "tensor([ 300, 400, 8000])\n" + ] + } + ], + "source": [ + "train_ds = ds.filter((ds.data['Reynolds Number'] < 500) | (ds.data['Reynolds Number'] > 5000))\n", + "print(train_ds.data['Reynolds Number'])" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "from torch.utils.data import DataLoader\n", + "\n", + "# Create DataLoader for training dataset\n", + "train_loader = DataLoader(\n", + " train_ds,\n", + " batch_size=10,\n", + " shuffle=False,\n", + " num_workers=1,\n", + " pin_memory=True,\n", + " # collate_fn=custom_collate_fn,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "ename": "RuntimeError", + "evalue": "DataLoader worker (pid(s) 19368) exited unexpectedly", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mEmpty\u001b[0m Traceback (most recent call last)", + "File \u001b[1;32mc:\\Users\\mwn4yc\\Anaconda3\\envs\\parc\\lib\\site-packages\\torch\\utils\\data\\dataloader.py:1133\u001b[0m, in \u001b[0;36m_MultiProcessingDataLoaderIter._try_get_data\u001b[1;34m(self, timeout)\u001b[0m\n\u001b[0;32m 1132\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m-> 1133\u001b[0m data \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_data_queue\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtimeout\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtimeout\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 1134\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m (\u001b[38;5;28;01mTrue\u001b[39;00m, data)\n", + "File \u001b[1;32mc:\\Users\\mwn4yc\\Anaconda3\\envs\\parc\\lib\\queue.py:179\u001b[0m, in \u001b[0;36mQueue.get\u001b[1;34m(self, block, timeout)\u001b[0m\n\u001b[0;32m 178\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m remaining \u001b[38;5;241m<\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;241m0.0\u001b[39m:\n\u001b[1;32m--> 179\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m Empty\n\u001b[0;32m 180\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mnot_empty\u001b[38;5;241m.\u001b[39mwait(remaining)\n", + "\u001b[1;31mEmpty\u001b[0m: ", + "\nThe above exception was the direct cause of the following exception:\n", + "\u001b[1;31mRuntimeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[16], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m batch \u001b[38;5;129;01min\u001b[39;00m train_loader:\n\u001b[0;32m 2\u001b[0m \u001b[38;5;28mprint\u001b[39m(batch)\n\u001b[0;32m 3\u001b[0m \u001b[38;5;28;01mbreak\u001b[39;00m\n", + "File \u001b[1;32mc:\\Users\\mwn4yc\\Anaconda3\\envs\\parc\\lib\\site-packages\\torch\\utils\\data\\dataloader.py:631\u001b[0m, in \u001b[0;36m_BaseDataLoaderIter.__next__\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 628\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_sampler_iter \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m 629\u001b[0m \u001b[38;5;66;03m# TODO(https://github.com/pytorch/pytorch/issues/76750)\u001b[39;00m\n\u001b[0;32m 630\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_reset() \u001b[38;5;66;03m# type: ignore[call-arg]\u001b[39;00m\n\u001b[1;32m--> 631\u001b[0m data \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_next_data\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 632\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_num_yielded \u001b[38;5;241m+\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;241m1\u001b[39m\n\u001b[0;32m 633\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_dataset_kind \u001b[38;5;241m==\u001b[39m _DatasetKind\u001b[38;5;241m.\u001b[39mIterable \u001b[38;5;129;01mand\u001b[39;00m \\\n\u001b[0;32m 634\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_IterableDataset_len_called \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m \\\n\u001b[0;32m 635\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_num_yielded \u001b[38;5;241m>\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_IterableDataset_len_called:\n", + "File \u001b[1;32mc:\\Users\\mwn4yc\\Anaconda3\\envs\\parc\\lib\\site-packages\\torch\\utils\\data\\dataloader.py:1329\u001b[0m, in \u001b[0;36m_MultiProcessingDataLoaderIter._next_data\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 1326\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_process_data(data)\n\u001b[0;32m 1328\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_shutdown \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_tasks_outstanding \u001b[38;5;241m>\u001b[39m \u001b[38;5;241m0\u001b[39m\n\u001b[1;32m-> 1329\u001b[0m idx, data \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_get_data\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 1330\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_tasks_outstanding \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;241m1\u001b[39m\n\u001b[0;32m 1331\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_dataset_kind \u001b[38;5;241m==\u001b[39m _DatasetKind\u001b[38;5;241m.\u001b[39mIterable:\n\u001b[0;32m 1332\u001b[0m \u001b[38;5;66;03m# Check for _IterableDatasetStopIteration\u001b[39;00m\n", + "File \u001b[1;32mc:\\Users\\mwn4yc\\Anaconda3\\envs\\parc\\lib\\site-packages\\torch\\utils\\data\\dataloader.py:1285\u001b[0m, in \u001b[0;36m_MultiProcessingDataLoaderIter._get_data\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 1283\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_pin_memory:\n\u001b[0;32m 1284\u001b[0m \u001b[38;5;28;01mwhile\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_pin_memory_thread\u001b[38;5;241m.\u001b[39mis_alive():\n\u001b[1;32m-> 1285\u001b[0m success, data \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_try_get_data\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 1286\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m success:\n\u001b[0;32m 1287\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m data\n", + "File \u001b[1;32mc:\\Users\\mwn4yc\\Anaconda3\\envs\\parc\\lib\\site-packages\\torch\\utils\\data\\dataloader.py:1146\u001b[0m, in \u001b[0;36m_MultiProcessingDataLoaderIter._try_get_data\u001b[1;34m(self, timeout)\u001b[0m\n\u001b[0;32m 1144\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(failed_workers) \u001b[38;5;241m>\u001b[39m \u001b[38;5;241m0\u001b[39m:\n\u001b[0;32m 1145\u001b[0m pids_str \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;241m.\u001b[39mjoin(\u001b[38;5;28mstr\u001b[39m(w\u001b[38;5;241m.\u001b[39mpid) \u001b[38;5;28;01mfor\u001b[39;00m w \u001b[38;5;129;01min\u001b[39;00m failed_workers)\n\u001b[1;32m-> 1146\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mRuntimeError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mDataLoader worker (pid(s) \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mpids_str\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m) exited unexpectedly\u001b[39m\u001b[38;5;124m'\u001b[39m) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01me\u001b[39;00m\n\u001b[0;32m 1147\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(e, queue\u001b[38;5;241m.\u001b[39mEmpty):\n\u001b[0;32m 1148\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m (\u001b[38;5;28;01mFalse\u001b[39;00m, \u001b[38;5;28;01mNone\u001b[39;00m)\n", + "\u001b[1;31mRuntimeError\u001b[0m: DataLoader worker (pid(s) 19368) exited unexpectedly" + ] + } + ], + "source": [ + "for batch in train_loader:\n", + " print(batch)\n", + " break" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "module 'PARCtorch' has no attribute 'datasets'", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[1], line 2\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mPARCtorch\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m \u001b[38;5;21;01mparc\u001b[39;00m\n\u001b[1;32m----> 2\u001b[0m \u001b[43mparc\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdatasets\u001b[49m\u001b[38;5;241m.\u001b[39mNavierStokes()\n", + "\u001b[1;31mAttributeError\u001b[0m: module 'PARCtorch' has no attribute 'datasets'" + ] + } + ], + "source": [ + "import PARCtorch as parc\n", + "parc.datasets.NavierStokes()" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -516,7 +903,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "parc", "language": "python", "name": "python3" }, @@ -530,7 +917,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.13.2" + "version": "3.10.14" } }, "nbformat": 4, diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..e69de29 diff --git a/PARCtorch/misc/VIL_logo.png b/img/VIL_logo.png similarity index 100% rename from PARCtorch/misc/VIL_logo.png rename to img/VIL_logo.png diff --git a/PARCtorch/misc/iowa.png b/img/iowa.png similarity index 100% rename from PARCtorch/misc/iowa.png rename to img/iowa.png diff --git a/PARCtorch/misc/uva.png b/img/uva.png similarity index 100% rename from PARCtorch/misc/uva.png rename to img/uva.png diff --git a/tests/test_built_in_datasets.py b/tests/test_built_in_datasets.py new file mode 100644 index 0000000..41587e6 --- /dev/null +++ b/tests/test_built_in_datasets.py @@ -0,0 +1,8 @@ +import PARCtorch as parc + + +def test_dataset_navier_stokes(): + """ + Test built-in Navier-Stokes dataset + """ + ds = parc.datasets.NavierStokes(path='dummy.py') \ No newline at end of file