lululxvi / deepxde

A library for scientific machine learning and physics-informed learning
https://deepxde.readthedocs.io
GNU Lesser General Public License v2.1
2.64k stars 741 forks source link

Add experimental data regarding derivatives #780

Open tsarikahin opened 2 years ago

tsarikahin commented 2 years ago

Overview

Dear @lululxvi,

I have one question regarding the PointSetBC. Let's say I have the output quantity called u but the measurement data is based on du (It is derivative) then I can not use PointSetBC (If I am not wrong). What would be your suggestion?

Possible solution

OperatorBC allows us to use derivatives. But I could not think about how to use it in this context?

Here is the specific example:

Let's say here is the measurement data (includes 3 columns (coordinates x,y and displacement du) and n samples)

ext_data = np.loadtxt("/home/a11btasa/git_repos/pinnswithdxde/elasticity_2d/bulk_train_anchors.txt")

if the experimental data would be u instead of du, I could use simply

ex_data_xy = ext_data[:,0:2]
observe_u  = dde.PointSetBC(ex_data_xy, ext_data[:,2:3], component=0)

What would look like OpeatorBC?

dde.OperatorBC(geom, enforce_strain, domain_given)
def enforce_strain(x,y,X):
     # this is calculated strain
     eps_xx = dde.grad.jacobian(y, x, i=0, j=0)
     # eps_yy = dde.grad.jacobian(y, x, i=1, j=1) # not needed
     # eps_xy = 1/2*(dde.grad.jacobian(y, x, i=1, j=0)+dde.grad.jacobian(y, x, i=0, j=1)) # not needed

     # measured strain
     eps_xx_m = utils.return_tensor(ext_data[:,2:3]) 
     eps_xx_m = bkd.as_tensor(eps_xx_m, dtype=config.real(bkd.lib))   # of course it has to be tensor

     return eps_xx-eps_xx_m # some doubts if the dimensions will match??
def domain_given(x, on_boundary):
    return np.isclose(x, ex_data_xy)

Do you think it would be correct? Of course, I should add the extra points to the domain as well using anchors. I also thought creating a custom class:

class PointSetBCFunc(object):
    """Dirichlet boundary condition for a set of points.
    Compare the output (that associates with `points`) with `values` (target data).

    Args:
        points: An array of points where the corresponding target values are known and used for training.
        values: An array of values that gives the exact solution of the problem.
        component: The output component satisfying this BC.
    """

    def __init__(self, points, values, component=0):
        self.points = np.array(points, dtype=config.real(np))
        if not isinstance(values, numbers.Number) and values.shape[1] != 1:
            raise RuntimeError(
                "PointSetBC should output 1D values. Use argument 'component' for different components."
            )
        self.values = bkd.as_tensor(values, dtype=config.real(bkd.lib))
        self.component = component
        self.func = func

    def collocation_points(self, X):
        return self.points

    def error(self, X, inputs, outputs, beg, end):
        return self.func(inputs, outputs, X)[beg:end]- self.values

Thanks in advance!

Best regards, Tarik

lululxvi commented 2 years ago

Both approaches can work. But using dde.OperatorBC is a little tricky, and I suggest the second approach, i.e., adding a new class PointSetOperatorBC. Actually, there is another "Issue" already talking about this.

Your implementation is basically correct. Feel free to submit a PR, and we can improve it then.

sashahexe commented 2 years ago

I have erased this reply, as I found a bug in my code. Hope the idea with the PointSetOperatorBC will be brought to live. Thank you @lululxvi for your constant work on DeepXDE.

tsarikahin commented 2 years ago

@lululxvi I have implemented PointSetOperatorBC and tested for an example of solid mechanics. I will make a PR as soon as I have time!