Related
I have the following code. I know it's long and complex, however it takes 1.5 mins on my laptop to run. I would greatly appreciate any help towards finding the problem causing the error at the end - the plotting part.I didn't find anything on Google related to this error message:
TypeError: unsupported operand type(s) for : 'QuadMesh' and 'float'
from scipy import interpolate
from scipy.fft import fft, ifft
from scipy.constants import c, epsilon_0
import numpy as np, math
from matplotlib import pyplot as plt
lambda_0 = 800 * 10**(-9)
omega_0 = 2*np.pi*c / lambda_0
delta_lambda = 50.0 * 10**(-9)
delta_Tau = (1.47 * 10**(-3) * (lambda_0*10**9)**2 / (delta_lambda*10**9)) * 10**(-15) #
delta_omega_PFT = (4*np.log(2) / delta_Tau) # equivalent (equal) to: ((4*ln(2)) / (2*pi)) * (2*pi/delta_Tau) = 0.441 * (2*pi/delta_Tau)
F = 2.0 # focal length in meters, as from Liu 2017
def G(omegas):
# return ( np.sqrt(np.pi/(2*np.log(2))) * tau * np.exp( -(tau**2/(8*np.log(2))) * (omegas-omega_0)**2 ) ) # why is this here?
return np.exp( -(delta_Tau**2/(8*np.log(2))) * (omegas-omega_0)**2 )
xsi = 0.1 * (1.0 * 10**(-15)) / (1.0 * 10**(-3))
def phase_c(xs, omegas):
return ( xsi * np.reshape(xs, (xs.shape[0], 1)) * np.reshape((omegas-omega_0), (1, omegas.shape[0])) )
E0 = np.sqrt( (0.2*10**4 * 8 * np.sqrt(np.log(2))) / (delta_Tau*np.sqrt(np.pi)*c*epsilon_0/2.0) ) * np.sqrt(2*np.pi*np.log(2)) / delta_omega_PFT
def f(xi, omega): # the prefactors from Eq. (5) of Li et al. (2017) (the ones pre-multiplying the Fraunhoffer integral)
first = omega * np.exp(1j * (omega/c) * F) / (1j * 2*np.pi*c*F) # only function of omega. first is shape (omega.shape[0], )
omega = np.reshape(omega, (1, omega.shape[0]))
xi = np.reshape(xi, (xi.shape[0], 1))
second = np.exp(1j * (omega/c) * xi**2 / (2*F)) # second is shape (xi.shape[0], omega.shape[0]).
return (first * second) # returned is shape (xi.shape[0], omega.shape[0])
x0 = 0.0
delta_x = 196.0 # obtained from N=10, N_x=8*10^3, xi_max=10um, F=2m
xmin_PFT = x0 - delta_x #
xmax_PFT = x0 + delta_x #
num_xs_PFT = 8 * 10**3
xs_PFT = np.linspace(xmin_PFT, xmax_PFT, num_xs_PFT)
sampling_spacing_xs_PFT = np.true_divide( (xmax_PFT-xmin_PFT), num_xs_PFT)
num_omegas_focus = 5 * 10**2
maximum_time = 100.0 * 10**(-15)
N = math.ceil( (np.pi*num_omegas_focus)/(2*delta_omega_PFT*maximum_time) ) - 1
omega_max_focus = omega_0 + N*delta_omega_PFT
omega_min_focus = omega_0 - N*delta_omega_PFT
omegas_focus = np.linspace(omega_min_focus, omega_max_focus, num_omegas_focus) # shape (num_omegas_focus, )
sampling_spacing_omegas_focus = np.true_divide((omega_max_focus-omega_min_focus) , num_omegas_focus)
Es_x_omega = np.multiply( (E0 * G(omegas_focus)) ,
(np.exp(1j*phase_c(xs_PFT, omegas_focus))) # phase_c uses xsi, the PFT coefficient
)
# Es_x_omega holds across columns (vertically downwards) the x-dependence and across rows (horizontally) the omega-dependence
# Es_x_omega is shape (num_xs_PFT, num_omegas_focus)
Bprime_data_real = np.empty((Es_x_omega.shape[0], Es_x_omega.shape[1])) # this can be rewritten in a more Pythonic way
Bprime_data_imag = np.empty((Es_x_omega.shape[0], Es_x_omega.shape[1]))
for i in range(Es_x_omega.shape[1]): # for all the columns (all omegas)
# Perform FFT wrt x (so go from x to Kappa (a scaled spatial frequency))
intermediate = fft(Es_x_omega[:, i])
Bprime_data_real[:, i] = np.real(intermediate) * sampling_spacing_xs_PFT # multiplication by \Delta, see my docu above
Bprime_data_imag[:, i] = np.imag(intermediate) * sampling_spacing_xs_PFT # multiplication by \Delta, see my docu above
if i % 10000 == 0:
print("We have done fft number {}".format(i) + " out of {}".format(Es_x_omega.shape[1]) + "ffts")
# Bprime is function of (Kappa, omega): across rows the omega dependence, across columns the Kappa dependence.
# Get the Kappas:
returned_freqs = np.fft.fftfreq(num_xs_PFT, sampling_spacing_xs_PFT) # shape (num_xs_PFT, )
Kappas_ugly = 2*np.pi * returned_freqs # shape (num_xs_PFT, ), but unordered in terms of the magnitude of the values! see https://numpy.org/doc/stable/reference/generated/numpy.fft.fftfreq.html
Kappas_pretty = 2*np.pi * np.fft.fftshift(returned_freqs)
indices = (Kappas_ugly == Kappas_pretty[:, None]).argmax(1) # shape (num_xs_PFT, )
indices = indices.reshape((indices.shape[0], 1)) # needed for adapting Dani Mesejo's answer: he reordered based on 1D slices laid horizontally, here I reorder based on 1D slices laid vertically.
# see my notebook for visuals, 22-23 Nov 2021
hold_real = Bprime_data_real.shape[1]
hold_imag = Bprime_data_imag.shape[1]
Bprime_data_real_pretty = np.take_along_axis(Bprime_data_real, np.tile(indices, (1, hold_real)), axis=0) # adapted from Dani Mesejo's answer
Bprime_data_imag_pretty = np.take_along_axis(Bprime_data_imag, np.tile(indices, (1, hold_imag)), axis=0) # adapted from Dani Mesejo's answer
print(Bprime_data_real_pretty.shape) # shape (num_xs_PFT, num_omegas_focus), similarly for Bprime_data_imag_pretty
Bprime_real = interpolate.RectBivariateSpline(Kappas_pretty, omegas_focus, Bprime_data_real_pretty) # this CTOR creates an object faster (which can also be queried faster)
Bprime_imag = interpolate.RectBivariateSpline(Kappas_pretty, omegas_focus, Bprime_data_imag_pretty) # than interpolate.interp2d() does.
print("We have the interpolators!")
# Prepare for the aim: plot E versus time (horizontal axis) and xi (vertical axis).
xi_min = -5.0 * 10**(-6) # um
xi_max = 5.0 * 10**(-6) # um
num_xis = 5000
xis = np.linspace(xi_min, xi_max, num_xis)
print("We are preparing now!")
Es_Kappa_omega_without_prefactor = np.empty((xis.shape[0], omegas_focus.shape[0]), dtype=complex)
for j in range(Es_Kappa_omega_without_prefactor.shape[0]): # for each row
for i in range(Es_Kappa_omega_without_prefactor.shape[1]): # for each column
Es_Kappa_omega_without_prefactor[j, i] = Bprime_real(omegas_focus[i]*xis[j] /(c*F), omegas_focus[i]) + 1j*Bprime_imag(omegas_focus[i]*xis[j] /(c*F), omegas_focus[i])
if ((i + j*Es_Kappa_omega_without_prefactor.shape[1]) % 30000 == 0):
print("We have done iter number {}".format(i + j*Es_Kappa_omega_without_prefactor.shape[1])
+ " out of {}".format(Es_Kappa_omega_without_prefactor.shape[0] * Es_Kappa_omega_without_prefactor.shape[1]) + " iterations in querying the interpolators")
Es_Kappa_omega = np.multiply( f(xis, omegas_focus), # f(xis, omegas_focus) is shape (xis.shape[0], omegas_focus.shape[0])
Es_Kappa_omega_without_prefactor # Es_Kappa_omega_without_prefactor is shape (xis.shape[0], omegas_focus.shape[0])
) # the obtained variable is shape (xis.shape[0], omegas_focus.shape[0])
# Do IFT of Es_Kappa_omega w.r.t. omega to go from FD (omega) to TD (time t).
Es_Kappa_time = np.empty_like(Es_Kappa_omega, dtype=complex) # shape (xis.shape[0], omegas_focus.shape[0])
# Along columns (so vertically) the xi dependence, along rows (horizontally), the omega dependence
for i in range(Es_Kappa_omega.shape[0]): # for each row (for each xi)
Es_Kappa_time[i, :] = ifft(Es_Kappa_omega[i, :]) * (sampling_spacing_omegas_focus/(2*np.pi)) * num_omegas_focus # 1st multiplication is by Delta, 2nd multiplication is by N
if i % 10000 == 0:
print("We have done ifft number {}".format(i) + " out of a total of {}".format(Es_Kappa_omega.shape[0]) + " iffts")
returned_times_ugly = np.fft.fftfreq(num_omegas_focus, d=(sampling_spacing_omegas_focus/(2*np.pi))) # shape (num_omegas_focus, )
returned_times_pretty = np.fft.fftshift(returned_times_ugly) # order the returned "frequencies" (here "frequencies" = times because it's IFT (so from FD to TD))
indices = (returned_times_ugly == returned_times_pretty[:, None]).argmax(1)
Es_Kappa_time = np.take_along_axis(Es_Kappa_time, np.tile(indices, (Es_Kappa_time.shape[0], 1)), axis=1) # this is purely Dani Mesejo's answer
returned_times_pretty_mesh, xis_mesh = np.meshgrid(returned_times_pretty, xis)
fig, ax = plt.subplots()
c = ax.pcolormesh(returned_times_pretty_mesh, xis_mesh, np.real(Es_Kappa_time), cmap='viridis')
fig.colorbar(c, ax=ax, label=r'$[V/m]$')
ax.set_xlabel("t [s]")
ax.set_ylabel("xi [m]")
plt.show()
fig, ax = plt.subplots()
ax.imshow(np.multiply(np.square(np.real(Es_Kappa_time)), (c*epsilon_0)), cmap='viridis')
ax.set_xlabel("t [s]")
ax.set_ylabel("xi [m]")
plt.show()
I have tried many forms to be introduced in the plotting part. It fails with:
c = ax.pcolormesh(returned_times_pretty_mesh, xis_mesh, (c*epsilon_0)*np.real(Es_Kappa_time)**2, cmap='viridis')
fig.colorbar(c, ax=ax, label=r'$[V/m]$')
Fails with:
160 fig, ax = plt.subplots()
--> 161 ax.imshow(np.multiply(np.real(Es_Kappa_time)**2, (c*epsilon_0)), cmap='viridis')
I ran out of ideas of what I might introduce there.
Thank you!
It looks like you're reassigning c to the return value from ax.pcolormesh(...) after you import c from scipy.constants.
I've got some XYZ coordinates in Kilometers (gotten using wgs) with the origin at the center of the Earth, is it possible to convert this into latitude and longitude?
In addition: how can I do this quickly inside python?
It's simply a reverse of this question here: Converting from longitude\latitude to Cartesian coordinates
Based on #daphshez answer
You can use this code,
Here, x, y and z are in Kms and R is an approximate diameter of Earth.
import numpy as np
R = 6371
lat = np.degrees(np.arcsin(z/R))
lon = np.degrees(np.arctan2(y, x))
This is how you do it. Taking into account both radiuses. Based on:
https://gist.github.com/govert/1b373696c9a27ff4c72a
and verifyed.
import math
x = float(4333216) #in meters
y = float(3193635) #in meters
z = float(3375365) #in meters
a = 6378137.0 #in meters
b = 6356752.314245 #in meters
f = (a - b) / a
f_inv = 1.0 / f
e_sq = f * (2 - f)
eps = e_sq / (1.0 - e_sq)
p = math.sqrt(x * x + y * y)
q = math.atan2((z * a), (p * b))
sin_q = math.sin(q)
cos_q = math.cos(q)
sin_q_3 = sin_q * sin_q * sin_q
cos_q_3 = cos_q * cos_q * cos_q
phi = math.atan2((z + eps * b * sin_q_3), (p - e_sq * a * cos_q_3))
lam = math.atan2(y, x)
v = a / math.sqrt(1.0 - e_sq * math.sin(phi) * math.sin(phi))
h = (p / math.cos(phi)) - v
lat = math.degrees(phi)
lon = math.degrees(lam)
print(lat,lon,h)
Ok, this is going to be really long. I am trying to calculate water levels in an analytical solution in a polar grid. It depends on both r and theta as well as this variable j. What I am trying to do is essentially calculate a water level at a specific r, theta point in my grid based in a given equation. This equation has a portion where it sums over infinite values of j. Part of the equation is here Equation image
Some of the code is as follows:
"""
Plot idealized solution for water levels in a quarter circle domain with
constant bathymetry
"""
import numpy as np
import matplotlib.pyplot as plt
#from pylab import meshgrid,cm,imshow,contour,clabel,colorbar,axis,title,show
# establish parameters
Ho = 300 #m
g = 9.81 #m/s2
r1 = 1000 #m
r2 = 10000 #m
rr = np.arange(r1,r2,10)
#radial size of domain
phi = np.pi/2
#theta is the angle in radians at a specific location within the domain
#theta = np.pi/4
theta = np.arange(0, phi, np.pi/360)#varies
Theta = theta[1:180]
zeta = [0] * len(rr) * len(Theta)
#converting from wind speed to wind shear stress
U = 10
Cd = (1/1000) * ((3/4) + (U/15))
Roair = 1.225 #kg/m3
Rowater = 997 #kg/m3
W = (Roair/Rowater) * Cd * (U**2)
#wind shear in m^2/s^2 in the 0 direction (W to E)
Wo = np.sqrt((W**2)/2)
#wind shear in m^2/s^2 in the phi direction
Wphi = np.sqrt((W**2)/2)
zeta = np.zeros((len(rr), len(Theta)))
#determines the bathymetry
a_star = []
n = 0
kappa = (1-n)**(0.5)
for t in range(len(Theta)):
a_star.append ( ( (np.sin(phi)) / (g*Ho*kappa* np.sin(kappa*Theta[t])) ) )
#first half of equation 19 that does not depend on j
for r in range(len(rr)):
for t in range(len(Theta)):
zeta[r,t] = ( (a_star[t] * (rr[r]**(1-n)))*(Wo*np.cos(((1-n)**(0.5))*Theta[t]) + Wphi*np.cos(((1-n)**(0.5))*(Theta[t]-phi))) )
#second half of equation 19 for j=0
ajbj = []
for t in range(len(Theta)):
j = 0
Djo = np.sin(( ( (1-n)**(0.5) ) * phi ) ) / ( (1-n)**(0.5) * (phi) )
Ejo = (np.sin(phi)) / (phi)
ajbj.append ( (r2**(1-n)) * (-a_star[t] * Djo))
for r in range(len(rr)):
zeta[r,t] = zeta[r,t] + (ajbj[t])*(Wo+Wphi)
#second half of equation 19 for j=1,2,3 (summation)
sj = []
tj = []
Dj = []
Ej = []
r1EogH = []
astarD = []
tjr1r2 = []
sjr2 = []
aj = []
bj = []
jj = [1,2,3]
for j in range(len(jj)):
sj.append(- (n/2) + np.sqrt( ( (n/2)**2) + ( (jj[j]*np.pi / phi)**2) ) )
tj.append (- (n/2) - np.sqrt( ( (n/2)**2) + ( (jj[j]*np.pi / phi)**2) ) )
Dj.append ( (2* ((-1)**jj[j]) * ((1-n)**(0.5)) * phi * np.sin( ((1-n)**(0.5)) * phi )) / ( (1-n) * (phi**2) - (jj[j]**2) * (np.pi**2) ) )
Ej.append ( (2* ((-1)**jj[j]) * phi * np.sin(phi) ) / ( (phi**2) - (jj[j]**2) * (np.pi**2) ) )
r1EogH.append ( ( (r1**(1-n)) * Ej[j] ) / ( g * Ho ) )
tjr1r2.append ( tj[j] * (r1**tj[j]) * (r2**sj[j]) )
sjr2.append ( sj[j] * (r2**tj[j]) )
for t in range(len(Theta)):
#astarD.append ( a_star[t] * Dj[j] )
aj.append ( ( a_star[t]*Dj[j] * ( ( tj[j] * (r1**tj[j]) * (r2**(1-n)) ) - ( (r2**tj[j]) * (r1**(1-n)) ) ) + ( r1EogH[j] * r2**tj[j] ) ) / ( (sjr2[j] * (r1**sj[j])) - tjr1r2[j] ) )
bj.append ( ( -1* a_star[t]*Dj[j] * ( ( sj[j] * (r1**sj[j]) * (r2**(1-n)) ) - ( (r2**sj[j]) * (r1**(1-n)) ) ) - ( r1EogH[j] * r2**sj[j] ) ) / ( (sjr2[j] * (r2**sj[j])) - tjr1r2[j] ) )
for r in range(len(rr)):
zeta[r,t] = zeta[r,t] + ( ( (aj[j] * rr[r]**(sj[j])) + (bj[j] * rr[r]**(tj[j])) ) * (Wo*np.cos( (jj[j]*np.pi*Theta[t])/phi) + Wphi*np.cos( (jj[j]*np.pi*(Theta[t]-phi))/phi)) )
x,y = np.meshgrid(Theta, rr)
X = Theta
Y = rr
fig = plt.figure()
ax = fig.add_subplot(111, polar='True')
ax.pcolormesh(X, Y, zeta) #X,Y & data2D must all be same dimensions
ax.set_thetamin(0)
ax.set_thetamax(90)
plot = ax.pcolor(zeta)
fig.colorbar(plot)
plt.show()
Solution for above
The values I am getting for zeta are much to large. They should be more like the values in the below solution for theta PI/4. I know the equations are complex. What I want is for a point in the grid say r=1000, theta= pi/4 for it to calculate the zeta value for j=1, j=2 and j=3 and then sum those all together and then do the same thing at each point in the grid. I am wondering if I just need to structure my loops differently? Or not use the .append function? Does anyone have any suggestions?
DONE FOR THETA PI/4
"""
Plot idealized solution for water levels in a quarter circle domain with
constant bathymetry
"""
import numpy as np
import matplotlib.pyplot as plt
#from pylab import meshgrid,cm,imshow,contour,clabel,colorbar,axis,title,show
# establish parameters
Ho = 300 #m
g = 9.81 #m/s2
r1 = 1000 #m
r2 = 10000 #m
rr = np.arange(r1,r2,10)
zeta = [0] * len(rr)
#radial size of domain
phi = np.pi/2
#theta is the angle in radians at a specific location within the domain
theta = np.pi/4
#converting from wind speed to wind shear stress
U = 10
Cd = (1/1000) * ((3/4) + (U/15))
Roair = 1.225 #kg/m3
Rowater = 997 #kg/m3
W = (Roair/Rowater) * Cd * (U**2)
#wind shear in m^2/s^2 in the 0 direction (W to E)
Wo = np.sqrt((W**2)/2)
#wind shear in m^2/s^2 in the phi direction
Wphi = np.sqrt((W**2)/2)
#determines the bathymetry
n = 0
kappa = (1-n)**(0.5)
a_star = ( (np.sin(phi)) / (g*Ho*kappa* np.sin(kappa*theta)) )
#first half of equation 19 that does not depend on j
for r in range(len(rr)):
zeta[r] = ( a_star * (rr[r]**(1-n))*(Wo*np.cos(((1-n)**(0.5))*theta) + Wphi*np.cos(((1-n)**(0.5))*(theta-phi))) )
#plt.xlabel("rr")
#plt.ylabel("zeta")
###
#plt.plot(rr,zeta, label = 'LHS eq 19')
#second half of equation 19 for j=0
for r in range(len(rr)):
j = 0
Djo = np.sin(( ( (1-n)**(0.5) ) * phi ) ) / ( (1-n)**(0.5) * (phi) )
Ejo = (np.sin(phi)) / (phi)
ajbj = (r2**(1-n)) * (-a_star * Djo)
zeta[r] = zeta[r] + (ajbj)*(Wo+Wphi)
#plt.xlabel("rr")
#plt.ylabel("zeta")
###
#plt.plot(rr,zeta, label = 'j=0')
#second half of equation 19 for j=1,2,3 (summation)
sj = []
tj = []
Dj = []
Ej = []
r1EogH = []
astarD = []
tjr1r2 = []
sjr2 = []
aj = []
bj = []
jj = [1,2,3]
for j in range(len(jj)):
sj.append(- (n/2) + np.sqrt( ( (n/2)**2) + ( (jj[j]*np.pi / phi)**2) ) )
tj.append (- (n/2) - np.sqrt( ( (n/2)**2) + ( (jj[j]*np.pi / phi)**2) ) )
Dj.append ( (2* ((-1)**jj[j]) * ((1-n)**(0.5)) * phi * np.sin( ((1-n)**(0.5)) * phi )) / ( (1-n) * (phi**2) - (jj[j]**2) * (np.pi**2) ) )
Ej.append ( (2* ((-1)**jj[j]) * phi * np.sin(phi) ) / ( (phi**2) - (jj[j]**2) * (np.pi**2) ) )
r1EogH.append ( ( (r1**(1-n)) * Ej[j] ) / ( g * Ho ) )
astarD.append ( a_star * Dj[j] )
tjr1r2.append ( tj[j] * (r1**tj[j]) * (r2**sj[j]) )
sjr2.append ( sj[j] * (r2**tj[j]) )
aj.append ( ( astarD[j] * ( ( tj[j] * (r1**tj[j]) * (r2**(1-n)) ) - ( (r2**tj[j]) * (r1**(1-n)) ) ) + ( r1EogH[j] * r2**tj[j] ) ) / ( sjr2[j] * (r1**sj[j]) - tjr1r2[j] ) )
bj.append (- ( astarD[j] * ( ( sj[j] * (r1**sj[j]) * (r2**(1-n)) ) - ( (r2**sj[j]) * (r1**(1-n)) ) ) - ( r1EogH[j] * r2**sj[j] ) ) / ( sjr2[j] * (r2**sj[j]) - tjr1r2[j] ) )
for r in range(len(rr)):
zeta[r] = zeta[r] + ( ( (aj[j] * rr[r]**(sj[j])) + (bj[j] * rr[r]**(tj[j])) ) * (Wo*np.cos( (jj[j]*np.pi*theta)/phi) + Wphi*np.cos( (jj[j]*np.pi*(theta-phi))/phi)) )
plt.xlabel("rr")
plt.ylabel("zeta")
plt.title("Wind In at 45 degrees")
#
plt.plot(rr,zeta, label = 'Ho=100m')
plt.legend(loc='upper right')
Solution for theta 45degrees
Suggest writing a function zeta (r, t, j) that you can test with some hand-calculated values:
def zeta(r, theta, j):
#your complex calculations here
assert zeta(4000, pi/4, 2) == 0.00043 #This is a test to be sure your formulae
# are right (eyeballed from your graph)
Then iterate over rr and theta to fill the array:
zeta_out = np.zeros((len(rr), len(Theta)))
for r in range(len(rr)):
for t in range(len(theta)):
zeta_out[r, t] = np.mean(zeta(rr[r], theta[t], j) for j in (1,2,3))
Unfortunately I am not a math wizard. I tried to run your code to see what output it got prior to me trying to refactor it in some way. However, there are errors because things like sj from sj.append() are not defined in the snippet provided. I do not know how to read the equation provided in your image (math courses were many years ago and not used since college).
As for advice, without fully understanding your problem, the best I can offer you is to consider making functions. This allows you/others to see the code more clearly. Another advantage is for when something changes (seems unlikely with an equation, but perhaps you want to change your input type at some point in the future) the changes are made in smaller pieces.
def calculate_j(point_or_other_necessary_input):
""" do the maths for j """
return some_equation_or_value_for_j
def calculate_t(point_or_other_necessary_input):
""" do the maths for t """
return some_equation_or_value_for_t
def calculate_r(point_or_other_necessary_input):
""" do the maths for r """
return some_equation_or_value_for_r
def process_grid(zeta_grid):
""" process each point in the provided grid"""
for point in zeta_grid:
# or whatever makes sense to combine the values/equations
calculated_sum = calculate_j(point) + calculate_t(point) + calculate_r(point)
# store value in some reasonable way, probably another grid
return calculated_points
print(process_grid(zeta))
After further evaluation, and more info from your edit, I have to ask if you really mean to do:
jj = [1,2,3]
for j in range(len(jj)):
I'm guessing, without really being sure, that you want j to be 1 then 2, then 3, no? Currently you are really getting 0, 1, 2 because you are iterating over the length of the list, not the items in the list. This is significant not in the first portion where you are getting the values of jj with jj[j] but it is in the portion for r where you use j instead of jj[j] such as in:
zeta[r] = zeta[r] + ( ( (aj[j] * rr[r]**(sj[j])) + (bj[j] * rr[r]**(tj[j])) )
As stated, that could be your intended behavior to only use 0,1,2 instead of 1,2,3. As for why the values might be too large, do you intend to calculate r for all of rr 3 times? You have it nested inside of the first for loop which means it is executing in every iteration of the for j in ... loop. So it is adding to itself (zeta[r] = zeta[r] + ...) some large number of times. (Again, not a math person) but isn't that running len(rr)^3 times or 3^len(rr) times? Some number of times more than possibly intended.
I am attempting to create a grid of locators that serve as projected points onto a parallel finite plane from a camera in maya at a specified depth. The grid should line up with a specified resolution so as to match rendered output.
At the moment my calculations are off and I am looking for some help to ascertain how my formula for ascertaining the projected points is incorrect.
I have a self contained python script and image showing the current position of locators that are spawned as an example.
image showing current spawned locators are off on y and z axis
import maya.cmds as mc
import maya.OpenMaya as om
res = [mc.getAttr('defaultResolution.width'),
mc.getAttr('defaultResolution.height')]
print res
grid = [5, 5]
def projectedGridPoint(camera, coord, depth, res):
selList = om.MSelectionList()
selList.add(camera)
dagPath = om.MDagPath()
selList.getDagPath(0,dagPath)
dagPath.extendToShape()
camMtx = dagPath.inclusiveMatrix()
fnCam = om.MFnCamera(dagPath)
mFloatMtx = fnCam.projectionMatrix()
projMtx = om.MMatrix(mFloatMtx.matrix)
#center of camera
eyePt = fnCam.eyePoint()
#offset position
z = eyePt.z - depth
#calculated xy positions
x = (2 * z * coord[0] / res[0]) - z
y = (2 * z * coord[1] / res[1]) - z
return om.MPoint(x,y,depth) * camMtx * projMtx.inverse()
for y in range(grid[1] + 1):
for x in range(grid[0] + 1):
coord = ( x / float(grid[0]) * res[0], y / float(grid[1]) * res[1] )
pt = projectedGridPoint('camera1', coord, 10, res)
mc.spaceLocator(a=1, p=[pt.x, pt.y, pt.z])
Once I adjusted Theodox's answer to account for all possible grid divisions, such that the ndc_x and ndc_y was always in the range of -1 and 1. I was able to get a working solution.
import maya.api.OpenMaya as om
import maya.cmds as cmds
def projectedGridPoint(camera, coord, depth):
selList = om.MGlobal.getSelectionListByName(camera)
dagPath = selList.getDagPath(0)
dagPath.extendToShape()
view = dagPath.inclusiveMatrix()
fnCam = om.MFnCamera(dagPath)
projection = om.MMatrix(fnCam.projectionMatrix())
viewProj = projection * view
r = om.MPoint(coord[0],coord[1], -1 * depth) * projection.inverse()
return r.homogenize() * view
xx, yy = (6, 6)
for y in range(yy + 1):
for x in range(xx + 1):
ndc_x = -1
ndc_y = -1
if x > 0:
ndc_x = (x / float(xx) * 2) - 1
if y > 0:
ndc_y = (y / float(yy) * 2) - 1
coord = ( ndc_x, ndc_y)
print coord
pt = projectedGridPoint('camera1', coord, 0)
c,_ = cmds.polyCube(w = 0.1, d = 0.1, h = 0.1)
cmds.xform(c, t = (pt[0], pt[1], pt[2]))
I think you want something a bit more like this (note, i converted it to API 2 to cut down on the boilerplate)
import maya.api.OpenMaya as om
import maya.cmds as cmds
def projectedGridPoint(camera, coord, depth):
selList = om.MGlobal.getSelectionListByName(camera)
dagPath = selList.getDagPath(0)
dagPath.extendToShape()
view = dagPath.inclusiveMatrix()
fnCam = om.MFnCamera(dagPath)
projection = om.MMatrix(fnCam.projectionMatrix())
viewProj = projection * view
r = om.MPoint(coord[0],coord[1], -1 * depth) * projection.inverse()
return r.homogenize() * view
xx, yy = (2, 2)
for y in range(yy):
for x in range(xx):
ndc_x = 2.0 * x / float(xx - 1) - 1
ndc_y = 2.0 * y / float(yy - 1) - 1
coord = ( ndc_x, ndc_y)
pt = projectedGridPoint('camera1', coord,0)
c,_ = cmds.polyCube(w = 0.1, d = 0.1, h = 0.1)
cmds.xform(c, t = (pt[0], pt[1], pt[2]))
The coords are supplied as normalized device coordinates (from -1,-1 to 1, 1 at the corners of the view) and the depth goes from the near to far clip planes -- a depth of 1 is right on the near plane and a depth of 0 is on the far plane. I think in practice I'd lock the depth at 0 and use the clip plane setting on the camera to set the depth
edit I rationalized the original, wonky method of converting index values to NDC coordinates
Hi :)
i have the following python code that generates points lying on a sphere's surface
from math import sin, cos, pi
toRad = pi / 180
ox = 10
oy = -10
oz = 50
radius = 10.0
radBump = 3.0
angleMin = 0
angleMax = 360
angleOffset = angleMin * toRad
angleRange = (angleMax - angleMin) * toRad
steps = 48
angleStep = angleRange / steps
latMin = 0
latMax = 180
latOffset = latMin * toRad
if (latOffset < 0):
latOffset = 0;
latRange = (latMax - latMin) * toRad
if (latRange > pi):
latRange = pi - latOffset;
latSteps = 48
latAngleStep = latRange / latSteps
for lat in range(0, latSteps):
ang = lat * latAngleStep + latOffset
z = cos(ang) * radius + oz
radMod = sin(ang) * radius
for a in range(0, steps):
x = sin(a * angleStep + angleOffset) * radMod + ox
y = cos(a * angleStep + angleOffset) * radMod + oy
print "%f %f %f"%(x,y,z)
after that i plot the points with gnuplot using splot 'datafile'
can you give any hints on how to create deformations on that sphere?
like "mountains" or "spikes" on it?
(something like the openbsd logo ;) : https://https.openbsd.org/images/tshirt-23.gif )
i know it is a trivial question :( but thanks for your time :)
DsP
The approach that springs to my mind, especially with the way you compute a set of points that are not explicitly connected, is to find where the point goes on the sphere's surface, then move it by a distance and direction determined by a set of control points. The control points could have smaller effects the further away they are. For example:
# we have already computed a points position on the sphere, and
# called it x,y,z
for p in controlPoints:
dx = p.x - x
dy = p.y - y
dz = p.z - z
xDisplace += 1/(dx*dx)
yDisplace += 1/(dy*dy)
zDisplace += 1/(dz*dz) # using distance^2 displacement
x += xDisplace
y += yDisplace
z += zDisplace
By changing the control points you can alter the sphere's shape
By changing the movement function, you can alter the way the points shape the sphere
You could get really tricky and have different functions for different points:
# we have already computed a points position on the sphere, and
# called it x,y,z
for p in controlPoints:
xDisplace += p.displacementFunction(x)
yDisplace += p.displacementFunction(y)
zDisplace += p.displacementFunction(z)
x += xDisplace
y += yDisplace
z += zDisplace
If you do not want all control points affecting every point in the sphere, just build that into the displacement function.
How's this?
from math import sin, cos, pi, radians, ceil
import itertools
try:
rng = xrange # Python 2.x
except NameError:
rng = range # Python 3.x
# for the following calculations,
# - all angles are in radians (unless otherwise specified)
# - latitude is in [-pi/2..pi/2]
# - longitude is in [-pi..pi)
MIN_LAT = -pi/2 # South Pole
MAX_LAT = pi/2 # North Pole
MIN_LON = -pi # Far West
MAX_LON = pi # Far East
def floatRange(start, end=None, step=1.0):
"Floating-point range generator"
start += 0.0 # cast to float
if end is None:
end = start
start = 0.0
steps = int(ceil((end-start)/step))
return (start + k*step for k in rng(0, steps+1))
def patch2d(xmin, xmax, ymin, ymax, step=1.0):
"2d rectangular grid generator"
if xmin>xmax:
xmin,xmax = xmax,xmin
xrange = floatRange(xmin, xmax, step)
if ymin>ymax:
ymin,ymax = ymax,ymin
yrange = floatRange(ymin, ymax, step)
return itertools.product(xrange, yrange)
def patch2d_to_3d(xyIter, zFn):
"Convert 2d field to 2.5d height-field"
mapFn = lambda a: (a[0], a[1], zFn(a[0],a[1]))
return itertools.imap(mapFn, xyIter)
#
# Representation conversion functions
#
def to_spherical(lon, lat, rad):
"Map from spherical to spherical coordinates (identity function)"
return lon, lat, rad
def to_cylindrical(lon, lat, rad):
"Map from spherical to cylindrical coordinates"
# angle, z, radius
return lon, rad*sin(lat), rad*cos(lat)
def to_cartesian(lon, lat, rad):
"Map from spherical to Cartesian coordinates"
# x, y, z
cos_lat = cos(lat)
return rad*cos_lat*cos(lon), rad*cos_lat*sin(lon), rad*sin(lat)
def bumpySphere(gridSize, radiusFn, outConv):
lonlat = patch2d(MIN_LON, MAX_LON, MIN_LAT, MAX_LAT, gridSize)
return list(outConv(*lonlatrad) for lonlatrad in patch2d_to_3d(lonlat, radiusFn))
# make a plain sphere of radius 10
sphere = bumpySphere(radians(5.0), lambda x,y: 10.0, to_cartesian)
# spiky-star-function maker
def starFnMaker(xWidth, xOffset, yWidth, yOffset, minRad, maxRad):
# make a spiky-star function:
# longitudinal and latitudinal triangular waveforms,
# joined as boolean intersection,
# resulting in a grid of positive square pyramids
def starFn(x, y, xWidth=xWidth, xOffset=xOffset, yWidth=yWidth, yOffset=yOffset, minRad=minRad, maxRad=maxRad):
xo = ((x-xOffset)/float(xWidth)) % 1.0 # xo in [0.0..1.0), progress across a single pattern-repetition
xh = 2 * min(xo, 1.0-xo) # height at xo in [0.0..1.0]
xHeight = minRad + xh*(maxRad-minRad)
yo = ((y-yOffset)/float(yWidth)) % 1.0
yh = 2 * min(yo, 1.0-yo)
yHeight = minRad + yh*(maxRad-minRad)
return min(xHeight, yHeight)
return starFn
# parameters to spike-star-function maker
width = 2*pi
horDivs = 20 # number of waveforms longitudinally
horShift = 0.0 # longitudinal offset in [0.0..1.0) of a wave
height = pi
verDivs = 10
verShift = 0.5 # leave spikes at the poles
minRad = 10.0
maxRad = 15.0
deathstarFn = starFnMaker(width/horDivs, width*horShift/horDivs, height/verDivs, height*verShift/verDivs, minRad, maxRad)
deathstar = bumpySphere(radians(2.0), deathstarFn, to_cartesian)
so i finally created the deformation using a set of control points that "pull" the spherical
surface. it is heavilly OO and ugly though ;)
thanks for all the help !!!
to use it > afile and with gnuplot : splot 'afile' w l
DsP
from math import sin, cos, pi ,sqrt,exp
class Point:
"""a 3d point class"""
def __init__(self,x,y,z):
self.x = x
self.y = y
self.z = z
def __repr__(self):
return "%f %f %f\n"%(self.x,self.y,self.z)
def __str__(self):
return "point centered: %f %f %f\n"%(self.x,self.y,self.z)
def distance(self,b):
return sqrt((self.x - b.x)**2 +(self.y - b.y)**2 +(self.z -b.z)**2)
def displaceTowards(self,b):
self.x
class ControlPoint(Point):
"""a control point that deforms positions of other points"""
def __init__(self,p):
Point.__init__(self,p.x,p.y,p.z)
self.deformspoints=[]
def deforms(self,p):
self.deformspoints.append(p)
def deformothers(self):
self.deformspoints.sort()
#print self.deformspoints
for i in range(0,len(self.deformspoints)):
self.deformspoints[i].x += (self.x - self.deformspoints[i].x)/2
self.deformspoints[i].y += (self.y - self.deformspoints[i].y)/2
self.deformspoints[i].z += (self.z - self.deformspoints[i].z)/2
class Sphere:
"""returns points on a sphere"""
def __init__(self,radius,angleMin,angleMax,latMin,latMax,discrStep,ox,oy,oz):
toRad = pi/180
self.ox=ox
self.oy=oy
self.oz=oz
self.radius=radius
self.angleMin=angleMin
self.angleMax=angleMax
self.latMin=latMin
self.latMax=latMax
self.discrStep=discrStep
self.angleRange = (self.angleMax - self.angleMin)*toRad
self.angleOffset = self.angleMin*toRad
self.angleStep = self.angleRange / self.discrStep
self.latOffset = self.latMin*toRad
self.latRange = (self.latMax - self.latMin) * toRad
self.latAngleStep = self.latRange / self.discrStep
if(self.latOffset <0):
self.latOffset = 0
if(self.latRange > pi):
self.latRange = pi - latOffset
def CartesianPoints(self):
PointList = []
for lat in range(0,self.discrStep):
ang = lat * self.latAngleStep + self.latOffset
z = cos(ang) * self.radius + self.oz
radMod = sin(ang)*self.radius
for a in range(0,self.discrStep):
x = sin(a*self.angleStep+self.angleOffset)*radMod+self.ox
y = cos(a*self.angleStep+self.angleOffset)*radMod+self.oy
PointList.append(Point(x,y,z))
return PointList
mysphere = Sphere(10.0,0,360,0,180,50,10,10,10)
mylist = mysphere.CartesianPoints()
cpoints = [ControlPoint(Point(0.0,0.0,0.0)),ControlPoint(Point(20.0,0.0,0.0))]
deforpoints=[]
for cp in cpoints:
for p in mylist:
if(p.distance(cp) < 15.0):
cp.deforms(p)
"""print "cp ",cp,"deforms:"
for dp in cp.deformspoints:
print dp ,"at distance", dp.distance(cp)"""
cp.deformothers()
out= mylist.__repr__()
s = out.replace(","," ")
print s