File indexing completed on 2026-04-09 07:48:51
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 """
0022 xrainbow.py : Rainbow Expectations
0023 ====================================
0024
0025 Using derivations from: Jearl D. Walker
0026 "Multiple rainbows from single drops of water and other liquids",
0027
0028 * http://www.patarnott.com/atms749/pdf/MultipleRainbowsSingleDrops.pdf
0029
0030 Alexanders dark band, between the 1st and 2nd bows
0031 (due to no rays below min deviation for each bow)
0032
0033
0034 See Also
0035 ----------
0036
0037 Abandoned approach to analytic rainbows in env/opticksnpy/rainbow*.py
0038
0039
0040 Polarization Check
0041 -------------------
0042
0043 Plane of incidence defined by initial direction vector
0044 (a constant vector) and the surface normal at point of incidence,
0045 which will be different for every intersection point.
0046
0047 Thus need to specially prepare the polarizations in order to
0048 arrange S-polarized incident light. Basically need to
0049 calculate surface normal for all points of sphere.
0050
0051 S-polarized : perpendicular to the plane of incidence
0052
0053
0054 Rendering Spectra
0055 -------------------
0056
0057 Comparison of several approaches to handling out of gamut spectral colors
0058
0059 * http://www-rohan.sdsu.edu/~aty/explain/optics/rendering.html
0060
0061 Collection of color science links
0062
0063 * http://www.midnightkite.com/color.html
0064
0065
0066 Rainbow Calculations
0067 ----------------------
0068
0069 The mathematical physics of rainbows and glories, John A. Adam
0070
0071 * http://ww2.odu.edu/~jadam/docs/rainbow_glory_review.pdf
0072
0073
0074
0075 Optics of a water drop
0076 ------------------------
0077
0078 * http://www.philiplaven.com/index1.html
0079
0080 Fig 4, Provides relative intensities of S/P-polarizations
0081 at each step for primary bow.
0082
0083
0084 Thru multiple Relect/Transmit : is S/P polarization retained ?
0085 ------------------------------------------------------------------
0086
0087 S/P polarization is defined with respect to the surface normal
0088 at the point if incidence.
0089
0090 Every reflection/transmission happens in the same plane, so that
0091 suggests
0092
0093
0094
0095 Maybe the assumption of constant polarization
0096 state is in fact a valid one ?
0097
0098 * does this depend on the geometry
0099
0100
0101
0102
0103
0104
0105
0106 """
0107 import os, logging, numpy as np
0108 log = logging.getLogger(__name__)
0109
0110 import matplotlib.pyplot as plt
0111 from opticks.ana.base import opticks_environment
0112 from opticks.ana.droplet import Droplet
0113
0114
0115 class XRainbow(object):
0116 def __init__(self, w, boundary, k=1 ):
0117 """
0118 :param w: wavelength array
0119 :param boundary: instance
0120 :param k: 1.. rainbow index, -1 direct reflection
0121
0122 Attributes:
0123
0124 i
0125 incident angle of minimum deviation
0126 d
0127 total deviation angle at minimum deviation
0128 n
0129 refractive indices corresponding to wavelength array
0130
0131
0132 There is symmetry about the ray at normal incidence so consider
0133 a half illuminated drop.
0134
0135 Deviation angles are calculated in range 0:360 degrees
0136
0137 k red blue
0138 1 137.63 139.35
0139 2 230.37 233.48
0140
0141
0142 0:180
0143 signifies rays exiting in hemisphere opposite
0144 to the incident hemisphere
0145
0146 180:360
0147 signifies rays exiting in same hemisphere
0148 as incidence
0149
0150
0151 ::
0152
0153 In [8]: xbow.dv
0154 Out[8]:
0155 array([ 2.553, 2.553, 2.553, 2.553, 2.553, 2.553, 2.553, 2.553,
0156 2.513, 2.488, 2.47 , 2.456, 2.447, 2.441, 2.435, 2.43 ,
0157 2.426, 2.422, 2.42 , 2.418, 2.416, 2.414, 2.412, 2.41 ,
0158 2.408, 2.407, 2.407, 2.405, 2.405, 2.403, 2.402, 2.402,
0159 2.402, 2.4 , 2.4 , 2.4 , 2.399, 2.397, 2.397])
0160
0161 In [9]: xbow.w
0162 Out[9]:
0163 array([ 60. , 79.737, 99.474, 119.211, 138.947, 158.684,
0164 178.421, 198.158, 217.895, 237.632, 257.368, 277.105,
0165 296.842, 316.579, 336.316, 356.053, 375.789, 395.526,
0166 415.263, 435. , 454.737, 474.474, 494.211, 513.947,
0167 533.684, 553.421, 573.158, 592.895, 612.632, 632.368,
0168 652.105, 671.842, 691.579, 711.316, 731.053, 750.789,
0169 770.526, 790.263, 810. ])
0170
0171
0172 """
0173 self.boundary = boundary
0174 self.droplet = Droplet(boundary)
0175 self.w = w
0176 self.k = k
0177
0178 redblue = np.array([780., 380.])
0179 self.dvr = self.droplet.deviation_angle(redblue, k)
0180 self.dv = self.droplet.deviation_angle(w, k)
0181
0182
0183 def dbins(self, nb, window=[-0.5,0.5]):
0184 """
0185 :param nb: number of bins
0186 :param window: degress of window around predicted min/max deviation
0187 """
0188 d = self.dvr
0189 dmin = d.min() + window[0]*deg
0190 dmax = d.max() + window[1]*deg
0191 return np.linspace(dmin,dmax, nb)
0192
0193
0194 def refractive_index(self):
0195 """
0196 Plateau in refractive index below 330nm for Glass,
0197 edge of data artifact
0198
0199 ::
0200
0201 xbow.refractive_index()
0202 plt.show()
0203
0204 """
0205 wd = np.arange(80,820,10)
0206 nd = self.boundary.imat.refractive_index(wd)
0207
0208 plt.plot(wd, nd)
0209
0210 return wd, nd
0211
0212
0213
0214 class XFrac(object):
0215 """
0216 S-pol/P-pol (polarized perperndicular/parallel to plane of incidence) intensity fraction
0217 """
0218 def __init__(self, n, k=np.arange(1,6)):
0219
0220 i = np.arccos( np.sqrt((n*n - 1.)/(k*(k+2.)) ))
0221 r = np.arcsin( np.sin(i)/n )
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234 fs = np.power( np.sin(i-r)/np.sin(i+r) , 2 )
0235 ts = 1 - fs
0236 s = ts*ts*np.power(fs, k)
0237
0238
0239 fp = np.power( np.tan(i-r)/np.tan(i+r) , 2 )
0240 tp = 1 - fp
0241 p = tp*tp*np.power(fp, k)
0242
0243
0244 kk = np.sqrt( k*k + k + 1 )
0245 qq = (kk - 1)/(kk + 1)
0246 pq = np.power((1-qq*qq),2)*np.power(qq, 2*k)
0247
0248 self.i = i
0249 self.r = r
0250
0251 self.fp = fp
0252 self.tp = tp
0253 self.p = p
0254
0255 self.fs = fs
0256 self.ts = ts
0257 self.s = s
0258
0259 self.t = s + p
0260
0261
0262 self.kk = kk
0263 self.qq = qq
0264 self.pq = pq
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275 if __name__ == '__main__':
0276 logging.basicConfig(level=logging.INFO)
0277 opticks_environment()
0278
0279 from opticks.ana.boundary import Boundary
0280
0281 boundary = Boundary("Vacuum///MainH2OHale")
0282
0283 w = np.linspace(60.,810., 39)
0284
0285 k = 1
0286
0287 xbow = XRainbow(w, boundary, k=k )
0288
0289
0290