Skip to content

Commit

Permalink
Merge pull request #40 from praksharma/development
Browse files Browse the repository at this point in the history
FCNN working
  • Loading branch information
praksharma authored Nov 10, 2023
2 parents 208e340 + b779149 commit 82f14ae
Show file tree
Hide file tree
Showing 24 changed files with 419 additions and 139 deletions.
1 change: 1 addition & 0 deletions DeepINN/geometry_refactor/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pass
8 changes: 8 additions & 0 deletions DeepINN/geometry_refactor/points.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""
Contains a class that handles the storage of all created data points.
"""

import torch
import numpy as np
from .space import Space

1 change: 1 addition & 0 deletions DeepINN/geometry_refactor/spaces/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .space import Space, R1, R2, R3
147 changes: 147 additions & 0 deletions DeepINN/geometry_refactor/spaces/space.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
from collections import Counter, OrderedDict

"""
* A Counter is a dict subclass for counting hashable objects. It is a collection where elements are stored as dictionary keys and their counts are stored as dictionary values.
* An OrderedDict is a dictionary subclass that remembers the order in which items are inserted.
"""

class Space(Counter, OrderedDict):
"""
Base class to define the dimensions of the variables in the differential equation.
Parameters
----------
variables_dims: dict
A dict containing name of variables and the dimension of each variable.
"""
def __init__(self, variables_dims):
# set counter of variable names and their dimensionalities
# Since the Counter is inherited first, if the super().__init__ is consumed by Counter then the second super class won't receive the call.
super().__init__(variables_dims)

# # Adding a magic method to overload the multiply operator using __mul__
# def __mul__(self, additional_space):
# """
# Combine two spaces to create higher dimension spaces.
# E.g R1('x')*R1('y') is a two dimensional space where one axis is 'x'
# and the other stands for 'y'.
# """
# assert isinstance(additional_space, Space), "The additional dimension isn't an instance of Space"
# # Since we haven't defined __add__. Python will use Counter's __add__ method
# return Space(self + additional_space)

# # __contains__ is a predefined method checks if the key (a string) is present in the counter.
# # whenever we use `in` keyword with if condition involving instances of Space object, this self.__contains__ will run be override python's default __contains__.
# # here we override this functionpython's default __contains__
# # So if we do addition __add__ we will end up executing self.__contains__
# def __contains__(self, space):
# """
# Check if the variables of other space are container in this space.
# There are two possibilities.
# * method executed for internal dictionary operations such as addition
# * method executed when checking if intersection of space and self is space.
# That is why we need to modify python default __contains__ for instances of Space.

# ChatGPT's description:
# Override the membership test (in) for the Space class.
# - If `space` is a string: Checks if the variable name (key) exists in this Space.
# This is useful for both direct membership tests and internal operations
# (e.g., during dictionary-style key checking in addition).

# - If `space` is another Space object: Determines if the provided Space is
# entirely contained within the current Space (i.e., if it's a subset).
# """
# if isinstance(space,str):
# #print("Flag: string")
# # check if the space already contains the variable names.
# return super().__contains__(space)
# if isinstance(space, Space):
# #print("Flag: Space")
# return (self & space) == space
# else:
# return False

# # This is a special method in Python which is invoked when we try to access items from containers like array or dictionary.
# # It's what gets called when you use square bracket notation to access elements, such as with lists, dictionaries, and strings.
# def __getitem__(self, val):
# """
# Since __getitem__ is used to retrieve items. There are three ways to retrieve items. str, slice, list or tuple.

# 1. In the case of a slice.
# space_obj = Space({'a': 1, 'b': 2, 'c': 3, 'd': 4})
# sub_space = space_obj['a':'c'] # returns a Space with {'a': 1, 'b': 2, 'c': 3}

# 2. In the case of a tuple or a list
# space_obj = Space({'a': 1, 'b': 2, 'c': 3, 'd': 4})
# sub_space = space_obj[['a', 'c']] # returns a Space with {'a': 1, 'c': 3}

# 3. In all other cases then use Counter's __getitem__.
# space_obj = Space({'a': 1, 'b': 2, 'c': 3, 'd': 4})
# value = space_obj['a'] # returns 1

