How to write a program for 2 D curvilinear interpolation? - 2d

2-D curvilinear interpolation
Apply the tensorization for 2-D Lagrangian interpolation of order 4 on a sinusoidal grid given by:
% Definition of sinusoidal grid
% -----------------------------
nx=41;
ny=41;
xmin=0;
ymin=0;
xmax=80;
ymax=80;
lx=xmax-xmin;
ly=ymax-ymin;
facteur=1.;
ax=2*facteur;
ay=2*facteur;
enex=4;
eney=4;
phix=0;
phiy=0;
omegatau=0.25;
deltax0=lx/(nx-1);
deltay0=ly/(ny-1);
for i=1:nx,
for j=1:ny,
xg(i,j) = xmin+deltax0*((i-1)+ax*sin(2.0*pi*omegatau)...
sin(enex*pi(j-1)deltay0/ly+iphix/(nx-1)));
yg(i,j) = ymin+deltay0*((j-1)+ay*sin(2.0*pi*omegatau)...
sin(eney*pi(i-1)deltax0/lx+jphiy/(ny-1)));
val(i,j)=1;
end
end
% Definition of a 2D Gaussian function (test function)
% ------------------------------------
alph=log(2)/10^2; % width of Gaussian
i0=20; % center of Gaussian
j0=20; % center of Gaussian
for i=1:nx
for j=1:ny
U2(i,j)=exp(-alph*((xg(i,j)-xg(i0,j0))^2+(yg(i,j)-yg(i0,j0))^2));
end
end
% Interpolation on NxN points -> order N
% --------------------------------------
% order
N=4;
% width of interpolation per direction
dw=N;
% degrees of freedom
dl=dw*dw;
% interpolation point at (xint,yint)
% ----------------------------------
ii=23;
ji=23;
xint=xg(ii,ji)+1;
yint=yg(ii,ji)+1;
Then find the location of the point to be interpolated in the computational space using the isoparametric mapping and 2-D Newton’s algorithm.

Related

Comparing the exact and an approximation of the CDF function with R command ecdf

I want to compute the exact and an approximation of the Cumulative Distribution Function for the following density :
f(x)= U(x;-1,2)/2 + U(x;0,1)/2
where U(.;a,b) is the uniform density function on the interval [a,b].
I know how to compute the exact expression of the CDF.
My problem is that I do not understand why my approximation provided by the R function ecdf is a very bad approximation of the exact CDF (see code below).
#density function
f = function(x){dunif(x,-1,2)/2+dunif(x)/2}
plot(f,-2,4)
#Approximation
xis = runif(1000000,-1,2)/2+runif(1000000)/2
Ffapp = ecdf(xis)
zs = seq(-1.2, 2.2, by=0.01)
Ffs = Ffapp(zs)
plot(zs,Ffs,type='l',col="red")
#exact expression
Ffexact = function(t){(t <= -1) * 0 +
(t>-1 & t<=0) * (t+1)/6 +
(t>0 & t<=1) * ((t+1)/6 + t/2) +
(t>1 & t<=2) * ((t+1)/6 + 1/2) +
(t>2) * 1}
curve(Ffexact,-2,3,add=TRUE)
legend(-1, 0.9, legend=c("Fapp", "Fexact"),col=c("red", "black"), lty=1:1)
How to explain the bad approximation of the CDF obtained with the ecdf command ?
EDIT: here is the plot.
We can see that the approximation is quite far from the exact expression. But more importantly I say it's a bad approximation because we do not have convergence of the red curve to the black curve when the size of the sample (argument of runif) tends to plus infinity. Mathematically we should have pointwise convergence of the two CDF.
The problem is in the way you generate your random sample xis. If we look at its histogram, we can see that the distribution doesn't follow your density. hist(xis):
xis are just random values, you don't want to divide them by 2 (this shrinks the distribution) and instead of summing, you need to concatenate the two vectors:
xis <- c(runif(1000000, -1, 2), runif(1000000))
Now the approximation fits perfectly:

how to express Chebyshev sequence constants for function approximations in an interval other than [-1,1]?

