├── InversePinnConstantCoef.mlx ├── InversePinnVariableCoef.mlx ├── License.txt ├── README.md ├── SECURITY.md ├── images ├── ConstantCoefSolution.png ├── ConstantCoefTraining.png ├── Geometry.png ├── VariableCoefTraining.png ├── VariablePredictedC.png └── VariablePredictedSolution.png └── src ├── InversePinnConstantCoef.m └── InversePinnVariableCoef.m /InversePinnConstantCoef.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matlab-deep-learning/Inverse-Problems-using-Physics-Informed-Neural-Networks-PINNs/20a80ca16d82044ba7886c7fa35b49811fab54fb/InversePinnConstantCoef.mlx -------------------------------------------------------------------------------- /InversePinnVariableCoef.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matlab-deep-learning/Inverse-Problems-using-Physics-Informed-Neural-Networks-PINNs/20a80ca16d82044ba7886c7fa35b49811fab54fb/InversePinnVariableCoef.mlx -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2023, The MathWorks, Inc. 2 | All rights reserved. 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 5 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 6 | 3. In all cases, the software is, and all modifications and derivatives of the software shall be, licensed to you solely for use in conjunction with MathWorks products and service offerings. 7 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Inverse Problems using PINNs 2 | 3 | ## Overview 4 | This repository contains two examples: InversePinnConstantCoef.mlx and InversePinnVariableCoef.mlx. Both examples are solvers for an inverse problem for the Poisson equation $−\nabla \cdot (c\nabla u)=1$ with suitable boundary conditions. In particular, this is a parameter estimation problem in which we assume that we have an exact solution u, and we are interested in computing an approximation to the coefficient $c$. 5 | 6 | The first example, InversePinnConstantCoef, shows how to solve the parameter estimation problem when $c$ is a constant. In the example, a PINN corresponding to the solution is trained, and while training the PINN, the coefficient is optimized. Both the network parameters and the coefficient are trained using the Adam algorithm. This results in an approximation for the coefficient to be found and a PINN that can be used to approximate the solution. 7 | 8 | The second example is essentially the same setup as the first. However, rather than using a constant coefficient, the coefficient is also approximated by a neural network. Both the PINN and coefficient networks are trained simulataneously. After training, there are two networks, one which approximates the PDE and one which approximates the coefficient. 9 | 10 | 11 | ## Pinns for Inverse Problems : Constant Coefficients 12 | 13 | The Poisson equation on a unit disk with zero Dirichlet boundary condition can be written as $-\nabla\cdot (c \nabla u) = 1$ in $\Omega$, $u=0$ on $\partial \Omega$, where $\Omega$ is the unit disk. The exact solution when $c=1$ is $$u(x,y) = \frac{1 - x^2 - y^2}{4}$$ 14 | 15 | This equation is relevant for example in therodynamics, where this describes a steady state heat equation, with the boundary of the circle held at a constant temperature of 0, the right hand side of the equation is a volumetric heat source, and the coefficient $c$ is the thermal diffusivity. The typical "forward" problem is to use this information to find u. 16 | One could consider the inverse problem: given a known temperature distribution $u$ corresponding to the solution at a set of points, a known volumetric heat source, and boundary conditions, what is the thermal diffusivity? Using a PINN to solve the equation, we can optimize the PINN parameters and the optimize to solve for the coefficient at the same time. In this exmaple, we will take the data to be given by the exact solution above. In practice, the exact solution is often not known, but measurements of the solution can be provided instead. 17 | 18 | ### PDE Model Definition 19 | 20 | ```matlab:Code 21 | rng('default'); % for reproducibility 22 | model = createpde(); 23 | geometryFromEdges(model,@circleg); 24 | applyBoundaryCondition(model,"dirichlet", ... 25 | "Edge",1:model.Geometry.NumEdges, ... 26 | "u",0); 27 | ``` 28 | 29 | Plot the geometry and display the edge labels for use in the boundary condition definition. 30 | 31 | ```matlab:Code 32 | figure 33 | pdegplot(model,"EdgeLabels","on"); 34 | axis equal 35 | ``` 36 | 37 | ![Geometry.png](images/Geometry.png) 38 | 39 | Create a structural array of coefficents. Specify the coefficients to the PDE model. Note that pdeCoeffs.c is an initial guess; it will be updated during training. We also define pdeCoeffs to be a struct of dlarrays so that we can compute gradients with respect to them. 40 | 41 | ```matlab:Code 42 | pdeCoeffs.c = .5; 43 | % fixed values for other coefficients 44 | pdeCoeffs.m = 0; 45 | pdeCoeffs.d = 0; 46 | pdeCoeffs.a = 0; 47 | pdeCoeffs.f = 1; 48 | % set up model 49 | specifyCoefficients(model,"m",pdeCoeffs.m,"d",pdeCoeffs.d,"c",pdeCoeffs.c,"a",pdeCoeffs.a,"f",pdeCoeffs.f); 50 | Hmax = 0.05; Hgrad = 2; Hedge = Hmax/10; 51 | msh = generateMesh(model,"Hmax",Hmax,"Hgrad",Hgrad,"Hedge",{1:model.Geometry.NumEdges,Hedge}); 52 | % make coefs dlarrays so gradients can be computed 53 | pdeCoeffs = structfun(@dlarray,pdeCoeffs,'UniformOutput',false); 54 | ``` 55 | 56 | ### Generate Spatial Data for Training PINN 57 | 58 | This examples uses mesh nodes as the collocation points. Model loss at the collocation points on the domain and boundary are used to train the PINN. 59 | 60 | ```matlab:Code 61 | boundaryNodes = findNodes(msh,"region","Edge",1:model.Geometry.NumEdges); 62 | domainNodes = setdiff(1:size(msh.Nodes,2),boundaryNodes); 63 | domainCollocationPoints = msh.Nodes(:,domainNodes)'; 64 | ``` 65 | 66 | ### Define Deep Learning Model 67 | 68 | This is a neural network with 3 hidden layers and 50 neurons per layer. The two inputs to the network correspond to the x and y coordinates, and the one output corresponds to the solution, so predict(pinn,XY) appoximates u(x,y). While training the c coefficient, we will also train this neural network to provide solutions to the PDE. 69 | 70 | ```matlab:Code 71 | numLayers = 3; 72 | numNeurons = 50; 73 | layers = featureInputLayer(2); 74 | for i = 1:numLayers-1 75 | layers = [ 76 | layers 77 | fullyConnectedLayer(numNeurons) 78 | tanhLayer];%#ok 79 | end 80 | layers = [ 81 | layers 82 | fullyConnectedLayer(1)]; 83 | pinn = dlnetwork(layers); 84 | ``` 85 | 86 | ### Define Custom Training Loop to Train the PINN Using ADAM Solver 87 | 88 | Specify training options. Create arrays for average gradients and square gradients for both the PINN and the parameter; both will be trained using the ADAM solver. 89 | 90 | ```matlab:Code 91 | numEpochs = 1500; 92 | miniBatchSize = 2^12; 93 | initialLearnRate = 0.01; 94 | learnRateDecay = 0.001; 95 | averageGrad = []; % for pinn updates 96 | averageSqGrad = []; 97 | pAverageGrad = []; % for parameter updates 98 | pAverageSqGrad = []; 99 | ``` 100 | 101 | Setup data store for the training points. For simplicity, we both train the PINN and compute the known data at the mesh nodes. 102 | 103 | ```matlab:Code 104 | ds = arrayDatastore(domainCollocationPoints); 105 | mbq = minibatchqueue(ds, MiniBatchSize = miniBatchSize, MiniBatchFormat="BC"); 106 | Calculate the total number of iterations for the training progress monitor and initialize the monitor. 107 | numIterations = numEpochs * ceil(size(domainCollocationPoints,1)/miniBatchSize); 108 | monitor = trainingProgressMonitor(Metrics="Loss",Info="Epoch",XLabel="Iteration"); 109 | ``` 110 | 111 | ### Training Loop 112 | 113 | Train the model and parameter using a custom training loop. Update the network parameters using the adamupdate function. At the end of each iteration, display the training progress. Note that we allow the PINN to be trained for 1/10th of the epochs before updating the c coefficient. This helps with robustness to the initial guess. 114 | 115 | ```matlab:Code 116 | iteration = 0; 117 | epoch = 0; 118 | learningRate = initialLearnRate; 119 | lossFcn = dlaccelerate(@modelLoss); 120 | while epoch < numEpochs && ~monitor.Stop 121 | epoch = epoch + 1; 122 | reset(mbq); 123 | while hasdata(mbq) && ~monitor.Stop 124 | iteration = iteration + 1; 125 | XY = next(mbq); 126 | % Evaluate the model loss and gradients using dlfeval. 127 | [loss,gradients] = dlfeval(lossFcn,model,pinn,XY,pdeCoeffs); 128 | % Update the network parameters using the adamupdate function. 129 | [pinn,averageGrad,averageSqGrad] = adamupdate(pinn,gradients{1},averageGrad,... 130 | averageSqGrad,iteration,learningRate); 131 | % Update the c coefficient using the adamupdate function. Defer 132 | % updating until 1/10 of epochs are finished. 133 | if epoch > numEpochs/10 134 | [pdeCoeffs.c,pAverageGrad,pAverageSqGrad] = adamupdate(pdeCoeffs.c,gradients{2},pAverageGrad,... 135 | pAverageSqGrad,iteration,learningRate); 136 | end 137 | end 138 | % Update learning rate. 139 | learningRate = initialLearnRate / (1+learnRateDecay*iteration); 140 | % Update the training progress monitor. 141 | recordMetrics(monitor,iteration,Loss=loss); 142 | updateInfo(monitor,Epoch=epoch + " of " + numEpochs); 143 | monitor.Progress = 100 * iteration/numIterations; 144 | end 145 | ``` 146 | 147 | ![ConstantCoefTraining.png](images/ConstantCoefTraining.png) 148 | 149 | ### Visualize Data 150 | 151 | Evaluate PINN at mesh nodes and plot, include updated value of c in title. Note that c = 1.001, compared to the exact value of 1, this is a 0.1% error. 152 | 153 | ```matlab:Code 154 | nodesDLarry = dlarray(msh.Nodes,"CB"); 155 | Upinn = gather(extractdata(predict(pinn,nodesDLarry))); 156 | figure; 157 | pdeplot(model,"XYData",Upinn); 158 | title(sprintf("Solution with c = %.4f",double(pdeCoeffs.c))); 159 | ``` 160 | ![ConstantCoefSolution](images/ConstantCoefSolution.png) 161 | 162 | ### Model Loss Function 163 | 164 | The modelLoss helper function takes a dlnetwork object pinn and a mini-batch of input data XY, and returns the loss and the gradients of the loss with respect to the learnable parameters in pinn and with respect to the c coefficient. To compute the gradients automatically, use the dlgradient function. Return the gradients w.r.t. learnable and w.r.t the parameter as two elements of a cell array so they can be used separately. The model is trained by enforcing that given an input the output of the network satsifies Poisson's equation and the boundary conditions. 165 | 166 | ```matlab:Code 167 | function [loss,gradients] = modelLoss(model,pinn,XY,pdeCoeffs) 168 | dim = 2; 169 | U = forward(pinn,XY); 170 | 171 | % Loss for difference in data taken at mesh nodes. 172 | Utrue = getSolutionData(XY); 173 | lossData = l2loss(U,Utrue); 174 | 175 | % Compute gradients of U and Laplacian of U. 176 | gradU = dlgradient(sum(U,"all"),XY,EnableHigherDerivatives=true); 177 | Laplacian = 0; 178 | for i=1:dim 179 | % Add each term of the Laplacian 180 | gradU2 = dlgradient(sum(pdeCoeffs.c.*gradU(i,:),"all"),XY,EnableHigherDerivatives=true); 181 | Laplacian = gradU2(i,:)+Laplacian; 182 | end 183 | 184 | % Enforce PDE. Calculate lossF. 185 | res = -pdeCoeffs.f - Laplacian + pdeCoeffs.a.*U; 186 | lossF = mean(sum(res.^2,1),2); 187 | 188 | % Enforce boundary conditions. Calculate lossU. 189 | actualBC = []; % contains the actual boundary information 190 | BC_XY = []; % boundary coordinates 191 | % Loop over the boundary edges and find boundary coordinates and actual BC 192 | % assigned to PDE model. 193 | numBoundaries = model.Geometry.NumEdges; 194 | for i=1:numBoundaries 195 | BCi = findBoundaryConditions(model.BoundaryConditions,'Edge',i); 196 | BCiNodes = findNodes(model.Mesh,"region","Edge",i); 197 | BC_XY = [BC_XY, model.Mesh.Nodes(:,BCiNodes)]; %#ok 198 | actualBCi = ones(1,numel(BCiNodes))*BCi.u; 199 | actualBC = [actualBC actualBCi]; %#ok 200 | end 201 | BC_XY = dlarray(BC_XY,"CB"); % format the coordinates 202 | predictedBC = forward(pinn,BC_XY); 203 | lossBC = mse(predictedBC,actualBC); 204 | 205 | % Combine weighted losses. 206 | lambdaPDE = 0.4; % weighting factor 207 | lambdaBC = 0.6; 208 | lambdaData = 0.5; 209 | loss = lambdaPDE*lossF + lambdaBC*lossBC + lambdaData*lossData; 210 | 211 | % Calculate gradients with respect to the learnable parameters and 212 | % C-coefficient. Pass back cell array to update pinn and coef separately. 213 | gradients = dlgradient(loss,{pinn.Learnables,pdeCoeffs.c}); 214 | end 215 | ``` 216 | 217 | ### Data Function 218 | This function returns the solution data at a given set of points XY. As a demonstration of the method, we return the exact solution from this function, but this function could be replaced with measured data for a given application. 219 | 220 | ```matlab:Code 221 | function UD = getSolutionData(XY) 222 | UD = (1-XY(1,:).^2-XY(2,:).^2)/4; 223 | end 224 | ``` 225 | 226 | 227 | ## Pinns for Inverse Problems : Variable Coefficients 228 | 229 | The Poisson equation on a unit disk with zero Dirichlet boundary condition can be written as $-\nabla\cdot (c \nabla u) = 1$ in $\Omega$, $u=0$ on $\partial \Omega$, where $\Omega$ is the unit disk. The exact solution when $c=1$ is $$u(x,y) = \frac{1 - x^2 - y^2}{4}$$ 230 | 231 | This equation is relevant for example in therodynamics, where this describes a steady state heat equation, with the boundary of the circle held at a constant temperature of 0, the right hand side of the equation is a volumetric heat source, and the coefficient $c$ is the thermal diffusivity. The typical "forward" problem is to use this information to find $u$. 232 | 233 | One could consider the inverse problem: given a known temperature distribution $u$ corresponding to the solution at a set of points, a known volumetric heat source, and boundary conditions, what is the thermal diffusivity? Using a PINN to solve the equation, we can optimize the PINN parameters and the optimize to solve for the coefficient at the same time. In this exmaple, we will take the data to be given by the exact solution above. In practice, the exact solution is often not known, but measurements of the solution can be provided instead. 234 | 235 | If the coefficients are known to be a function of space or of the solution, we can use a neural network to represent the coefficient, and train this neural network alongside the PINN. 236 | 237 | ### PDE Model Definition 238 | 239 | We reuse the same geometry as the previous example. 240 | 241 | ```matlab:Code 242 | rng('default'); % for reproducibility 243 | model = createpde(); 244 | geometryFromEdges(model,@circleg); 245 | applyBoundaryCondition(model,"dirichlet", ... 246 | "Edge",1:model.Geometry.NumEdges, ... 247 | "u",0); 248 | ``` 249 | 250 | Create a structural array of coefficents. C is left empty; it will be approximated using a neural network. 251 | 252 | ```matlab:Code 253 | pdeCoeffs.c = []; 254 | % fixed values for other coefficients 255 | pdeCoeffs.m = 0; 256 | pdeCoeffs.d = 0; 257 | pdeCoeffs.a = 0; 258 | pdeCoeffs.f = 1; 259 | % set up mesh 260 | Hmax = 0.05; Hgrad = 2; Hedge = Hmax/10; 261 | msh = generateMesh(model,"Hmax",Hmax,"Hgrad",Hgrad,"Hedge",{1:model.Geometry.NumEdges,Hedge}); 262 | % make coefs dlarrays so gradients can be computed 263 | pdeCoeffs = structfun(@dlarray,pdeCoeffs,'UniformOutput',false); 264 | ``` 265 | 266 | 267 | ### Generate Spatial Data for Training PINN 268 | 269 | This examples uses mesh nodes as the collocation points. Model loss at the collocation points on the domain and boundary are used to train the PINN. For simplicity, we will supply the true solution data at the same set of collocation points where the PINN loss is computed, but this is not required. 270 | 271 | ```matlab:Code 272 | boundaryNodes = findNodes(msh,"region","Edge",1:model.Geometry.NumEdges); 273 | domainNodes = setdiff(1:size(msh.Nodes,2),boundaryNodes); 274 | domainCollocationPoints = msh.Nodes(:,domainNodes)'; 275 | ``` 276 | 277 | ### Define Deep Learning Model 278 | 279 | This is a neural network with 3 hidden layers and 50 neurons per layer. The two inputs to the network correspond to the x and y coordinates, and the one output corresponds to the solution, so predict(pinn,XY) appoximates u(x,y). 280 | 281 | ```matlab:Code 282 | numLayers = 3; 283 | numNeurons = 50; 284 | layers = featureInputLayer(2); 285 | for i = 1:numLayers-1 286 | layers = [ 287 | layers 288 | fullyConnectedLayer(numNeurons) 289 | tanhLayer];%#ok 290 | end 291 | layers = [ 292 | layers 293 | fullyConnectedLayer(1)]; 294 | pinn = dlnetwork(layers); 295 | ``` 296 | 297 | Set up the coefficient network by copying the PINN so the two networks have the same architecture. Here, the two inputs represent x and y and the one output corresponds to the coefficient, so predict(coefNet,XY) appoximates c(x,y). If the problem was nonlinear and spatially dependent, c = c(x,y,u), you could add a third input and make the corresponding changes in the model loss function. Because of the data that will be supplied to the network, we expect that coefNet will learn c(x,y) = 1 for all x and y. 298 | 299 | ```matlab:Code 300 | coefNet = pinn; 301 | ``` 302 | 303 | Put both networks in one struct. 304 | 305 | ```matlab:Code 306 | nets = struct(pinn=pinn,coefNet=coefNet); 307 | ``` 308 | 309 | ### Define Custom Training Loop to Train the PINN Using ADAM Solver 310 | 311 | Specify training options. Create arrays for average gradients and square gradients for both the PINN and the parameter network; both will be trained using the ADAM solver. 312 | 313 | ```matlab:Code 314 | numEpochs = 5000; 315 | miniBatchSize = 2^12; 316 | initialLearnRate = 0.02; 317 | learnRateDecay = 0.001; 318 | averageGrad = []; 319 | averageSqGrad = []; 320 | ``` 321 | 322 | Setup data store for the training points. As stated before, we both train the PINN and compute the known data at the mesh nodes. 323 | 324 | ```matlab:Code 325 | ds = arrayDatastore(domainCollocationPoints); 326 | mbq = minibatchqueue(ds, MiniBatchSize = miniBatchSize, MiniBatchFormat="BC"); 327 | Calculate the total number of iterations for the training progress monitor and initialize the monitor. 328 | numIterations = numEpochs * ceil(size(domainCollocationPoints,1)/miniBatchSize); 329 | monitor = trainingProgressMonitor(Metrics="Loss",Info="Epoch",XLabel="Iteration"); 330 | ``` 331 | 332 | ### Training Loop 333 | Train the model and parameter network using a custom training loop. Update the network parameters using the adamupdate function. At the end of each iteration, display the training progress. 334 | 335 | ```matlab:Code 336 | epoch = 0; 337 | iteration = 0; 338 | learningRate = initialLearnRate; 339 | lossFcn = dlaccelerate(@modelLoss); 340 | while epoch < numEpochs && ~monitor.Stop 341 | epoch = epoch + 1; 342 | reset(mbq); 343 | while hasdata(mbq) && ~monitor.Stop 344 | iteration = iteration + 1; 345 | XY = next(mbq); 346 | % XY coordinates at which to get data 347 | XYData = XY; 348 | % Evaluate the model loss and gradients using dlfeval. 349 | [loss,gradients] = dlfeval(lossFcn,model,nets,XY,pdeCoeffs,XYData); 350 | % update the parameters of both networks 351 | [nets,averageGrad,averageSqGrad] = adamupdate(nets,gradients,averageGrad,... 352 | averageSqGrad,iteration,learningRate); 353 | end 354 | % Update learning rate. 355 | learningRate = initialLearnRate / (1+learnRateDecay*iteration); 356 | % Update the training progress monitor. 357 | recordMetrics(monitor,iteration,Loss=loss); 358 | updateInfo(monitor,Epoch=epoch + " of " + numEpochs); 359 | monitor.Progress = 100 * iteration/numIterations; 360 | end 361 | ``` 362 | 363 | 364 | ![VariableCoefTraining](images/VariableCoefTraining.png) 365 | 366 | 367 | ### Visualize Data 368 | 369 | Evaluate PINN and parameter network at mesh nodes and plot. Compute the maximum error at collocation points for the predicted coefficient. 370 | 371 | ```matlab:Code 372 | nodesDLarry = dlarray(msh.Nodes,"CB"); 373 | Upinn = gather(extractdata(predict(nets.pinn,nodesDLarry))); 374 | figure(1); 375 | pdeplot(model,"XYData",Upinn); 376 | C = gather(extractdata(predict(nets.coefNet,nodesDLarry))); 377 | figure(2); 378 | pdeplot(model,"XYData",C); 379 | title(sprintf('Predicted coefficient max error: = %0.1e',max(abs(C-1)))) 380 | ``` 381 | 382 | ![VariablePredictedSolution](images/VariablePredictedSolution.png) 383 | ![VariableCoefPredictedC](images/VariablePredictedC.png) 384 | 385 | 386 | 387 | ### Model Loss Function 388 | 389 | The modelLoss helper function takes a dlnetwork object pinn and a mini-batch of input data XY, and returns the loss and the gradients of the loss with respect to the learnable parameters in pinn and with respect to the c coefficient. To compute the gradients automatically, use the dlgradient function. Return the gradients w.r.t. learnable and w.r.t the parameter network as two elements of a cell array so they can be used separately. The model is trained by enforcing that given an input the output of the network satisfies Poisson's equation and the boundary conditions. 390 | 391 | ```matlab:Code 392 | function [loss,gradients] = modelLoss(model,nets,XY,pdeCoeffs,XYData) 393 | dim = 2; 394 | U = forward(nets.pinn,XY); 395 | C = forward(nets.coefNet,XY); 396 | 397 | % Loss for difference in data taken at mesh nodes. 398 | UDPred = forward(nets.pinn,XYData); 399 | UData = getSolutionData(XYData); 400 | lossData = l2loss(UDPred,UData); 401 | 402 | % Compute gradients of U and Laplacian of U. 403 | gradU = dlgradient(sum(U,"all"),XY,EnableHigherDerivatives=true); 404 | Laplacian = 0; 405 | for i=1:dim 406 | % Add each term of the Laplacian 407 | gradU2 = dlgradient(sum(C.*gradU(i,:),"all"),XY,EnableHigherDerivatives=true); 408 | Laplacian = gradU2(i,:)+Laplacian; 409 | end 410 | 411 | % Enforce PDE. Calculate lossF. 412 | res = -pdeCoeffs.f - Laplacian + pdeCoeffs.a.*U; 413 | zeroTarget = zeros(size(res), "like", res); 414 | lossF = mse(res, zeroTarget); 415 | 416 | % Enforce boundary conditions. Calculate lossU. 417 | actualBC = []; % contains the actual boundary information 418 | BC_XY = []; % boundary coordinates 419 | % Loop over the boundary edges and find boundary coordinates and actual BC 420 | % assigned to PDE model. 421 | numBoundaries = model.Geometry.NumEdges; 422 | for i=1:numBoundaries 423 | BCi = findBoundaryConditions(model.BoundaryConditions,'Edge',i); 424 | BCiNodes = findNodes(model.Mesh,"region","Edge",i); 425 | BC_XY = [BC_XY, model.Mesh.Nodes(:,BCiNodes)]; %#ok 426 | actualBCi = ones(1,numel(BCiNodes))*BCi.u; 427 | actualBC = [actualBC actualBCi]; %#ok 428 | end 429 | BC_XY = dlarray(BC_XY,"CB"); % format the coordinates 430 | predictedBC = forward(nets.pinn,BC_XY); 431 | lossBC = mse(predictedBC,actualBC); 432 | 433 | % Combine weighted losses. 434 | lambdaPDE = 1.1; 435 | lambdaBC = 1.; 436 | lambdaData = 1.; 437 | loss = lambdaPDE*lossF + lambdaBC*lossBC + lambdaData*lossData; 438 | 439 | % Calculate gradients with respect to the learnable parameters and 440 | % C-coefficient. Return gradients as a struct in order to update them 441 | % simultaneously using adamupdate. 442 | grads = dlgradient(loss,{nets.pinn.Learnables,nets.coefNet.Learnables}); 443 | gradients.pinn = grads{1}; 444 | gradients.coefNet = grads{2}; 445 | end 446 | ``` 447 | 448 | ### Data Function 449 | 450 | This function returns the solution data at a given set of points XY. As a demonstration of the method, we return the exact soltuion from this function, but this function could be replaced with measured data at the given set of points for applications. 451 | 452 | ```matlab:Code 453 | function UD = getSolutionData(XY) 454 | UD = (1-XY(1,:).^2-XY(2,:).^2)/4; 455 | end 456 | ``` 457 | 458 | ## Requirements 459 | MATLAB ® 460 | 461 | Deep Learning Toolbox ™ 462 | 463 | PDE Toolbox ™ 464 | 465 | ## To run 466 | Open the MLX files and run. No data or additional setup is required. Versions with the M file extension can be found under /src. 467 | 468 | 469 | Copyright 2023 The MathWorks, Inc. -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Reporting Security Vulnerabilities 2 | 3 | If you believe you have discovered a security vulnerability, please report it to 4 | [security@mathworks.com](mailto:security@mathworks.com). Please see 5 | [MathWorks Vulnerability Disclosure Policy for Security Researchers](https://www.mathworks.com/company/aboutus/policies_statements/vulnerability-disclosure-policy.html) 6 | for additional information. -------------------------------------------------------------------------------- /images/ConstantCoefSolution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matlab-deep-learning/Inverse-Problems-using-Physics-Informed-Neural-Networks-PINNs/20a80ca16d82044ba7886c7fa35b49811fab54fb/images/ConstantCoefSolution.png -------------------------------------------------------------------------------- /images/ConstantCoefTraining.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matlab-deep-learning/Inverse-Problems-using-Physics-Informed-Neural-Networks-PINNs/20a80ca16d82044ba7886c7fa35b49811fab54fb/images/ConstantCoefTraining.png -------------------------------------------------------------------------------- /images/Geometry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matlab-deep-learning/Inverse-Problems-using-Physics-Informed-Neural-Networks-PINNs/20a80ca16d82044ba7886c7fa35b49811fab54fb/images/Geometry.png -------------------------------------------------------------------------------- /images/VariableCoefTraining.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matlab-deep-learning/Inverse-Problems-using-Physics-Informed-Neural-Networks-PINNs/20a80ca16d82044ba7886c7fa35b49811fab54fb/images/VariableCoefTraining.png -------------------------------------------------------------------------------- /images/VariablePredictedC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matlab-deep-learning/Inverse-Problems-using-Physics-Informed-Neural-Networks-PINNs/20a80ca16d82044ba7886c7fa35b49811fab54fb/images/VariablePredictedC.png -------------------------------------------------------------------------------- /images/VariablePredictedSolution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matlab-deep-learning/Inverse-Problems-using-Physics-Informed-Neural-Networks-PINNs/20a80ca16d82044ba7886c7fa35b49811fab54fb/images/VariablePredictedSolution.png -------------------------------------------------------------------------------- /src/InversePinnConstantCoef.m: -------------------------------------------------------------------------------- 1 | %% *Pinns for Inverse Problems : Constant Coefficients* 2 | % 3 | % 4 | % The Poisson equation on a unit disk with zero Dirichlet boundary condition 5 | % can be written as $$- \nabla \cdot (c\nabla u) = 1$$ in $\Omega$, $u = 0$ on 6 | % $\partial \Omega$, where $\Omega$ is the unit disk. The exact solution when 7 | % $c = 1$ is 8 | % 9 | % $$u(x,y)= \frac{1-x^2-y^2}{4}$$ 10 | % 11 | % This equation is relevant for example in therodynamics, where this describes 12 | % a steady state heat equation, with the boundary of the circle held at a constant 13 | % temperature of 0, the right hand side of the equation is a volumetric heat source, 14 | % and the coefficient $c$ is the thermal diffusivity. The typical "forward" problem 15 | % is to use this information to find u. 16 | % 17 | % One could consider the inverse problem: given a known temperature distribution 18 | % $u$ corresponding to the solution at a set of points, a known volumetric heat 19 | % source, and boundary conditions, what is the thermal diffusivity? Using a PINN 20 | % to solve the equation, we can optimize the PINN parameters and the optimize 21 | % to solve for the coefficient at the same time. In this exmaple, we will take 22 | % the data to be given by the exact solution above. In practice, the exact solution 23 | % is often not known, but measurements of the solution can be provided instead. 24 | %% PDE Model Definition 25 | % 26 | 27 | rng('default'); % for reproducibility 28 | model = createpde(); 29 | geometryFromEdges(model,@circleg); 30 | applyBoundaryCondition(model,"dirichlet", ... 31 | "Edge",1:model.Geometry.NumEdges, ... 32 | "u",0); 33 | %% 34 | % Plot the geometry and display the edge labels for use in the boundary condition 35 | % definition. 36 | 37 | figure 38 | pdegplot(model,"EdgeLabels","on"); 39 | axis equal 40 | %% 41 | % Create a structural array of coefficents. Specify the coefficients to the 42 | % PDE model. Note that pdeCoeffs.c is an initial guess; it will be updated during 43 | % training. We also define pdeCoeffs to be a struct of dlarrays so that we can 44 | % compute gradients with respect to them. 45 | 46 | pdeCoeffs.c = .5; 47 | % fixed values for other coefficients 48 | pdeCoeffs.m = 0; 49 | pdeCoeffs.d = 0; 50 | pdeCoeffs.a = 0; 51 | pdeCoeffs.f = 1; 52 | % set up model 53 | specifyCoefficients(model,"m",pdeCoeffs.m,"d",pdeCoeffs.d,"c",pdeCoeffs.c,"a",pdeCoeffs.a,"f",pdeCoeffs.f); 54 | Hmax = 0.05; Hgrad = 2; Hedge = Hmax/10; 55 | msh = generateMesh(model,"Hmax",Hmax,"Hgrad",Hgrad,"Hedge",{1:model.Geometry.NumEdges,Hedge}); 56 | % make coefs dlarrays so gradients can be computed 57 | pdeCoeffs = structfun(@dlarray,pdeCoeffs,'UniformOutput',false); 58 | %% Generate Spatial Data for Training PINN 59 | % This examples uses mesh nodes as the collocation points. Model loss at the 60 | % collocation points on the domain and boundary are used to train the PINN. 61 | 62 | boundaryNodes = findNodes(msh,"region","Edge",1:model.Geometry.NumEdges); 63 | domainNodes = setdiff(1:size(msh.Nodes,2),boundaryNodes); 64 | domainCollocationPoints = msh.Nodes(:,domainNodes)'; 65 | %% Define Deep Learning Model 66 | % This is a neural network with 3 hidden layers and 50 neurons per layer. The 67 | % two inputs to the network correspond to the x and y coordinates, and the one 68 | % output corresponds to the solution, so |predict(pinn,XY)| appoximates |u(x,y)|. 69 | % While training the c coefficient, we will also train this neural network to 70 | % provide solutions to the PDE. 71 | 72 | numLayers = 3; 73 | numNeurons = 50; 74 | layers = featureInputLayer(2); 75 | for i = 1:numLayers-1 76 | layers = [ 77 | layers 78 | fullyConnectedLayer(numNeurons) 79 | tanhLayer];%#ok 80 | end 81 | layers = [ 82 | layers 83 | fullyConnectedLayer(1)]; 84 | pinn = dlnetwork(layers); 85 | %% Define Custom Training Loop to Train the PINN Using ADAM Solver 86 | % Specify training options. Create arrays for average gradients and square gradients 87 | % for both the PINN and the parameter; both will be trained using the ADAM solver. 88 | 89 | numEpochs = 1500; 90 | miniBatchSize = 2^12; 91 | initialLearnRate = 0.01; 92 | learnRateDecay = 0.001; 93 | averageGrad = []; % for pinn updates 94 | averageSqGrad = []; 95 | pAverageGrad = []; % for parameter updates 96 | pAverageSqGrad = []; 97 | %% 98 | % Setup data store for the training points. For simplicity, we both train the 99 | % PINN and compute the known data at the mesh nodes. 100 | 101 | ds = arrayDatastore(domainCollocationPoints); 102 | mbq = minibatchqueue(ds, MiniBatchSize = miniBatchSize, MiniBatchFormat="BC"); 103 | %% 104 | % Calculate the total number of iterations for the training progress monitor 105 | % and initialize the monitor. 106 | 107 | numIterations = numEpochs * ceil(size(domainCollocationPoints,1)/miniBatchSize); 108 | monitor = trainingProgressMonitor(Metrics="Loss",Info="Epoch",XLabel="Iteration"); 109 | %% Training Loop 110 | % Train the model and parameter using a custom training loop. Update the network 111 | % parameters using the adamupdate function. At the end of each iteration, display 112 | % the training progress. Note that we allow the PINN to be trained for 1/10th 113 | % of the epochs before updating the c coefficient. This helps with robustness 114 | % to the initial guess. 115 | 116 | iteration = 0; 117 | epoch = 0; 118 | learningRate = initialLearnRate; 119 | lossFcn = dlaccelerate(@modelLoss); 120 | while epoch < numEpochs && ~monitor.Stop 121 | epoch = epoch + 1; 122 | reset(mbq); 123 | while hasdata(mbq) && ~monitor.Stop 124 | iteration = iteration + 1; 125 | XY = next(mbq); 126 | % Evaluate the model loss and gradients using dlfeval. 127 | [loss,gradients] = dlfeval(lossFcn,model,pinn,XY,pdeCoeffs); 128 | % Update the network parameters using the adamupdate function. 129 | [pinn,averageGrad,averageSqGrad] = adamupdate(pinn,gradients{1},averageGrad,... 130 | averageSqGrad,iteration,learningRate); 131 | % Update the c coefficient using the adamupdate function. Defer 132 | % updating until 1/10 of epochs are finished. 133 | if epoch > numEpochs/10 134 | [pdeCoeffs.c,pAverageGrad,pAverageSqGrad] = adamupdate(pdeCoeffs.c,gradients{2},pAverageGrad,... 135 | pAverageSqGrad,iteration,learningRate); 136 | end 137 | end 138 | % Update learning rate. 139 | learningRate = initialLearnRate / (1+learnRateDecay*iteration); 140 | % Update the training progress monitor. 141 | recordMetrics(monitor,iteration,Loss=loss); 142 | updateInfo(monitor,Epoch=epoch + " of " + numEpochs); 143 | monitor.Progress = 100 * iteration/numIterations; 144 | end 145 | %% Visualize Data 146 | % Evaluate PINN at mesh nodes and plot, include updated value of c in title. 147 | % Note that c = 1.001, compared to the exact value of 1, this is a 0.1% error. 148 | 149 | nodesDLarry = dlarray(msh.Nodes,"CB"); 150 | Upinn = gather(extractdata(predict(pinn,nodesDLarry))); 151 | figure; 152 | pdeplot(model,"XYData",Upinn); 153 | title(sprintf("Solution with c = %.4f",double(pdeCoeffs.c))); 154 | %% 155 | % 156 | % 157 | % 158 | %% Model Loss Function 159 | % The |modelLoss| helper function takes a |dlnetwork| object |pinn| and a mini-batch 160 | % of input data |XY|, and returns the loss and the gradients of the loss with 161 | % respect to the learnable parameters in |pinn| and with respect to the c coefficient. 162 | % To compute the gradients automatically, use the |dlgradient| function. Return 163 | % the gradients w.r.t. learnable and w.r.t the parameter as two elements of a 164 | % cell array so they can be used separately. The model is trained by enforcing 165 | % that given an input $(x,y)$ the output of the network $u(x,y)$ satsifies Poisson's 166 | % equation and the boundary conditions. 167 | 168 | function [loss,gradients] = modelLoss(model,pinn,XY,pdeCoeffs) 169 | dim = 2; 170 | U = forward(pinn,XY); 171 | 172 | % Loss for difference in data taken at mesh nodes. 173 | Utrue = getSolutionData(XY); 174 | lossData = l2loss(U,Utrue); 175 | 176 | % Compute gradients of U and Laplacian of U. 177 | gradU = dlgradient(sum(U,"all"),XY,EnableHigherDerivatives=true); 178 | Laplacian = 0; 179 | for i=1:dim 180 | % Add each term of the Laplacian 181 | gradU2 = dlgradient(sum(pdeCoeffs.c.*gradU(i,:),"all"),XY,EnableHigherDerivatives=true); 182 | Laplacian = gradU2(i,:)+Laplacian; 183 | end 184 | 185 | % Enforce PDE. Calculate lossF. 186 | res = -pdeCoeffs.f - Laplacian + pdeCoeffs.a.*U; 187 | lossF = mean(sum(res.^2,1),2); 188 | 189 | % Enforce boundary conditions. Calculate lossU. 190 | actualBC = []; % contains the actual boundary information 191 | BC_XY = []; % boundary coordinates 192 | % Loop over the boundary edges and find boundary coordinates and actual BC 193 | % assigned to PDE model. 194 | numBoundaries = model.Geometry.NumEdges; 195 | for i=1:numBoundaries 196 | BCi = findBoundaryConditions(model.BoundaryConditions,'Edge',i); 197 | BCiNodes = findNodes(model.Mesh,"region","Edge",i); 198 | BC_XY = [BC_XY, model.Mesh.Nodes(:,BCiNodes)]; %#ok 199 | actualBCi = ones(1,numel(BCiNodes))*BCi.u; 200 | actualBC = [actualBC actualBCi]; %#ok 201 | end 202 | BC_XY = dlarray(BC_XY,"CB"); % format the coordinates 203 | predictedBC = forward(pinn,BC_XY); 204 | lossBC = mse(predictedBC,actualBC); 205 | 206 | % Combine weighted losses. 207 | lambdaPDE = 0.4; % weighting factor 208 | lambdaBC = 0.6; 209 | lambdaData = 0.5; 210 | loss = lambdaPDE*lossF + lambdaBC*lossBC + lambdaData*lossData; 211 | 212 | % Calculate gradients with respect to the learnable parameters and 213 | % C-coefficient. Pass back cell array to update pinn and coef separately. 214 | gradients = dlgradient(loss,{pinn.Learnables,pdeCoeffs.c}); 215 | end 216 | %% 217 | % 218 | % 219 | % 220 | %% Data Function 221 | % This function returns the solution data at a given set of points |XY|. As 222 | % a demonstration of the method, we return the exact solution from this function, 223 | % but this function could be replaced with measured data for a given application. 224 | 225 | function UD = getSolutionData(XY) 226 | UD = (1-XY(1,:).^2-XY(2,:).^2)/4; 227 | end 228 | %% 229 | % Copyright 2023 The MathWorks, Inc. -------------------------------------------------------------------------------- /src/InversePinnVariableCoef.m: -------------------------------------------------------------------------------- 1 | %% *Pinns for Inverse Problems : Variable Coefficients* 2 | % 3 | % 4 | % The Poisson equation on a unit disk with zero Dirichlet boundary condition 5 | % can be written as $$- \nabla \cdot (c\nabla u) = 1$$ in $\Omega$, $u = 0$ on 6 | % $\partial \Omega$, where $\Omega$ is the unit disk. The exact solution when 7 | % $c = 1$ is 8 | % 9 | % $$u(x,y)= \frac{1-x^2-y^2}{4}$$ 10 | % 11 | % This equation is relevant for example in therodynamics, where this describes 12 | % a steady state heat equation, with the boundary of the circle held at a constant 13 | % temperature of 0, the right hand side of the equation is a volumetric heat source, 14 | % and the coefficient $c$ is the thermal diffusivity. The typical "forward" problem 15 | % is to use this information to find u. 16 | % 17 | % One could consider the inverse problem: given a known temperature distribution 18 | % $u$ corresponding to the solution at a set of points, a known volumetric heat 19 | % source, and boundary conditions, what is the thermal diffusivity? Using a PINN 20 | % to solve the equation, we can optimize the PINN parameters and the optimize 21 | % to solve for the coefficient at the same time. In this exmaple, we will take 22 | % the data to be given by the exact solution above. In practice, the exact solution 23 | % is often not known, but measurements of the solution can be provided instead. 24 | % 25 | % If the coefficients are known to be a function of space or of the solution, 26 | % we can use a neural network to represent the coefficient, and train this neural 27 | % network alongside the PINN. 28 | %% PDE Model Definition 29 | % 30 | 31 | rng('default'); % for reproducibility 32 | model = createpde(); 33 | geometryFromEdges(model,@circleg); 34 | applyBoundaryCondition(model,"dirichlet", ... 35 | "Edge",1:model.Geometry.NumEdges, ... 36 | "u",0); 37 | %% 38 | % Plot the geometry and display the edge labels for use in the boundary condition 39 | % definition. 40 | 41 | figure 42 | pdegplot(model,"EdgeLabels","on"); 43 | axis equal 44 | %% 45 | % Create a structural array of coefficents. C is left empty; it will be approximated 46 | % using a neural network. 47 | 48 | pdeCoeffs.c = []; 49 | % fixed values for other coefficients 50 | pdeCoeffs.m = 0; 51 | pdeCoeffs.d = 0; 52 | pdeCoeffs.a = 0; 53 | pdeCoeffs.f = 1; 54 | % set up mesh 55 | Hmax = 0.05; Hgrad = 2; Hedge = Hmax/10; 56 | msh = generateMesh(model,"Hmax",Hmax,"Hgrad",Hgrad,"Hedge",{1:model.Geometry.NumEdges,Hedge}); 57 | % make coefs dlarrays so gradients can be computed 58 | pdeCoeffs = structfun(@dlarray,pdeCoeffs,'UniformOutput',false); 59 | %% Generate Spatial Data for Training PINN 60 | % This examples uses mesh nodes as the collocation points. Model loss at the 61 | % collocation points on the domain and boundary are used to train the PINN. For 62 | % simplicity, we will supply the true solution data at the same set of collocation 63 | % points where the PINN loss is computed, but this is not required. 64 | 65 | boundaryNodes = findNodes(msh,"region","Edge",1:model.Geometry.NumEdges); 66 | domainNodes = setdiff(1:size(msh.Nodes,2),boundaryNodes); 67 | domainCollocationPoints = msh.Nodes(:,domainNodes)'; 68 | %% Define Deep Learning Model 69 | % This is a neural network with 3 hidden layers and 50 neurons per layer. The 70 | % two inputs to the network correspond to the x and y coordinates, and the one 71 | % output corresponds to the solution, so |predict(pinn,XY)| appoximates |u(x,y)|. 72 | 73 | numLayers = 3; 74 | numNeurons = 50; 75 | layers = featureInputLayer(2); 76 | for i = 1:numLayers-1 77 | layers = [ 78 | layers 79 | fullyConnectedLayer(numNeurons) 80 | tanhLayer];%#ok 81 | end 82 | layers = [ 83 | layers 84 | fullyConnectedLayer(1)]; 85 | pinn = dlnetwork(layers); 86 | %% 87 | % Set up the coefficient network by copying the PINN so the two networks have 88 | % the same architecture. Here, the two inputs represent x and y and the one output 89 | % corresponds to the coefficient, so |predict(coefNet,XY)| appoximates |c(x,y)|. 90 | % If the problem was nonlinear and spatially dependent, |c = c(x,y,u)|, you could 91 | % add a third input and make the corresponding changes in the model loss function. 92 | % Because of the data that will be supplied to the network, we expect that coefNet 93 | % will learn |c(x,y) = 1| for all x and y. 94 | 95 | coefNet = pinn; 96 | %% 97 | % Put both networks in one struct. 98 | 99 | nets = struct(pinn=pinn,coefNet=coefNet); 100 | %% Define Custom Training Loop to Train the PINN Using ADAM Solver 101 | % Specify training options. Create arrays for average gradients and square gradients 102 | % for both the PINN and the parameter network; both will be trained using the 103 | % ADAM solver. 104 | 105 | numEpochs = 5000; 106 | miniBatchSize = 2^12; 107 | initialLearnRate = 0.02; 108 | learnRateDecay = 0.001; 109 | averageGrad = []; 110 | averageSqGrad = []; 111 | %% 112 | % Setup data store for the training points. As stated before, we both train 113 | % the PINN and compute the known data at the mesh nodes. 114 | 115 | ds = arrayDatastore(domainCollocationPoints); 116 | mbq = minibatchqueue(ds, MiniBatchSize = miniBatchSize, MiniBatchFormat="BC"); 117 | %% 118 | % Calculate the total number of iterations for the training progress monitor 119 | % and initialize the monitor. 120 | 121 | numIterations = numEpochs * ceil(size(domainCollocationPoints,1)/miniBatchSize); 122 | monitor = trainingProgressMonitor(Metrics="Loss",Info="Epoch",XLabel="Iteration"); 123 | %% Training Loop 124 | % Train the model and parameter network using a custom training loop. Update 125 | % the network parameters using the adamupdate function. At the end of each iteration, 126 | % display the training progress. 127 | 128 | epoch = 0; 129 | iteration = 0; 130 | learningRate = initialLearnRate; 131 | lossFcn = dlaccelerate(@modelLoss); 132 | while epoch < numEpochs && ~monitor.Stop 133 | epoch = epoch + 1; 134 | reset(mbq); 135 | while hasdata(mbq) && ~monitor.Stop 136 | iteration = iteration + 1; 137 | XY = next(mbq); 138 | % XY coordinates at which to get data 139 | XYData = XY; 140 | % Evaluate the model loss and gradients using dlfeval. 141 | [loss,gradients] = dlfeval(lossFcn,model,nets,XY,pdeCoeffs,XYData); 142 | % update the parameters of both networks 143 | [nets,averageGrad,averageSqGrad] = adamupdate(nets,gradients,averageGrad,... 144 | averageSqGrad,iteration,learningRate); 145 | end 146 | % Update learning rate. 147 | learningRate = initialLearnRate / (1+learnRateDecay*iteration); 148 | % Update the training progress monitor. 149 | recordMetrics(monitor,iteration,Loss=loss); 150 | updateInfo(monitor,Epoch=epoch + " of " + numEpochs); 151 | monitor.Progress = 100 * iteration/numIterations; 152 | end 153 | %% Visualize Data 154 | % Evaluate PINN and parameter network at mesh nodes and plot. Compute the maximum 155 | % error at collocation points for the predicted coefficient. 156 | 157 | nodesDLarry = dlarray(msh.Nodes,"CB"); 158 | Upinn = gather(extractdata(predict(nets.pinn,nodesDLarry))); 159 | figure(1); 160 | pdeplot(model,"XYData",Upinn); 161 | C = gather(extractdata(predict(nets.coefNet,nodesDLarry))); 162 | figure(2); 163 | pdeplot(model,"XYData",C); 164 | title(sprintf('Predicted coefficient max error: = %0.1e',max(abs(C-1)))) 165 | %% 166 | % 167 | % 168 | % 169 | %% Model Loss Function 170 | % The |modelLoss| helper function takes a |dlnetwork| object |pinn| and a mini-batch 171 | % of input data |XY|, and returns the loss and the gradients of the loss with 172 | % respect to the learnable parameters in |pinn| and with respect to the c coefficient. 173 | % To compute the gradients automatically, use the |dlgradient| function. Return 174 | % the gradients w.r.t. learnable and w.r.t the parameter network as two elements 175 | % of a cell array so they can be used separately. The model is trained by enforcing 176 | % that given an input $(x,y)$ the output of the network $u(x,y)$ satisfies Poisson's 177 | % equation and the boundary conditions. 178 | 179 | function [loss,gradients] = modelLoss(model,nets,XY,pdeCoeffs,XYData) 180 | dim = 2; 181 | U = forward(nets.pinn,XY); 182 | C = forward(nets.coefNet,XY); 183 | 184 | % Loss for difference in data taken at mesh nodes. 185 | UDPred = forward(nets.pinn,XYData); 186 | UData = getSolutionData(XYData); 187 | lossData = l2loss(UDPred,UData); 188 | 189 | % Compute gradients of U and Laplacian of U. 190 | gradU = dlgradient(sum(U,"all"),XY,EnableHigherDerivatives=true); 191 | Laplacian = 0; 192 | for i=1:dim 193 | % Add each term of the Laplacian 194 | gradU2 = dlgradient(sum(C.*gradU(i,:),"all"),XY,EnableHigherDerivatives=true); 195 | Laplacian = gradU2(i,:)+Laplacian; 196 | end 197 | 198 | % Enforce PDE. Calculate lossF. 199 | res = -pdeCoeffs.f - Laplacian + pdeCoeffs.a.*U; 200 | zeroTarget = zeros(size(res), "like", res); 201 | lossF = mse(res, zeroTarget); 202 | 203 | % Enforce boundary conditions. Calculate lossU. 204 | actualBC = []; % contains the actual boundary information 205 | BC_XY = []; % boundary coordinates 206 | % Loop over the boundary edges and find boundary coordinates and actual BC 207 | % assigned to PDE model. 208 | numBoundaries = model.Geometry.NumEdges; 209 | for i=1:numBoundaries 210 | BCi = findBoundaryConditions(model.BoundaryConditions,'Edge',i); 211 | BCiNodes = findNodes(model.Mesh,"region","Edge",i); 212 | BC_XY = [BC_XY, model.Mesh.Nodes(:,BCiNodes)]; %#ok 213 | actualBCi = ones(1,numel(BCiNodes))*BCi.u; 214 | actualBC = [actualBC actualBCi]; %#ok 215 | end 216 | BC_XY = dlarray(BC_XY,"CB"); % format the coordinates 217 | predictedBC = forward(nets.pinn,BC_XY); 218 | lossBC = mse(predictedBC,actualBC); 219 | 220 | % Combine weighted losses. 221 | lambdaPDE = 1.1; 222 | lambdaBC = 1.; 223 | lambdaData = 1.; 224 | loss = lambdaPDE*lossF + lambdaBC*lossBC + lambdaData*lossData; 225 | 226 | % Calculate gradients with respect to the learnable parameters and 227 | % C-coefficient. Return gradients as a struct in order to update them 228 | % simultaneously using adamupdate. 229 | grads = dlgradient(loss,{nets.pinn.Learnables,nets.coefNet.Learnables}); 230 | gradients.pinn = grads{1}; 231 | gradients.coefNet = grads{2}; 232 | end 233 | %% 234 | % 235 | % 236 | % 237 | %% Data Function 238 | % This function returns the solution data at a given set of points |XY|. As 239 | % a demonstration of the method, we return the exact soltuion from this function, 240 | % but this function could be replaced with measured data at the given set of points 241 | % for applications. 242 | 243 | function UD = getSolutionData(XY) 244 | UD = (1-XY(1,:).^2-XY(2,:).^2)/4; 245 | end 246 | %% 247 | % Copyright 2023 The MathWorks, Inc. --------------------------------------------------------------------------------