How can I convert latitude-longitude to ease grid of NASA? - r

I am working with he5 files downloaded from nasa eosdis. I successfully read the files using rhdf5 package in r. The hdf file has subdatasets consist of a matrix, dim 721 x 721.
As far as I understand the file is built as easegrid which does not have any info about the coordinates, so i cannot find in which grid (element in the matrix) my workplace is.
Is there any way to convert latitude longitude values to ease grid?
thank you so much

I've found a python software which capable of doing several conversions between different cartography systems on Brigham Young University's FTP server.
You would probably want to use ease2grid function in this file.
I've also fixed several linting issue on the file. Here is the file;
"""
Created on Sep 21, 2011
Revised on Apr 7, 2017 + include EASE2 support
#author: Bradley, DGL
"""
from __future__ import division
from numpy import cos, sin, tan, mod, sqrt, all
import numpy as np
from .ease2helper import ease2_map_info, easeconv_normalize_degrees
def latlon2pix(alon, alat, head):
"""Latitude/longitude to pixels
(x, y) = latlon2pix(lon,lat,head)
Convert a lat,lon coordinate (lon,lat) to an image pixel location
(x,y) (in floating point, matlab convention).
To compute integer pixel indices (ix,iy): check to insure
1 <= x < nsx+1 and 1 <= x < nsx+1 then ix=floor(x) iy=floor(y)
INPUTS:
lon,lat - longitude, latitude
head - header array from load sir
OUTPUTS:
x,y - pixel location (matlab coordinates y_matlab=nxy-y_sir+1)
"""
nsx = head[0] # noqa: F841
nsy = head[1]
iopt = head[16]
xdeg = head[2]
ydeg = head[3]
ascale = head[5]
bscale = head[6]
a0 = head[7]
b0 = head[8]
if iopt == -1: # image only (can't transform!)
x = ascale * (alon - a0)
y = bscale * (alat - b0)
elif iopt == 0: # rectalinear lat/lon
thelon = alon
thelat = alat
x = ascale * (thelon - a0)
y = bscale * (thelat - b0)
elif (iopt == 1) or (iopt == 2): # lambert
thelon, thelat = lambert1(alat, alon, ydeg, xdeg, iopt)
x = ascale * (thelon - a0)
y = bscale * (thelat - b0)
elif iopt == 5: # polar stereographic
thelon, thelat = polster(alon, alat, xdeg, ydeg)
x = (thelon - a0) / ascale
y = (thelat - b0) / bscale
elif (iopt == 8) or (iopt == 9) or (iopt == 10): # EASE2
thelon, thelat = ease2grid(iopt, alat, alon, ascale, bscale)
x = thelon + 1.0 - a0
y = thelat + 1.0 + b0
elif (iopt == 11) or (iopt == 12) or (iopt == 13): # EASE
thelon, thelat = easegrid(iopt, alat, alon, ascale)
thelon = thelon + xdeg
thelat = thelat + ydeg
x = thelon - (xdeg + a0)
y = thelat - (ydeg + b0)
else:
print("*** Unknown SIR transformation: %d" % iopt)
y = nsy - y - 1.0 # convert from matlab coordinates to SIR coordinates
return x, y
def lambert1(lat, lon, orglat, orglon, iopt):
"""Lambert azimuthal equal-area projection
(x,y)=lambert1(lat,lon,orglat,orglon,iopt)
Computes the transformation from lat/lon to x/y for the
lambert azimuthal equal-area projection
inputs:
lat (r): latitude +90 to -90 deg with north positive
lon (r): longitude 0 to +360 deg with east positive
or -180 to +180 with east more positive
orglat (r): origin parallel +90 to -90 deg with north positive
orglon (r): central meridian (longitude) 0 to +360 deg
or -180 to +180 with east more positive
iopt (i): earth radius option
for iopt=1 a fixed, nominal earth radius is used.
for iopt=2 the local radius of the earth is used.
outputs:
x,y (r): rectangular coordinates in km
see "map projections used by the u.s. geological survey"
geological survey bulletin 1532, pgs 157-173
for this routine, a spherical earth is assumed for the projection
the 1972 wgs ellipsoid model (bulletin pg 15).
the error will be small for small-scale maps.
"""
radearth = 6378.135 # equitorial earth radius
f = 298.26 # 1/f wgs 72 model values
dtr = 3.141592654 / 180.0
lon1 = mod(lon + 720.0, 360.0)
orglon1 = mod(orglon + 720.0, 360.0)
#
# compute local radius of the earth at center of image
#
eradearth = 6378.0 # use fixed nominal value
if iopt == 2: # local radius
era = 1.0 - 1.0 / f
eradearth = (
radearth
* era
/ sqrt(era * era * cos(orglat * dtr) ** 2 + sin(orglat * dtr) ** 2)
)
denom = (
1.0
+ sin(orglat * dtr) * sin(lat * dtr)
+ cos(orglat * dtr) * cos(lat * dtr) * cos(dtr * (lon1 - orglon1))
)
if all(denom > 0.0):
ak = sqrt(2.0 / denom)
else:
print("*** division error in lambert1 routine ***")
ak = 1.0
x = ak * cos(lat * dtr) * sin(dtr * (lon1 - orglon1))
y = ak * (
cos(dtr * orglat) * sin(dtr * lat)
- sin(dtr * orglat) * cos(dtr * lat) * cos(dtr * (lon1 - orglon1))
)
x = x * eradearth
y = y * eradearth
return x, y
def polster(alon, alat, xlam, slat):
"""Polar stereographic trasnformation
(x,y)=polster(lon,lat,xlam,slat)
computes the polar sterographic transformation for a lon,lat
input of (alon,alat) with reference origin lon,lat=(xlam,slat).
output is (x,y) in km
algorithm is the same as used for processing ers-1 sar images
as received from m. drinkwater (1994)
"""
# ported from polster.m by JPB 21 Sept 2011
e2 = 0.006693883
re = 6378.273
dtr = 3.141592654 / 180.0
e = sqrt(e2)
if slat < 0:
sn = -1.0
rlat = -alat
else:
sn = 1.0
rlat = alat
t = ((1.0 - e * sin(rlat * dtr)) / (1.0 + e * sin(rlat * dtr))) ** (e * 0.5)
ty = tan(dtr * (45.0 - 0.5 * rlat)) / t
if slat < 0:
rlat = -slat
else:
rlat = slat
t = ((1.0 - e * sin(dtr * rlat)) / (1.0 + e * sin(dtr * rlat))) ** (e * 0.5)
tx = tan(dtr * (45.0 - 0.5 * rlat)) / t
cm = cos(dtr * rlat) / sqrt(1.0 - e2 * sin(dtr * rlat) ** 2)
rho = re * cm * ty / tx
x = (sn * sin(dtr * (sn * alon - xlam))) * rho
y = -(sn * cos(dtr * (sn * alon - xlam))) * rho
return x, y
def easegrid(iopt, alat, alon, ascale):
"""EASE grid transformation
(thelon thelat)=easegrid(iopt,lat,lon,ascale)
computes the forward "ease" grid transform
given a lat,lon (alat,alon) and the scale (ascale) the image
transformation coordinates (thelon,thelat) are comuted
using the "ease grid" (version 1.0) transformation given in fortran
source code supplied by nsidc.
the radius of the earth used in this projection is imbedded into
ascale while the pixel dimension in km is imbedded in bscale
the base values are: radius earth= 6371.228 km
pixel dimen =25.067525 km
then, bscale = base_pixel_dimen
ascale = radius_earth/base_pixel_dimen
iopt is ease type: iopt=11=north, iopt=12=south, iopt=13=cylindrical
"""
# ported from easegrid.m by JPB 21 Sept 2011
pi2 = np.pi / 2.0
dtr = pi2 / 90.0
if iopt == 11: # ease grid north
thelon = ascale * sin(alon * dtr) * sin(dtr * (45.0 - 0.5 * alat))
thelat = ascale * cos(alon * dtr) * sin(dtr * (45.0 - 0.5 * alat))
elif iopt == 12: # ease grid south
thelon = ascale * sin(alon * dtr) * cos(dtr * (45.0 - 0.5 * alat))
thelat = ascale * cos(alon * dtr) * cos(dtr * (45.0 - 0.5 * alat))
elif iopt == 13: # ease cylindrical
thelon = ascale * pi2 * alon * cos(30.0 * dtr) / 90.0
thelat = ascale * sin(alat * dtr) / cos(30.0 * dtr)
return thelon, thelat
def ease2grid(iopt, alat, alon, ascale, bscale):
"""EASE2 grid transformation
(thelon thelat)=ease2grid(iopt,lat,lon,ascale,bscale)
given a lat,lon (alat,alon) and the scale (ascale) the image
transformation coordinates (thelon,thelat) are comuted
using the "ease2 grid" (version 2.0) transformation given in IDL
source code supplied by MJ Brodzik
RADIUS EARTH=6378.137 KM (WGS 84)
MAP ECCENTRICITY=0.081819190843 (WGS84)
inputs:
iopt: projection type 8=EASE2 N, 9-EASE2 S, 10=EASE2 T/M
alon, alat: lon, lat (deg) to convert (can be outside of image)
ascale and bscale should be integer valued)
ascale: grid scale factor (0..5) pixel size is (bscale/2^ascale)
bscale: base grid scale index (ind=int(bscale))
see ease2helper.py for definitions of isc and ind
outputs:
thelon: X coordinate in pixels (can be outside of image)
thelat: Y coordinate in pixels (can be outside of image)
"""
DTR = 0.01745329241994
ind = round(bscale)
isc = round(ascale)
dlon = alon
phi = DTR * alat
lam = dlon
# get base EASE2 map projection parameters
(
map_equatorial_radius_m,
map_eccentricity,
e2,
map_reference_latitude,
map_reference_longitude,
map_second_reference_latitude,
sin_phi1,
cos_phi1,
kz,
map_scale,
bcols,
brows,
r0,
s0,
epsilon,
) = ease2_map_info(iopt, isc, ind)
dlon = dlon - map_reference_longitude
dlon = easeconv_normalize_degrees(dlon)
lam = DTR * dlon
sin_phi = np.sin(phi)
q = (1.0 - e2) * (
(sin_phi / (1.0 - e2 * sin_phi * sin_phi))
- (1.0 / (2.0 * map_eccentricity))
* np.log(
(1.0 - map_eccentricity * sin_phi) / (1.0 + map_eccentricity * sin_phi)
)
)
if iopt == 8: # EASE2 grid north
qp = 1.0 - (
(1.0 - e2)
/ (2.0 * map_eccentricity)
* np.log((1.0 - map_eccentricity) / (1.0 + map_eccentricity))
)
rho = map_equatorial_radius_m * np.sqrt(qp - q)
if np.size(rho) > 1:
rho[np.abs(qp - q) < epsilon] = 0.0
else:
if np.abs(qp - q) < epsilon:
rho = 0
x = rho * np.sin(lam)
y = -rho * np.cos(lam)
elif iopt == 9: # EASE2 grid south
qp = 1.0 - (
(1.0 - e2)
/ (2.0 * map_eccentricity)
* np.log((1.0 - map_eccentricity) / (1.0 + map_eccentricity))
)
rho = map_equatorial_radius_m * np.sqrt(qp + q)
if np.size(rho) > 1:
rho[np.abs(qp - q) < epsilon] = 0.0
else:
if np.abs(qp - q) < epsilon:
rho = 0
x = rho * np.sin(lam)
y = rho * np.cos(lam)
elif iopt == 10: # EASE2 cylindrical
x = map_equatorial_radius_m * kz * lam
y = (map_equatorial_radius_m * q) / (2.0 * kz)
else:
print("*** invalid EASE2 projection specificaion in ease2grid")
thelon = r0 + (x / map_scale) + 0.5
thelat = s0 + (y / map_scale) + 0.5
return (thelon, thelat)
This piece of Python code depends on another python code called ease2helper. Which I've found that on the same FTP server.
I've also fixed several linting issues on this file too. Here is ease2helper code;
#!/usr/bin/env python
""" EASE2 grid helper utility functions for sirpy"""
######
# Imports
######
from __future__ import division
import numpy as np
##############################
# The EASE2 helper functions
##############################
def easeconv_normalize_degrees(dlon):
#
# Return dlon to within the range -180 <= dlon <= 180
# can handle array inputs
#
out = dlon
if np.size(out) > 1:
while (out < -180.0).sum() > 0:
out[out < -180.0] = out[out > 180.0] + 360.0
while (out > 180.0).sum() > 0:
out[out > 180.0] = out[out > 180.0] - 360.0
else:
while out < -180.0:
out = out + 360.0
while out > 180.0:
out = out - 360.0
return out
def ease2_map_info(iopt, isc, ind):
""" internally used routine
(map_equatorial_radius_m, map_eccentricity, \
e2, map_reference_latitude, map_reference_longitude, \
map_second_reference_latitude, sin_phi1, cos_phi1, kz, \
map_scale, bcols, brows, r0, s0, epsilon) = ease2_map_info(iopt, isc, nd)
defines EASE2 grid information
inputs:
iopt: projection type 8=EASE2 N, 9=EASE2 S, 10=EASE2 T/M
isc: scale factor 0..5 grid size is (basesize(ind))/2^isc
ind: base grid size index (map units per cell in m
NSIDC .grd file for isc=0
project type ind=0 ind=1 ind=2 ind=3
N EASE2_N25km EASE2_N30km EASE2_N36km EASE2_N24km
S EASE2_S25km EASE2_S30km EASE2_S36km EASE2_S24km
T/M EASE2_T25km EASE2_M25km EASE2_M36km EASE2_M24km
cell size (m) for isc=0 (scale is reduced by 2^isc)
project type ind=0 ind=1 ind=2 ind=3
N 25000.0 30000.0 36000.0 24000.0
S 25000.0 30000.0 36000.0 24000.0
T/M T25025.26 M25025.26000 M36032.220840584 M24021.480560389347
for a given base cell size (e.g., ind=0) isc is related to
NSIDC CETB .grd file names according to
isc N .grd name S .grd name T .grd name
0 EASE2_N25km EASE2_S25km EASE2_T25km
1 EASE2_N12.5km EASE2_S12.5km EASE2_T12.5km
2 EASE2_N6.25km EASE2_S6.25km EASE2_T6.25km
3 EASE2_N3.125km EASE2_S3.125km EASE2_T3.125km
4 EASE2_N1.5625km EASE2_S1.5625km EASE2_T1.5625km
outputs
map_equatorial_radius_m EASE2 Earth equitorial radius (km) [WGS84]
map_eccentricity EASE2 Earth eccentricity [WGS84]
map_reference_latitude Reference latitude (deg)
map_reference_longitude Reference longitude (deg)
map_second_reference_latitude Secondary reference longitude* (deg)
sin_phi1, cos_phi1 kz EASE2 Cylin parameters*
map_scale EASE2 map projection pixel size (km)
bcols, brows, EASE2 grid size in pixels
r0, s0 EASE2 base projection size in pixels
epsilon EASE2 near-polar test factor
"""
DTR = 0.01745329241994
m = 2 ** np.floor(isc) # compute power-law scale factor
map_equatorial_radius_m = 6378137.0 # WGS84
map_eccentricity = 0.081819190843 # WGS84
e2 = map_eccentricity * map_eccentricity
map_reference_longitude = 0.0
epsilon = 1.0e-6
# map-specific parameters
if iopt == 8: # EASE2 grid north
map_reference_latitude = 90.0
if ind == 1: # EASE2_N30km.gpd
base = 30000.0
nx = 600
ny = 600
elif ind == 2: # EASE2_N36km.gpd
base = 36000.0
nx = 500
ny = 500
elif ind == 3: # EASE2_N24km.gpd
base = 24000.0
nx = 750
ny = 750
else: # EASE2_N25km.gpd
base = 25000.0
nx = 720
ny = 720
map_second_reference_latitude = 0.0
sin_phi1 = 0.0
cos_phi1 = 1.0
kz = cos_phi1
elif iopt == 9: # EASE2 grid south
map_reference_latitude = -90.0
if ind == 1: # EASE2_S30km.gpd
base = 30000.0
nx = 600
ny = 600
elif ind == 2: # EASE2_S36km.gpd
base = 36000.0
nx = 500
ny = 500
elif ind == 3: # EASE2_S24km.gpd
base = 24000.0
nx = 750
ny = 750
else: # EASE2_S25km.gpd
base = 25000.0
nx = 720
ny = 720
map_second_reference_latitude = 0.0
sin_phi1 = 0.0
cos_phi1 = 1.0
kz = cos_phi1
elif iopt == 10: # EASE2 cylindrical
map_reference_latitude = 0.0
map_second_reference_latitude = 30.0
sin_phi1 = np.sin(DTR * map_second_reference_latitude)
cos_phi1 = np.cos(DTR * map_second_reference_latitude)
kz = cos_phi1 / np.sqrt(1.0 - e2 * sin_phi1 * sin_phi1)
if ind == 1: # EASE2_M25km.gpd
base = 25025.26000
nx = 1388
ny = 584
elif ind == 2: # EASE2_M36km.gpd
base = 36032.220840584
nx = 964
ny = 406
elif ind == 3: # EASE2_M24km.gpd
base = 24021.480560389347
nx = 1446
ny = 609
else: # EASE2_T25km.gpd
base = 25025.26000
nx = 1388
ny = 540
else:
print("*** invalid EASE2 projection code ***")
# grid info
if isc >= 0:
map_scale = base / m
bcols = np.ceil(nx * m)
brows = np.ceil(ny * m)
r0 = (nx * m - 1) / 2
s0 = (ny * m - 1) / 2
else:
map_scale = base * m
bcols = np.ceil(nx / np.float(m))
brows = np.ceil(ny / np.float(m))
r0 = (nx / np.float(m) - 1) / 2
s0 = (ny / np.float(m) - 1) / 2
return (
map_equatorial_radius_m,
map_eccentricity,
e2,
map_reference_latitude,
map_reference_longitude,
map_second_reference_latitude,
sin_phi1,
cos_phi1,
kz,
map_scale,
bcols,
brows,
r0,
s0,
epsilon,
)