# Parameters
# ----------
# val : str, slice, list or tuple
# The keys that correspond to the variables that should be used in the
# subspace.
# """
# if isinstance(val, slice): # if val is a slice
# keys = list(self.keys())
# new_slice = slice(keys.index(val.start) if val.start is not None else None,
# keys.index(val.stop) if val.stop is not None else None,
# val.step)
# new_keys = keys[new_slice]
# return Space({k: self[k] for k in new_keys})
# if isinstance(val, list) or isinstance(val, tuple):
# return Space({k: self[k] for k in val})
# else:
# return super().__getitem__(val)

# # To promote encapsulation, @property decorator allows you to print internal read-only attributes of choice.
# # @property also allows you to call a function without the parentheses. This is useful when these isn't any input attribute.
# @property
# def dim(self):
# """
# Return the dimension of the space.
# """
# # self is the class Space inheriting Counter, which inherits dict, so values() will return list of values for each key of variables_dims. then sum will sum them up.
# return sum(self.values())

class R1(Space):
"""
Space to define 1D domain.
Parameters
----------
variable_name: str
The name of the variable that belongs to this space.
It can be any string for coordinate axes.
"""
def __init__(self, variable_name):
super().__init__(variable_name, 1)

class R2(Space):
"""
Space to define 2D domain.
Parameters
----------
variable_name: str
The name of the variable that belongs to this space.
It can be any string for coordinate axes.
"""
def __init__(self, variable_name):
super().__init__(variable_name, 2)

