Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding ability to define test space through convex hull #18

Merged
merged 18 commits into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions examples/burgers1d.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,27 @@ parameter_space:
test_space:
type: grid

## An example if we want to provide training points on exterior
## of region and train in convex hull of training points
# parameter_space:
# parameters:
# - name: a
# min: 0.7
# max: 0.9
# test_space_type: list
# sample_size: 21
# list: [0.70, 0.725, 0.75, 0.800, 0.85, 0.90]
# log_scale: false
# - name: w
# min: 0.9
# max: 1.1
# test_space_type: list
# sample_size: 21
# list: [0.90, 0.970, 1.00, 0.925, 0.98, 1.10]
# log_scale: false
# test_space:
# type: hull

latent_space:
type: ae
ae:
Expand Down
15 changes: 13 additions & 2 deletions src/lasdi/gplasdi.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,11 @@ def train(self):
n_train = ps.n_train()
ld = self.latent_dynamics

self.training_loss = []
andersonw1 marked this conversation as resolved.
Show resolved Hide resolved
self.ae_loss = []
self.ld_loss = []
self.coef_loss = []

'''
determine number of iterations.
Perform n_iter iterations until overall iterations hit max_iter.
Expand All @@ -184,6 +189,11 @@ def train(self):

loss = loss_ae + self.ld_weight * loss_ld / n_train + self.coef_weight * loss_coef / n_train

self.training_loss.append(loss.item())
self.ae_loss.append(loss_ae.item())
self.ld_loss.append(loss_ld.item())
self.coef_loss.append(loss_coef.item())

loss.backward()
self.optimizer.step()

Expand Down Expand Up @@ -267,7 +277,8 @@ def export(self):
dict_ = {'X_train': self.X_train, 'X_test': self.X_test, 'lr': self.lr, 'n_iter': self.n_iter,
'n_samples' : self.n_samples, 'best_coefs': self.best_coefs, 'max_iter': self.max_iter,
'max_iter': self.max_iter, 'ld_weight': self.ld_weight, 'coef_weight': self.coef_weight,
'restart_iter': self.restart_iter, 'timer': self.timer.export(), 'optimizer': self.optimizer.state_dict()
'restart_iter': self.restart_iter, 'timer': self.timer.export(), 'optimizer': self.optimizer.state_dict(),
'training_loss' : self.training_loss, 'ae_loss' : self.ae_loss, 'ld_loss' : self.ld_loss, 'coeff_loss' : self.coef_loss
}
return dict_

Expand All @@ -280,4 +291,4 @@ def load(self, dict_):
self.optimizer.load_state_dict(dict_['optimizer'])
if (self.device != 'cpu'):
optimizer_to(self.optimizer, self.device)
return
return
111 changes: 108 additions & 3 deletions src/lasdi/param.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import numpy as np
from scipy.spatial import Delaunay
from .inputs import InputParser

def get_1dspace_from_list(config):
Expand Down Expand Up @@ -40,12 +41,18 @@ def __init__(self, config):
for param in self.param_list:
self.param_name += [param['name']]

self.train_space = self.createInitialTrainSpace(self.param_list)
self.n_init = self.train_space.shape[0]

test_space_type = parser.getInput(['test_space', 'type'], datatype=str)
if (test_space_type == 'grid'):
self.train_space = self.createInitialTrainSpace(self.param_list)
self.n_init = self.train_space.shape[0]

self.test_grid_sizes, self.test_meshgrid, self.test_space = self.createTestGridSpace(self.param_list)
if (test_space_type == 'hull'):
assert self.n_param >=2, 'Must have at least 2 parameters if test_space is \'hull\' '
andersonw1 marked this conversation as resolved.
Show resolved Hide resolved
self.train_space = self.createInitialTrainSpaceForHull(self.param_list)
self.n_init = self.train_space.shape[0]

self.test_grid_sizes, self.test_meshgrid, self.test_space = self.createTestHullSpace(self.param_list)

return

Expand All @@ -66,6 +73,38 @@ def createInitialTrainSpace(self, param_list):
mesh_grids = self.createHyperMeshGrid(paramRanges)
return self.createHyperGridSpace(mesh_grids)

def createInitialTrainSpaceForHull(self, param_list):
'''
dreamer2368 marked this conversation as resolved.
Show resolved Hide resolved
Concatenates the provided lists of training points into a 2D array.

Arguments
---------
param_list : :obj:`list(dict)`
A list of parameter dictionaries

Returns
-------
mesh_grids : :obj:`numpy.array`
np.array of size [d, k], where d is the number of points provided on the exterior of
the training space and k is the number of parameters (k == len(param_list)).
'''

paramRanges = []

for k, param in enumerate(param_list):

_, paramRange = getParam1DSpace['list'](param)
paramRanges += [paramRange]

if k > 0:
assert (len(paramRanges[k])==len(paramRanges[k - 1])), (f'Training parameters {k} and {k-1} have '
'different lengths. All training parameters '
'must have same length when test_space is \'hull\'.')


mesh_grids = np.vstack((paramRanges)).T
return mesh_grids

def createTestGridSpace(self, param_list):
paramRanges = []
gridSizes = []
Expand All @@ -78,6 +117,72 @@ def createTestGridSpace(self, param_list):
mesh_grids = self.createHyperMeshGrid(paramRanges)
return gridSizes, mesh_grids, self.createHyperGridSpace(mesh_grids)

def createTestGridSpaceForHull(self, param_list):
'''
dreamer2368 marked this conversation as resolved.
Show resolved Hide resolved
Builds an initial uniform grid for the testing parameters when the test_space is 'hull'.

Arguments
---------
param_list : :obj:`list(dict)`
A list of parameter dictionaries

Returns
-------
gridSizes : :obj:`list(int)`
A list containing the number of elements on the grid in each parameter.
mesh_grids : :obj:`numpy.array`
tuple of numpy nd arrays, corresponding to each parameter.
Dimension of the array equals to the number of parameters.
param_grid : :obj:`numpy.array`
numpy 2d array of size (grid size x number of parameters).
'''

paramRanges = []
gridSizes = []

for param in param_list:
Nx, paramRange = getParam1DSpace['uniform'](param)
gridSizes += [Nx]
paramRanges += [paramRange]

mesh_grids = self.createHyperMeshGrid(paramRanges)
return gridSizes, mesh_grids, self.createHyperGridSpace(mesh_grids)

def createTestHullSpace(self, param_list):
'''
This function builds an initial uniform grid for the testing parameters, and then
returns any testing points which are within the convex hull of the provided
training parameters.

Arguments
---------
param_list : :obj:`list(dict)`
A list of parameter dictionaries

Returns
-------
gridSizes : :obj:`list(int)`
A list containing the number of elements on the grid in each parameter.
mesh_grids : :obj:`numpy.array`
tuple of numpy nd arrays, corresponding to each parameter.
Dimension of the array equals to the number of parameters.
test_space : :obj:`numpy.array`
numpy 2d array of size [d, k], where d is the number of testing points within
convex hull of the training space and k is the number of parameters (k == len(param_list)).
'''

# Get the initial uniform grid over the training parameters
gridSizes, mesh_grids, test_space = self.createTestGridSpaceForHull(param_list)

# Mesh the training space. This will be slow in higher dimensions
cloud = Delaunay(self.train_space)
# Determine which test points are contained in the convex hull of training points
mask = cloud.find_simplex(test_space)>=0
# Only keep testing points in the convex hull of training points
test_space = test_space[mask]

return gridSizes, mesh_grids, test_space

def getParameter(self, param_vector):
'''
convert numpy array parameter vector to a dict.
Expand Down
Loading