I've had the same problem with SMOS data from CATDS. That is why I've created ease_lonlat package for python that converts geographic coordinates (longitude, latitude) to EASE(2)-grid coordinates (col, row) and vice versa. It uses pyproj (PROJ) library to convert longitude and latitude to x and y coordinates of EASE(2) projection. And then it just counted the row and column index of the specific grid using parameters from NSIDC.
I've tested it against EASE2-grids with resolutions of 9 km (North, South, and Global projections) and 36 km (North and Global) on SMAP data.
It looks like, that r also supports PROJ, so you can try the same approach.

Related

Return arc length of every rotation of an Archimedean Spiral given arm spacing and total length

I want to calculate the length of every full rotation of an Archimedean Spiral given the spacing between each arm and the total length are known. The closest to a solution I've been able to find is here, but this is for finding an unknown length.
I can't interpret math notation so am unable to extrapolate from the info in the link above. The closest I've been able to achieve is:
Distance between each spiral arm:
ArmSpace <- 7
Total length of spiral:
TotalLength <- 399.5238
Create empty df to accommodate TotalLength (note that sum(df[,2]) can be > TotalLength):
df <- data.frame(matrix(NA, nrow=0, ncol=2))
colnames(df) <- c("turn_num", "turn_len_m")
df[1,1] <- 0 # Start location of spiral
df[1,2] <- pi*1/1000
Return length of every turn:
i <- 0
while(i < TotalLength) {
df[nrow(df)+1,1] <- nrow(df) # Add turn number
df[nrow(df),2] <- pi*(df[nrow(df)-1,2] +
(2*df[nrow(df),1])*ArmSpace)/1000
i <- sum(df[,2])
}
An annotated example explaining the steps would be most appreciated.
I used approximation Clackson formula
t = 2 * Pi * Sqrt(2 * s / a)
to get theta angle corresponding to arc length s.
Example in Delphi, I hope idea is clear enough to implement in R
var
i, cx, cy, x, y: Integer;
s, t, a, r : Double;
begin
cx := 0;
cy := 0;
a := 10; //spiral size parameter
Canvas.MoveTo(cx, cy);
for i := 1 to 1000 do begin
s := 0.07 * i; //arc length
t := 2 * Pi * Sqrt(2 * s / a); //theta
r := a * t; //radius
x := Round(cx + r * cos(t)); //rounded coordinates
y := Round(cy + r * sin(t));
Memo1.Lines.Add(Format('len %5.3f theta %5.3f r %5.3f x %d y %d', [s, t, r, x, y]));
Canvas.LineTo(x, y);
if i mod 10 = 1 then //draw some points as small circles
Canvas.Ellipse(x-2, y-2, x+3, y+3);
end;
Some generated points
len 0.070 theta 0.743 r 7.434 x 5 y 5
len 0.140 theta 1.051 r 10.514 x 5 y 9
len 0.210 theta 1.288 r 12.877 x 4 y 12
len 0.280 theta 1.487 r 14.869 x 1 y 15
len 0.350 theta 1.662 r 16.624 x -2 y 17
len 0.420 theta 1.821 r 18.210 x -5 y 18
Link gives exact formula for ac length,
s(t) = 1/(2*a) * (t * Sqrt(1 + t*t) + ln(t + Sqrt(1+t*t)))
but we cannot calculate inverse (t for given s) using simple formula, so one need to apply numerical methods to find theta for arc length value.
Addition: length of k-th turn. Here we can use exact formula. Python code:
import math
def arch_sp_len(a, t):
return a/2 * (t * math.sqrt(1 + t*t) + math.log(t + math.sqrt(1+t*t)))
def arch_sp_turnlen(a, k):
return arch_sp_len(a, k*2*math.pi) - arch_sp_len(a, (k-1)*2*math.pi)
print(arch_sp_turnlen(1, 1))
print(arch_sp_turnlen(1, 2))
print(arch_sp_turnlen(10, 3))