class R3(Space):
"""
Space to define 3D domain.
Parameters
----------
variable_name: str
The name of the variable that belongs to this space.
It can be any string for coordinate axes.
"""
def __init__(self, variable_name):
super().__init__(variable_name, 3)
11 changes: 8 additions & 3 deletions DeepINN/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def compile(self, optimiser_string : str, lr : float, metrics_string : str, devi
self.compile_network()

def compile_domain(self):
# sample collcation points
# sample collocation points
self.collocation_point_sample, self.collocation_point_labels = self.domain.sample_collocation_labels()

# sample boundary points
Expand All @@ -47,14 +47,16 @@ def compile_network(self):
print("Network compiled", file=sys.stderr, flush=True)

def train(self, iterations : int = None, display_every : int = None):

if self.iter == 0: # We are running a fresh training
self.training_history = [] # Initialize an empty list for storing loss values
self.iterations = iterations
# Load all the seeds, data types, devices etc.
self.config.apply_seeds()
self.config.apply_float_type()
self.config.default_device()

# In 1D problem we need to combine the BCs as there is only one point for each BC, which returns an underfined feature scaling because the ub and lb are same in the denominator
# In 1D problem we need to combine the BCs as there is only one point for each BC, which returns an undefined feature scaling because the ub and lb are same in the denominator, so we get infinity
# For problem with multiple points on each boundary, we don't need to combine them.
if self.boundary_point_sample[0].size()[0] == 1: # if row is 1 in the particular boundary tensor
self.boundary_point_sample = torch.cat(self.boundary_point_sample, dim=0)
Expand All @@ -80,11 +82,14 @@ def train(self, iterations : int = None, display_every : int = None):
# backprop the total loss
self.total_loss.backward()

# Update model parameters based on the older values and the backproped gradient
# Update model parameters based on the older values and the backprop gradient
self.optimiser.step()
if self.iter % (self.iterations/10) == 0:
print(f"Iteration: {self.iter+1} \t BC Loss: {self.BC_loss:0.4f}\t PDE Loss: {self.PDE_loss:0.4f} \t Loss: {self.total_loss:0.4f}")

# Append the total loss value to the training history list
self.training_history.append(self.total_loss.item())

self.iter = self.iter + 1
else:
print('Training finished')
Expand Down
2 changes: 1 addition & 1 deletion DeepINN/nn/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
from .FCNN import BaseNetwork, FullyConnected
from.utils import activation, initialiser
from .utils import activation, initialiser
2 changes: 1 addition & 1 deletion DeepINN/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

from .data import PointsDataset, PointsDataLoader, DeepONetDataLoader

from .user_fun import UserFunction
from .user_fun import UserFunction, tensor2numpy
from .plotting import plot, animate, scatter
from .evaluation import compute_min_and_max

Expand Down
8 changes: 5 additions & 3 deletions DeepINN/utils/plotting/scatter_points.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ def scatter(subspace, *samplers, dpi=100, save=False):
Parameters
----------
subspace : torchphysics.problem.Space
subspace : dp.problem.Space
The (sub-)space of which the points should be plotted.
Only plotting for dimensions <= 3 is possible.
*samplers : torchphysics.problem.Samplers
*samplers : dp.problem.Samplers
The diffrent samplers for which the points should be plotted.
The plot for each sampler will be created in the order there were
passed in.
Expand Down Expand Up @@ -96,4 +96,6 @@ def _scatter_3D(points, labels, dpi, save):
ax.set_ylabel(labels[1])
ax.set_zlabel(labels[2])
if save:
plt.savefig('geom.jpg', dpi = dpi,bbox_inches='tight',transparent=True)
plt.savefig('geom.jpg', dpi = dpi,bbox_inches='tight',transparent=True)


8 changes: 7 additions & 1 deletion DeepINN/utils/user_fun.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,4 +310,10 @@ def evaluate_function(self, device='cpu', **inp):
self.fun = self.fun.to(device)
return self.fun
else:
return torch.tensor(self.fun, device=device).float()
return torch.tensor(self.fun, device=device).float()

def tensor2numpy(tensor_list):
"""
Converts a list of torch.tensors to numpy arrays.
"""
return [tensor.detach().cpu().numpy() for tensor in tensor_list]
44 changes: 8 additions & 36 deletions Tutorials/1. Geometry/Basic_domains.ipynb
Original file line number Diff line number Diff line change
@@ -1,49 +1,21 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 2,
"cell_type": "markdown",
"metadata": {},
"outputs": [],
"source": [
"# This is only valid when the package is not installed\n",
"import sys\n",
"sys.path.append('../../') # two folders up"
"# Basic domain "
]
},
{
"cell_type": "code",
"execution_count": 8,
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"MPLBACKEND=module://matplotlib_inline.backend_inline\n",
"HOSTNAME=925e79cc0c33\n",
"LD_LIBRARY_PATH=/usr/local/nvidia/lib:/usr/local/nvidia/lib64\n",
"HOME=/root\n",
"PAGER=cat\n",
"LC_CTYPE=C.UTF-8\n",
"FORCE_COLOR=1\n",
"NVIDIA_DRIVER_CAPABILITIES=compute,utility\n",
"TERM=xterm-color\n",
"PATH=/opt/conda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\n",
"PYTORCH_VERSION=2.0.1\n",
"CLICOLOR_FORCE=1\n",
"GIT_PAGER=cat\n",
"CLICOLOR=1\n",
"PWD=/workspace/tutorials/1. Geometry\n",
"JPY_PARENT_PID=1\n",
"PYDEVD_USE_FRAME_EVAL=NO\n",
"NVIDIA_VISIBLE_DEVICES=all\n",
"JPY_SESSION_NAME=/workspace/tutorials/1. Geometry/Basic_domains.ipynb\n"
]
}
],
"outputs": [],
"source": [
"!env"
"# This is only valid when the package is not installed\n",
"import sys\n",
"sys.path.append('../../') # two folders up"
]
},
{
Expand Down Expand Up @@ -91,7 +63,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.11"
"version": "3.8.10"
}
},
"nbformat": 4,
Expand Down
7 changes: 7 additions & 0 deletions Tutorials/1. Geometry/UKAEA SUT.ipynb
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# UKAEA SUT"
]
},
{
"cell_type": "code",
"execution_count": 1,
Expand Down
7 changes: 7 additions & 0 deletions Tutorials/1. Geometry/different sampling.ipynb
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Basic sampling techniques"
]
},
{
"cell_type": "code",
"execution_count": 1,
Expand Down
Loading

0 comments on commit 82f14ae

Please sign in to comment.