Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-09 07:48:51

0001 #!/usr/bin/env python
0002 #
0003 # Copyright (c) 2019 Opticks Team. All Rights Reserved.
0004 #
0005 # This file is part of Opticks
0006 # (see https://bitbucket.org/simoncblyth/opticks).
0007 #
0008 # Licensed under the Apache License, Version 2.0 (the "License"); 
0009 # you may not use this file except in compliance with the License.  
0010 # You may obtain a copy of the License at
0011 #
0012 #   http://www.apache.org/licenses/LICENSE-2.0
0013 #
0014 # Unless required by applicable law or agreed to in writing, software 
0015 # distributed under the License is distributed on an "AS IS" BASIS, 
0016 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
0017 # See the License for the specific language governing permissions and 
0018 # limitations under the License.
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.)) ))  # bow angle
0221         r = np.arcsin( np.sin(i)/n )                    
0222 
0223         # rainbow paper 
0224         #     Jearl D. Walker p426, demo that ek1 is indep of n 
0225         #
0226         #     derivations assume that the S/P polarization will stay the same 
0227         #     across all the reflections, that seems surprising 
0228         # 
0229         #     swapped the sin and tan for S/P factors
0230         # 
0231 
0232     
0233         # perpendicular to plane of incidence, S-pol 
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         # parallel to plane of incidence, P-pol 
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