MathOptInterface.OTHER_ERROR when trying to use ISRES of NLopt through JuMP

I am trying to minimize a nonlinear function with nonlinear inequality constraints with NLopt and JuMP.
In my test code below, I am minimizing a function with a known global minima.
Local optimizers such as LD_MMA fails to find this global minima, so I am trying to use global optimizers of NLopt that allow nonlinear inequality constraintes.
However, when I check my termination status, it says “termination_status(model) = MathOptInterface.OTHER_ERROR”. I am not sure which part of my code to check for this error.
What could be the cause?
I am using JuMP since in the future I plan to use other solvers such as KNITRO as well, but should I rather use the NLopt syntax?
Below is my code:
# THIS IS A CODE TO SOLVE FOR THE TOYMODEL
# THE EQUILIBRIUM IS CHARACTERIZED BY A NONLINEAR SYSTEM OF ODEs OF INCREASING FUCTIONS B(x) and S(y)
# THE GOAL IS TO APPROXIMATE B(x) and S(y) WITH POLYNOMIALS
# FIND THE POLYNOMIAL COEFFICIENTS THAT MINIMIZE THE LEAST SQUARES OF THE EQUILIBRIUM EQUATIONS
# load packages
using Roots, NLopt, JuMP
# model primitives and other parameters
k = .5 # equal split
d = 1 # degree of polynomial
nparam = 2*d+2 # number of parameters to estimate
m = 10 # number of grids
m -= 1
vGrid = range(0,1,m) # discretize values
c1 = 0 # lower bound for B'() and S'()
c2 = 2 # lower and upper bounds for offers
c3 = 1 # lower and upper bounds for the parameters to be estimated
# objective function to be minimized
function obj(α::T...) where {T<:Real}
# split parameters
αb = α[1:d+1] # coefficients for B(x)
αs = α[d+2:end] # coefficients for S(y)
# define B(x), B'(x), S(y), and S'(y)
B(v) = sum([αb[i] * v .^ (i-1) for i in 1:d+1])
B1(v) = sum([αb[i] * (i-1) * v ^ (i-2) for i in 2:d+1])
S(v) = sum([αs[i] * v .^ (i-1) for i in 1:d+1])
S1(v) = sum([αs[i] * (i-1) * v ^ (i-2) for i in 2:d+1])
# the equilibrium is characterized by the following first order conditions
#FOCb(y) = B(k * y * S1(y) + S(y)) - S(y)
#FOCs(x) = S(- (1-k) * (1-x) * B1(x) + B(x)) - B(x)
function FOCb(y)
sy = S(y)
binv = find_zero(q -> B(q) - sy, (-c2, c2))
return k * y * S1(y) + sy - binv
end
function FOCs(x)
bx = B(x)
sinv = find_zero(q -> S(q) - bx, (-c2, c2))
return (1-k) * (1-x) * B1(x) - B(x) + sinv
end
# evaluate the FOCs at each grid point and return the sum of squares
Eb = [FOCb(y) for y in vGrid]
Es = [FOCs(x) for x in vGrid]
E = [Eb; Es]
return E' * E
end
# this is the actual global minimum
αa = [1/12, 2/3, 1/4, 2/3]
obj(αa...)
# do optimization
model = Model(NLopt.Optimizer)
set_optimizer_attribute(model, "algorithm", :GN_ISRES)
#variable(model, -c3 <= α[1:nparam] <= c3)
#NLconstraint(model, [j = 1:m], sum(α[i] * (i-1) * vGrid[j] ^ (i-2) for i in 2:d+1) >= c1) # B should be increasing
#NLconstraint(model, [j = 1:m], sum(α[d+1+i] * (i-1) * vGrid[j] ^ (i-2) for i in 2:d+1) >= c1) # S should be increasing
register(model, :obj, nparam, obj, autodiff=true)
#NLobjective(model, Min, obj(α...))
println("")
println("Initial values:")
for i in 1:nparam
set_start_value(α[i], αa[i]+rand()*.1)
println(start_value(α[i]))
end
JuMP.optimize!(model)
println("")
#show termination_status(model)
#show objective_value(model)
println("")
println("Solution:")
sol = [value(α[i]) for i in 1:nparam]
My output:
Initial values:
0.11233072522513032
0.7631843020124309
0.3331559403539963
0.7161240026812674
termination_status(model) = MathOptInterface.OTHER_ERROR
objective_value(model) = 0.19116585196576466
Solution:
4-element Vector{Float64}:
0.11233072522513032
0.7631843020124309
0.3331559403539963
0.7161240026812674
I answered on the Julia forum: https://discourse.julialang.org/t/mathoptinterface-other-error-when-trying-to-use-isres-of-nlopt-through-jump/87420/2.
Posting my answer for posterity:
You have multiple issues:
range(0,1,m) should be range(0,1; length = m) (how did this work otherwise?) This is true for Julia 1.6. The range(start, stop, length) method was added for Julia v1.8
Sometimes your objective function errors because the root doesn't exist. If I run with Ipopt, I get
ERROR: ArgumentError: The interval [a,b] is not a bracketing interval.
You need f(a) and f(b) to have different signs (f(a) * f(b) < 0).
Consider a different bracket or try fzero(f, c) with an initial guess c.
Here's what I would do:
using JuMP
import Ipopt
import Roots
function main()
k, d, c1, c2, c3, m = 0.5, 1, 0, 2, 1, 10
nparam = 2 * d + 2
m -= 1
vGrid = range(0, 1; length = m)
function obj(α::T...) where {T<:Real}
αb, αs = α[1:d+1], α[d+2:end]
B(v) = sum(αb[i] * v^(i-1) for i in 1:d+1)
B1(v) = sum(αb[i] * (i-1) * v^(i-2) for i in 2:d+1)
S(v) = sum(αs[i] * v^(i-1) for i in 1:d+1)
S1(v) = sum(αs[i] * (i-1) * v^(i-2) for i in 2:d+1)
function FOCb(y)
sy = S(y)
binv = Roots.fzero(q -> B(q) - sy, zero(T))
return k * y * S1(y) + sy - binv
end
function FOCs(x)
bx = B(x)
sinv = Roots.fzero(q -> S(q) - bx, zero(T))
return (1-k) * (1-x) * B1(x) - B(x) + sinv
end
return sum(FOCb(x)^2 + FOCs(x)^2 for x in vGrid)
end
αa = [1/12, 2/3, 1/4, 2/3]
model = Model(Ipopt.Optimizer)
#variable(model, -c3 <= α[i=1:nparam] <= c3, start = αa[i]+ 0.1 * rand())
#constraints(model, begin
[j = 1:m], sum(α[i] * (i-1) * vGrid[j]^(i-2) for i in 2:d+1) >= c1
[j = 1:m], sum(α[d+1+i] * (i-1) * vGrid[j]^(i-2) for i in 2:d+1) >= c1
end)
register(model, :obj, nparam, obj; autodiff = true)
#NLobjective(model, Min, obj(α...))
optimize!(model)
print(solution_summary(model))
return value.(α)
end
main()