To approximate the function with Cheboshev polynomials, it is necessary to operate on the interval [-1,1]. How can these constants be recalculated if I want to approximate on another interval?
specifically, I use maple and the following loop:
(https://i.stack.imgur.com/TWT74.png)
but I don't know how to modify the function to calculate in an interval, for example [-pi,pi]
If you have a function f(x) defined on [-pi, pi] then you can transform it to a function g(u) on [-1, 1] by a linear change of variable:
u = -1 + 2 * (x + pi) / (2*pi).
Then you can approximate g by a polynomial P(u), and then transform P(u) to the polynomial Q(x) by the inverse change of variables:
x = -pi + (2*pi) * (u + 1) / 2.

Solve the Heat Equation with non-zero Dirichlet BCs with Implicit Euler and Conjugate Gradient Linear Solvers?

Many users have asked how to solve the Heat Equation, u_t = u_xx, with non-zero Dirichlet BCs and with conjugate gradients for the internal linear solver. This is a common simplified PDE problem before moving to more difficult versions of parabolic PDEs. How is this done in DifferentialEquations.jl?
Let's solve this problem in steps. First, let's build the linear operator for the discretized Heat Equation with Dirichlet BCs. A discussion of the discretization can be found on this Wiki page which shows that the central difference method gives a 2nd order discretization of the second derivative by (u[i-1] - 2u[i] + u[i+1])/dx^2. This is the same as multiplying by the Tridiagonal matrix of [1 -2 1]*(1/dx^2), so let's start by building this matrix:
using LinearAlgebra, OrdinaryDiffEq
x = collect(-π : 2π/511 : π)
## Dirichlet 0 BCs
u0 = #. -(x).^2 + π^2
n = length(x)
A = 1/(2π/511)^2 * Tridiagonal(ones(n-1),-2ones(n),ones(n-1))
Notice that we have implicitly simplified the end, since (u[0] - 2u[1] + u[2])/dx^2 = (- 2u[1] + u[2])/dx^2 when the left BC is zero, so the term is dropped from the matmul. We then use this discretization of the derivative to solve the Heat Equation:
function f(du,u,A,t)
mul!(du,A,u)
end
prob = ODEProblem(f,u0,(0.0,10.0),A)
sol = solve(prob,ImplicitEuler())
using Plots
plot(sol[1])
plot!(sol[end])
Now we make the BCs non-zero. Notice that we just have to add back the u[0]/dx^2 that we previously dropped off, so we have:
## Dirichlet non-zero BCs
## Note that the operator is no longer linear
## To handle affine BCs, we add the dropped term
u0 = #. (x - 0.5).^2 + 1/12
n = length(x)
A = 1/(2π/511)^2 * Tridiagonal(ones(n-1),-2ones(n),ones(n-1))
function f(du,u,A,t)
mul!(du,A,u)
# Now do the affine part of the BCs
du[1] += 1/(2π/511)^2 * u0[1]
du[end] += 1/(2π/511)^2 * u0[end]
end
prob = ODEProblem(f,u0,(0.0,10.0),A)
sol = solve(prob,ImplicitEuler())
plot(sol[1])
plot!(sol[end])
Now let's swap out the linear solver. The documentation suggests that you should use LinSolveCG here, which looks like:
sol = solve(prob,ImplicitEuler(linsolve=LinSolveCG()))
There are some advantages to this, since it has a norm handling that helps conditioning. Howerver, the documentation also states that you can build your own linear solver routine. This is done by giving a Val{:init} dispatch that returns the type to use as the linear solver, so we do:
## Create a linear solver for CG
using IterativeSolvers
function linsolve!(::Type{Val{:init}},f,u0;kwargs...)
function _linsolve!(x,A,b,update_matrix=false;kwargs...)
cg!(x,A,b)
end
end
sol = solve(prob,ImplicitEuler(linsolve=linsolve!))
plot(sol[1])
plot!(sol[end])
And there we are, non-zero Dirichlet Heat Equation with a Krylov method (conjugate gradients) for the linear solver, making it a Newton-Krylov method.

SVM: Why is Maximize margin == minimize Euclidean norm?

In the SVM opimization problem, we either want to maximise the margin of 2/||w||,
or minimise the Euclidean Norm of weight vector w:
(1/2)*w^t*w
Can somebody explain to me why the Euclidean Norm is the formula above? And not 1/sqrt(w^t*w)?
I assume euclidean norm is the Euclidean distance, how do we get to that formula?
The reason is that the following three are equivalent (under suitable mathematical conditions which are usually met):
Maximize a quantity z.
Maximize f(z), where f is a strictly growing function.
Minimize g(z), where g is a strictly decreasing function.
In your case, set z=||w||, and apply the above the other way round. Then minimizing||w|| is equivalent to minimizing f(z) = 1/2 ||w||^2, and to maximizing g(z) = 2/||w||.
We have two boundaries 𝑤⋅𝑥+𝑏=1 and 𝑤⋅𝑥+𝑏=−1 and a middle one which is 𝑤⋅𝑥+𝑏=0. Now we want to figure out the distance between each of these two lines with the middle one. If we call the distance 𝜆.
We consider a point z on 𝑤⋅𝑥+𝑏=1, then setting this point z as the origin, the point on 𝑤⋅𝑥+𝑏=0 would be 𝑧−𝜆⋅𝑤||𝑤||, here, the distance between the middle line and 𝑤⋅𝑥+𝑏=1 is the distance between z and 𝑧−𝜆⋅𝑤||𝑤||
now since this point is on 𝑤⋅𝑥+𝑏=0, we would have:
𝑤⋅(𝑧−𝜆⋅𝑤 / ||𝑤||)+𝑏 = 0
𝑤⋅𝑧+𝑏 −𝑤⋅𝜆⋅𝑤 / ||𝑤|| = 0
we know that since z is located on 𝑤⋅𝑥+𝑏=1, then 𝑤⋅𝑧+𝑏 equals 1, hence:
1 −𝑤⋅𝜆⋅𝑤 / ||𝑤|| = 0
𝑤⋅𝜆⋅𝑤 / ||𝑤|| = 1
𝜆 ⋅ ||𝑤||^2 / ||𝑤|| = 1
𝜆 ⋅ ||𝑤|| = 1
𝜆 = 1/||𝑤||

Fast, inaccurate sin function without lookup

For an ocean shader, I need a fast function that computes a very approximate value for sin(x). The only requirements are that it is periodic, and roughly resembles a sine wave.
The taylor series of sin is too slow, since I'd need to compute up to the 9th power of x just to get a full period.
Any suggestions?
EDIT: Sorry I didn't mention, I can't use a lookup table since this is on the vertex shader. A lookup table would involve a texture sample, which on the vertex shader is slower than the built in sin function.
It doesn't have to be in any way accurate, it just has to look nice.
Use a Chebyshev approximation for as many terms as you need. This is particularly easy if your input angles are constrained to be well behaved (-π .. +π or 0 .. 2π) so you do not have to reduce the argument to a sensible value first. You might use 2 or 3 terms instead of 9.
You can make a look-up table with sin values for some values and use linear interpolation between that values.
A rational algebraic function approximation to sin(x), valid from zero to π/2 is:
f = (C1 * x) / (C2 * x^2 + 1.)
with the constants:
c1 = 1.043406062
c2 = .2508691922
These constants were found by least-squares curve fitting. (Using subroutine DHFTI, by Lawson & Hanson).
If the input is outside [0, 2π], you'll need to take x mod 2 π.
To handle negative numbers, you'll need to write something like:
t = MOD(t, twopi)
IF (t < 0.) t = t + twopi
Then, to extend the range to 0 to 2π, reduce the input with something like:
IF (t < pi) THEN
IF (t < pi/2) THEN
x = t
ELSE
x = pi - t
END IF
ELSE
IF (t < 1.5 * pi) THEN
x = t - pi
ELSE
x = twopi - t
END IF
END IF
Then calculate:
f = (C1 * x) / (C2 * x*x + 1.0)
IF (t > pi) f = -f
The results should be within about 5% of the real sine.
Well, you don't say how accurate you need it to be. The sine can be approximated by straight lines of slopes 2/pi and -2/pi on intervals [0, pi/2], [pi/2, 3*pi/2], [3*pi/2, 2*pi]. This approximation can be had for the cost of a multiplication and an addition after reducing the angle mod 2*pi.
Using a lookup table is probably the best way to control the tradeoff between speed and accuracy.

Resources