agd.ExportedCode.Notebooks_FMM.BoatRouting
1# Code automatically exported from notebook BoatRouting.ipynb in directory Notebooks_FMM 2# Do not modify 3import sys; sys.path.insert(0,"..") # Allow import of agd from parent directory (useless if conda package installed) 4#from Miscellaneous import TocTools; print(TocTools.displayTOC('BoatRouting','FMM')) 5 6from ... import Eikonal 7from ... import LinearParallel as lp 8from ... import FiniteDifferences as fd 9from agd.Metrics import Rander,Riemann 10from ... import AutomaticDifferentiation as ad 11from agd.Plotting import savefig,quiver; #savefig.dirName = 'Images/BoatRouting' 12 13import numpy as np; xp = np 14from copy import copy 15import matplotlib.pyplot as plt 16 17def route_min(z,params): 18 z,μ,ω,M = fd.common_field((z,)+params, depths=(1,0,1,2)) 19 z_norm = np.sqrt(lp.dot_VAV(z,M,z)) 20 μω_norm = np.sqrt( 2*μ +lp.dot_VAV(ω,M,ω) ) 21 cost = z_norm*μω_norm - lp.dot_VAV(z,M,ω) 22 time = z_norm / μω_norm 23 fuel = cost/time 24 rvel = z/time - ω 25 return { 26 'cost':cost, # minimal cost for this travel 27 'time':time, # optimal travel time 28 'fuel':fuel, # instantaneous fuel consumption 29 'rvel':rvel, # relative velocity, w.r.t current 30 } 31 32def metric(params): 33 μ,ω,M = fd.common_field(params,depths=(0,1,2)) 34 return Rander( M*(2*μ + lp.dot_VAV(ω,M,ω)), -lp.dot_AV(M,ω)) 35 36def Spherical(θ,ϕ): 37 """Spherical embedding: θ is longitude, ϕ is latitude from equator toward pole""" 38 return (np.cos(θ)*np.cos(ϕ), np.sin(θ)*np.cos(ϕ), np.sin(ϕ)) 39 40def IntrinsicMetric(Embedding,*X): 41 """Riemannian metric for a manifold embedded in Euclidean space""" 42 X_ad = ad.Dense.identity(constant=X,shape_free=(2,)) # First order dense AD variable 43 Embed_ad = ad.asarray(Embedding(*X_ad)) # Differentiate the embedding 44 Embed_grad = Embed_ad.gradient() 45 Embed_M = lp.dot_AA(Embed_grad,lp.transpose(Embed_grad)) # Riemannian metric 46 return Embed_M 47 48def bump(x,y): 49 """Gaussian-like bump (not normalized)""" 50 return np.exp(-(x**2+y**2)/2) 51 52def Currents(θ,ϕ): 53 """Some arbitrary vector field (water currents)""" 54 bump0 = bump(θ+1,(ϕ+0.3)*2); ω0=(0,1) # intensity and direction of the currents 55 bump1 = 2*bump(2*(θ-0.7),ϕ-0.2); ω1=(1,-1) 56 bump0,ω0,bump1,ω1 = fd.common_field( (bump0,ω0,bump1,ω1), depths=(0,1,0,1)) 57 return bump0*ω0+bump1*ω1 58 59def ArrivalTime(hfmIn,params): 60 hfmIn = copy(hfmIn) 61# if hfmIn.xp is not np: hfmIn['solver']='AGSI' #TODO : why needed ? 62 hfmIn['metric'] = metric(params) 63 hfmIn['exportGeodesicFlow']=1 64 cache = Eikonal.Cache(needsflow=True) 65 hfmOut = hfmIn.Run(cache=cache) 66 67 flow = hfmOut['flow'] 68 no_flow = np.all(flow==0,axis=0) 69 flow[:,no_flow]=np.nan # No flow at the seed point, avoid zero divide 70 route = route_min(flow,params) 71 costVariation = route['time'] 72 costVariation[no_flow] = 0 73 hfmIn['costVariation'] = np.expand_dims(costVariation,axis=-1) 74 75 hfmOut2 = hfmIn.Run(cache=cache) # cache avoids some recomputations 76 time = hfmOut2['values'].gradient(0) 77 return time,hfmOut
def
route_min(z, params):
18def route_min(z,params): 19 z,μ,ω,M = fd.common_field((z,)+params, depths=(1,0,1,2)) 20 z_norm = np.sqrt(lp.dot_VAV(z,M,z)) 21 μω_norm = np.sqrt( 2*μ +lp.dot_VAV(ω,M,ω) ) 22 cost = z_norm*μω_norm - lp.dot_VAV(z,M,ω) 23 time = z_norm / μω_norm 24 fuel = cost/time 25 rvel = z/time - ω 26 return { 27 'cost':cost, # minimal cost for this travel 28 'time':time, # optimal travel time 29 'fuel':fuel, # instantaneous fuel consumption 30 'rvel':rvel, # relative velocity, w.r.t current 31 }
def
metric(params):
def
Spherical(θ, φ):
37def Spherical(θ,ϕ): 38 """Spherical embedding: θ is longitude, ϕ is latitude from equator toward pole""" 39 return (np.cos(θ)*np.cos(ϕ), np.sin(θ)*np.cos(ϕ), np.sin(ϕ))
Spherical embedding: θ is longitude, ϕ is latitude from equator toward pole
def
IntrinsicMetric(Embedding, *X):
41def IntrinsicMetric(Embedding,*X): 42 """Riemannian metric for a manifold embedded in Euclidean space""" 43 X_ad = ad.Dense.identity(constant=X,shape_free=(2,)) # First order dense AD variable 44 Embed_ad = ad.asarray(Embedding(*X_ad)) # Differentiate the embedding 45 Embed_grad = Embed_ad.gradient() 46 Embed_M = lp.dot_AA(Embed_grad,lp.transpose(Embed_grad)) # Riemannian metric 47 return Embed_M
Riemannian metric for a manifold embedded in Euclidean space
def
bump(x, y):
Gaussian-like bump (not normalized)
def
Currents(θ, φ):
53def Currents(θ,ϕ): 54 """Some arbitrary vector field (water currents)""" 55 bump0 = bump(θ+1,(ϕ+0.3)*2); ω0=(0,1) # intensity and direction of the currents 56 bump1 = 2*bump(2*(θ-0.7),ϕ-0.2); ω1=(1,-1) 57 bump0,ω0,bump1,ω1 = fd.common_field( (bump0,ω0,bump1,ω1), depths=(0,1,0,1)) 58 return bump0*ω0+bump1*ω1
Some arbitrary vector field (water currents)
def
ArrivalTime(hfmIn, params):
60def ArrivalTime(hfmIn,params): 61 hfmIn = copy(hfmIn) 62# if hfmIn.xp is not np: hfmIn['solver']='AGSI' #TODO : why needed ? 63 hfmIn['metric'] = metric(params) 64 hfmIn['exportGeodesicFlow']=1 65 cache = Eikonal.Cache(needsflow=True) 66 hfmOut = hfmIn.Run(cache=cache) 67 68 flow = hfmOut['flow'] 69 no_flow = np.all(flow==0,axis=0) 70 flow[:,no_flow]=np.nan # No flow at the seed point, avoid zero divide 71 route = route_min(flow,params) 72 costVariation = route['time'] 73 costVariation[no_flow] = 0 74 hfmIn['costVariation'] = np.expand_dims(costVariation,axis=-1) 75 76 hfmOut2 = hfmIn.Run(cache=cache) # cache avoids some recomputations 77 time = hfmOut2['values'].gradient(0) 78 return time,hfmOut