Convert Lat/Long to X,Y position within a Bounding Box

I have a bounding box of:
Left -122.27671
Bottom 37.80445
Right -122.26673
Top 37.81449
It could also be converted into NE Lat/Long and SW Lat/Long
Within that bounding box, I'd like to find the X,Y position of a specific Lat/Long. This would be using the Mercator projection.
I've seen answers that find the X,Y of a position on a world map using Mercator, but not within a specific lat/lon.
Any help appreciated!
UPDATE
Put this together from another question I saw. Can anyone validate if this seems legit?
map_width = 1240
map_height = 1279
map_lon_left = -122.296916
map_lon_right = -122.243380
map_lon_delta = map_lon_right - map_lon_left
map_lat_bottom = 37.782368
map_lat_bottom_degree = map_lat_bottom * Math::PI / 180
def convert_geo_to_pixel(lat, long)
x = (long - map_lon_left) * (map_width / map_lon_delta)
lat = lat * Math::PI / 180
world_map_width = ((map_width / map_lon_delta) * 360) / (2 * Math::PI)
map_offset_y = (world_map_width / 2 * Math.log((1 + Math.sin(map_lat_bottom_degree)) / (1 - Math.sin(map_lat_bottom_degree))))
y = map_height - ((world_map_width / 2 * Math.log((1 + Math.sin(lat)) / (1 - Math.sin(lat)))) - map_offset_y)
return [x, y]
end
Found a better solution that I've test and validated. Posting this for anyone else who might find it useful. It's written in Ruby but easy to convert to any other language
#north = to_radians(37.81449)
#south = to_radians(37.80445)
#east = to_radians(-122.26673)
#west = to_radians(-122.27671)
# Coordinates above are a subsection of Oakland, CA
#map_width = map_width
#map_height = map_height
def location_to_pixel(lat:, lon:)
lat = to_radians(lat)
lon = to_radians(lon)
ymin = mercator_y(#south)
ymax = mercator_y(#north)
x_factor = #map_width/(#east - #west)
y_factor = #map_height/(ymax - ymin)
y = mercator_y(lat);
x = (lon - #west) * x_factor
y = (ymax - y) * y_factor
[x, y]
end
def to_radians(deg)
deg * Math::PI/180
end
def mercator_y(lat)
Math.log(
Math.tan(lat/2 + Math::PI/4)
)
end
Let's s is shift of map in world space, bottom latitude in radians B, top latitude T. (I assume y=0 is bottom)
C * Sin(B) = 0 + s
C * Sin(T) = map_height + s
=>
C = map_height / (Sin(T) - Sin(B))
s = C * Sin(B)
y = C * Sin(Lat) - s =
C * Sin(Lat) - C * Sin(B) =
C * (Sin(Lat) - Sin(B)) =
map_height * (Sin(Lat) - Sin(B) / (Sin(T) - Sin(B))
// note - resembles linear interpolation is sine space

transfer the co-ordinates error in function

I am trying to transfer the coordinates of the points to a new generated system coordinates
the original points in the original system is in the top left corner ....
I wrote the following function to transfer the coordinates
I am using the formal that I got from this question
pre_question
this question has 2 photos that show what I mean and the sign for each part
The problem now is , I am getting negative value for w !
can anyone please check this function and let me know where is the problem
Thanks
{
CvPoint transfer_coordinate (CvPoint pt1 , CvPoint pt2 , CvPoint pt3 , CvPoint pt4 , CvPoint origin , CvPoint current)
{
// pt1 , pt2 ==> points in line Z
// pt3 , pt4 ==> points in line W
double a1 , a2 , b1 , b2 , d1 , d2;
d1= sqrt(pow((pt1.x - pt2.x),2.0)+ pow((pt1.y - pt2.y),2.0));
d2= sqrt(pow((pt3.x - pt4.x),2.0)+ pow((pt3.y - pt4.y),2.0));
a1 =(pt1.y-pt2.y)/d1;
b1 =(pt2.x-pt1.x)/d1;
a2 =(pt3.y-pt4.y)/d2;
b2 =(pt4.x-pt3.x)/d2;
CvPoint new_point;
//z = -sqrt(a1^2+b1^2)*(a2*(x-x0)+b2*(y-y0))/(a2*b1-a1*b2)
//w = sqrt(a2^2+b2^2)*(a1*(x-x0)+b1*(y-y0))/(a1*b2-a2*b1)
//z
new_point.x = -round(sqrt(pow(a1,2.0)+ pow(b1,2.0)) * (a2 * (current.x - origin.x) + b2 * (current.y - origin.y))/(a2 * b1 - a1 * b2));
// w
new_point.y = round(sqrt(pow(a2,2.0)+ pow(b2,2.0)) * (a1 * (current.x - origin.x) + b1 * (current.y - origin.y))/(a1 * b2 - a2 * b1));
CvPoint reverse_point;
//x = x0 - b1*z/sqrt(a1^2+b1^2) + b2*w/sqrt(a2^2+b2^2)
//y = y0 + a1*z/sqrt(a1^2+b1^2) - a2*w/sqrt(a2^2+b2^2)
//x
reverse_point.x = round (origin.x - b1 * new_point.x / sqrt(pow(a1,2.0) + pow(b1,2.0)) + b2 * new_point.y /sqrt(pow(a2,2)+ pow(b2,2)));
//y
reverse_point.y = round (origin.y + a1 * new_point.x / sqrt(pow(a1,2.0) + pow(b1,2.0)) - a2 * new_point.y /sqrt(pow(a2,2)+ pow(b2,2)));
//printf("\n points in Z line (%d,%d),(%d,%d) , points in W line (%d,%d),(%d,%d) , origin (%d,%d)",pt1.x,pt1.y,pt2.x,pt2.y,pt3.x,pt3.y,pt4.x,pt4.y,origin.x,origin.y);
//printf("\n current point = (%d,%d) , new point = (%d,%d) , reverse point = (%d,%d)" , current.x,current.y,new_point.x,new_point.y,reverse_point.x,reverse_point.y);
return new_point ;
}
}
If your W-axis corresponds to X-axis, then affine transformation matrix is M = [R]*[T], where R is rotation matrix by Phi angle and T is translation matrix by x0, y0
R = Cos(phi) -Sin(phi) 0
Sin(phi) Cos(phi) 0
0 0 1
and
T = 1 0 0
0 1 0
dx dy 1
You have to multiply these matrices to get M matrix and get inverse matrix MR = Inverse(M). Then you can use M and MR to transform coordinates from XY to WZ system and vice versa
[xnew, ynew, 1] = [xold, yold, 1] * [M]
More information here

Are my equations correct? Rotate on sphere from lat/long points A to B, where will point C be?

I’ve written the below python script. The idea is to calculate the new location of point C after you rotate the globe from point A to point B. I first calculate point P, which is the rotation pole. With calculating point P already something goes wrong. With the following input f.e. I would assume point P to be having latitude 90 or –90.
I asked this question before here: Rotate a sphere from coord1 to coord2, where will coord3 be?
But I figured it's better to ask again with the script included ;)
# GreatCircle can be downloaded from: http://www.koders.com/python/fid0A930D7924AE856342437CA1F5A9A3EC0CAEACE2.aspx?s=coastline
from GreatCircle import *
from math import *
# Points A and B defining the rotation:
LonA = radians(0)
LatA = radians(1)
LonB = radians(45)
LatB = radians(1)
# Point C which will be translated:
LonC = radians(90)
LatC = radians(1)
# The following equation is described here: http://articles.adsabs.harvard.edu//full/1953Metic...1...39L/0000040.000.html
# It calculates the rotation pole at point P of the Great Circle defined by point A and B.
# According to http://www.tutorialspoint.com/python/number_atan2.htm
# atan2(x, y) = atan(y / x)
LonP = atan2(((sin(LonB) * tan(LatA)) - (sin(LonA) * tan(LatB))), ((cos(LonA) * tan(LatB)) - (cos(LonB) * tan(LatA))))
LatP = atan2(-tan(LatA),(cos(LonP - LonA)))
print degrees(LonP), degrees(LatP)
# The equations to calculate the translated point C location were found here: http://www.uwgb.edu/dutchs/mathalgo/sphere0.htm
# The Rotation Angle in radians:
gcAP = GreatCircle(1,1,degrees(LonA),degrees(LatA),degrees(LonP),degrees(LatP))
gcBP = GreatCircle(1,1,degrees(LonB),degrees(LatB),degrees(LonP),degrees(LatP))
RotAngle = abs(gcAP.azimuth12 - gcBP.azimuth12)
# The rotation pole P in Cartesian coordinates:
Px = cos(LatP) * cos(LonP)
Py = cos(LatP) * sin(LonP)
Pz = sin(LatP)
# Point C in Cartesian coordinates:
Cx = cos(radians(LatC)) * cos(radians(LonC))
Cy = cos(radians(LatC)) * sin(radians(LonC))
Cz = sin(radians(LatC))
# The translated point P in Cartesian coordinates:
NewCx = (Cx * cos(RotAngle)) + (1 - cos(RotAngle)) * (Px * Px * Cx + Px * Py * Cy + Px * Pz * Cz) + (Py * Cz - Pz * Cy) * sin(RotAngle)
NewCy = (Cy * cos(RotAngle)) + (1 - cos(RotAngle)) * (Py * Px * Cx + Py * Py * Cy + Py * Pz * Cz) + (Pz * Cx - Px * Cz) * sin(RotAngle)
NewCz = (Cz * cos(RotAngle)) + (1 - cos(RotAngle)) * (Pz * Px * Cx + Pz * Py * Cy + Pz * Pz * Cz) + (Px * Cy - Py * Cx) * sin(RotAngle)
# The following equation I got from http://rbrundritt.wordpress.com/2008/10/14/conversion-between-spherical-and-cartesian-coordinates-systems/
# The translated point P in lat/long:
Cr = sqrt((NewCx*NewCx) + (NewCy*NewCy) + (NewCz*NewCz))
NewCLat = degrees(asin(NewCz/Cr))
NewCLon = degrees(atan2(NewCy, NewCx))
# Output:
print str(NewCLon) + "," + str(NewCLat)

Resources