
    j1                        d Z ddlmZ ddlZddlmZ dZg dZg dZdZ	d	Z
d!d
Zd"dZd#dZd$dZd%dZd&dZd'dZd(dZd)dZd*dZd+dZd,dZd-dZd.dZd/dZd0dZd1dZd2dZd1dZd3dZd4d5dZd6dZ d4d7d Z!y)8a}  Python port of packages/engine (the CMAH guidance engine).

Must produce output identical to the JS engine for every vector in
packages/engine/vectors/cases.json (see tests/test_engine_vectors.py). The
server uses it to recompute runs on finalize (never trusting the browser),
to backfill suggestions for imported forecasts, and to replay proposed
config versions against history.
    )annotationsN)Anyz1.0.0)north	northeasteast	southeastsouth	southwestwest	northwest)uppermiddlelower      c                2    t        j                  | dz         S )z5JavaScript Math.round (half rounds toward +infinity).      ?mathfloorvs    '/var/www/avy-guidance/api/app/engine.pyjs_roundr      s    ::a#g    c                D    | y t        j                  | dz  dz         dz  S )Ng     @r   r   r   s    r   round4r      s&    y::a#gm$s**r   c                    | | dk(  st        | t              ry	 t        j                  t	        |              S # t
        t        f$ r Y yw xY w)N F)
isinstanceboolr   isnanfloat	TypeError
ValueErrorr   s    r   is_numr&   "   sK    yAGz!T2::eAh'''z" s   9 A
Ac                2    t        |       rt        |       S d S N)r&   r#   r   s    r   _numr)   +   s    ay58*d*r   c                .    t        |t        ||             S r(   )maxmin)r   lohis      r   clampr/   /   s    r3r1:r   c                    t        |       j                         j                         j                         }t	        |      dk7  s|d   t
        vs|d   t        vry |d   |d   fS )Nr   r   r   )strstripr   splitlenASPECTSBANDS)locpartss     r   parse_locationr9   6   s[    HNN""$**,E
5zQ%('1U1XU5J8U1Xr   c                t    t               }| xs g D ]$  }t        |      }|s|j                  |d          & |S )Nr   )setr9   add)	locationsoutr7   ps       r   bands_ofr@   =   s?    
%CB 3GGAaDM Jr   c                n    t        | t              r
| dk  s| dkD  ry t        | dz      dt        | dz      S )Nr          )r    intr5   r6   )cells    r   cell_to_locationrG   F   s@    dC D1Hr	dQh %	"2!344r   c                    t        |       }|sy t        j                  |d         dz  t        j                  |d         z   S )Nr   rC   r   )r9   r6   indexr5   )r7   r?   s     r   location_to_cellrJ   L   s<    sA;;qtq 7==1#666r   c                   |d   |d   |d   t        t        |       dt              dz
        } t        t        |      dt              dz
        }t        j                  |       }t        t              dz
  |dz         }| |z
  }t        j                  |      }t        t              dz
  |dz         }||z
  }dfd}	 |	||      d|z
  z   |	||      |z  z   }
 |	||      d|z
  z   |	||      |z  z   }|
d|z
  z  ||z  z   S )NsensitivitydistributionlikelihoodMatrixr   r   c                ~    t        j                  |    d         xs i j                  |   d         xs d      S )Nkeyr   )r#   get)disidistmsenss     r   rF   zinterp_likelihood.<locals>.cellc   s<    aeeDHUO,277RHMANNr   )rR   rE   rS   rE   returnr#   )r/   r#   r4   r   r   r,   )dist_possens_posconfigd0d1fds0s1fsrF   bottomtoprT   rU   rV   s               @@@r   interp_likelihoodrc   V   s   - D.!D!"AU8_aTQ7HU8_aTQ7H	H	B	SY]BF	#B	BB	H	B	SY]BF	#B	BBO "b\QV$tB|b'88F
r2,!b&
!DRL2$5
5CQVsRx''r   c           	     z   | j                  d      xs i }| j                  d      xs i }t        d |j                  d      |j                  d      |j                  d      |j                  d      fD              sy t        |d   |d   |      }t        |d   |d   |      }t        ||      t	        ||      dS )NrL   rM   c              3  2   K   | ]  }t        |        y wr(   r&   .0xs     r   	<genexpr>z#likelihood_range.<locals>.<genexpr>n   s     [Qvay[   r,   r+   r,   r+   )rQ   allrc   r,   r+   )problemrZ   sdr-   r.   s         r   likelihood_rangerq   k   s    M"(bAN#)rA[155<uquuU|QUUSX\"Z[[	1U8QuXv	6B	1U8QuXv	6Br2;s2r{33r   c                    | sg S t        t        t        j                  | d         dd            }t        t        t        j                  | d         dd            }t        t        ||dz               S )Nr,   r      r+   )rE   r/   r   r   ceillistrange)rr-   r.   s      r   likelihood_optionsrx   u   s`    		U4::ah'A.	/B	U499QuX&1-	.Bb"q&!""r   c           	     
   t        | |      }|sy | j                  d      }t        |      r7t        t	        t        t        |            dd            }|t        |      v r|S t        t	        t        |d         dd            S )NlikelihoodChoicer   rs   r+   )rq   rQ   r&   rE   r/   r   r#   rx   )rn   rZ   rw   choicecs        r   likelihood_forr}   }   sv    &)A[[+,Ff~huV}-q!45"1%%HuXah'A.//r   c                    t        |d   d         }t        t        dt        |t	        j
                  t        |       dz
                          S )NdangerTable1r   g&.>)r4   rE   r+   r,   r   rt   r#   )sizerZ   colss      r   
size_classr      sA    vm$S)*Ds1c$		%+*< =>?@@r   c                x    |d   j                  t        |             }|syt        |t        ||      dz
           S )Nr   r   r   )rQ   r1   rE   r   )
likelihoodr   rZ   rows       r   
danger_forr      s=    


#
#C
O
4Cs:dF+a/011r   c           
     T   ddddd}t         D ]  }d}| D ]w  }t        ||      }|j                  d      xs i }|rt        |j                  d            sA|t	        |j                  d            vr^t        |t        ||d   |            }y |||<   t        |d   |      |d<    |S )Nr   )r   r   r   overallr   r+   r=   r   )r6   r}   rQ   r&   r@   r+   r   )problemsrZ   r>   bandbestr?   liker   s           r   danger_suggestionsr      s    Q1
=C 3 	DA!!V,D55=&BDvdhhuo68AEE+$677tZd5k6BCD	D D	S^T2I3 Jr   c                ~    t        t        | j                  d            t        |j                  d            z        S )Nr=   )r!   r@   rQ   )abs     r   _shares_bandr      s.    {+,xk8J/KKLLr   c                x    t        | |      t        ||      }}|r|sy|d   |d   dz   k  xr |d   |d   dz   k  S )NFr,   r+   r   )rq   )r   r   rZ   rarbs        r   _likelihood_overlapr      sO    a(*:1f*EBRe95	A%D"U)r%y1}*DDr   c           	     t   | j                  d      xs i |j                  d      xs i }}t        d |j                  d      |j                  d      |j                  d      |j                  d      fD              syt        |d         t        |d         k  xr t        |d         t        |d         k  S )Nr   c              3  2   K   | ]  }t        |        y wr(   rf   rg   s     r   rj   z _size_overlap.<locals>.<genexpr>   s     _Qvay_rk   r,   r+   F)rQ   rm   r#   )r   r   sasbs       r   _size_overlapr      s    UU6] b!%%-"52B_266%="&&-PRPVPVW\P]"^__EuRY//XE"U)4DbQViHX4XXr   c                N   i }| D ]%  }|j                  d      ||t        |d         <   ' g }|j                  d      xs g D ]  }|j                  t        |d               |j                  t        |d               }}|r|sBt        ||      t        |||      t	        ||      d}|j                  d      duxr t        |j                               }	|j                  |d    d|d    t        |d         t        |d         ||	|j                  d	      d
        |S )NtypepairingRulesr   r   )locationr   r   requireJustificationF-source)rP   r   r   overlapstrongr   )rQ   rE   r   r   r   rm   valuesappend)
r   rZ   by_typer?   flagsrulepapbr   r   s
             r   pairing_flagsr      s1   !G (55=$&'GC&	N#( E

>*0b 
Sc^,gkk#d3i..IB$R,-b"f=!"b)

 01>X3w~~GWCXs)Ad3i[1c^c^" ((8,		

( Lr   c                   g | j                  d      xs g }t        | j                  d      xs g       }d5d6fd}t        |      D ]g  \  }}|j                  d      t        |d         nd }|j                  d      xs i }	t	        |	j                  d            t	        |	j                  d            }}
t	        |j                  d      xs i j                  d            }t	        |j                  d	      xs i j                  d            }||
|
|z
  d
kD  r |dddd|       |dv r|
|
dk  r||t
        k  r |dddd|       |dk(  r*|
|
dk  r |dddd|       ||t        kD  r |dddd|       |dk(  r |dddd|       |j                  d      rXg r\ |ddd d|       j |D ch c]"  }|j                  d      t        |d         $ }}d!|v rd"|v rd#|vr |d$dd%d       d&|v r|r |d'dd(d       |rt        fd)|D              }t        D cg c]   }t        |j                  |      xs d*      " }}t        |      |r0d"k\  r+t        fd+|D              rdk(  rd,nd-} |d.d| d/d0       t               }|D ]  }|t        |j                  d            z  }! t        D ];  }t        |j                  |      xs d*      dk\  s%|s(||vs- |d1dd2| d3d4       = S c c}w c c}w )7Nr   
conditionsc                4    j                  | ||||d       y )N)idleveltextr   problemIndex)r   )id_r   r   r   problem_indexr>   s        r   r<   zguidance_checks.<locals>.add   s    

#tv_lmnr   r   r   r+   r,   rL   rM   r   
size_rangewarnzXKeep the range of sizes to two or less and describe outliers in the problem description.u   FG §3.4)r   r   g      ?small_loose_or_storminfozTable 1 lists Dry Loose and Storm Slab when there is potential for ~D1.5 or larger avalanches, or a widespread pattern of small avalanches.z
FG Table 1rs      dps_sizezODeep Persistent Slab is for slabs capable of high-consequence avalanches (D3+).dps_sensitivityzDeep Persistent Slab is reserved for low likelihood / high consequence scenarios and is normally stubborn to triggers. Temporary increases are acceptable if likelihood is expected to return to low.	   glide_durationzyGlide timing is highly uncertain: consider keeping the problem for at least 48 hours after the onset of glide avalanches.r=   no_locationzSMark the aspects and elevations where the problem is most likely to be encountered.new_snow_24h   r   first_storm_on_pwlzThe first storm on a persistent weak layer should be a Storm Slab unless you expect the terrain-management considerations of a Persistent Slab.	no_hazardstructure_not_problemz|Assign a problem only when there is an associated avalanche hazard; poor structure alone belongs in the Forecast Discussion.c              3     K   | ]W  }t        |j                  d       xs i j                  d            duxr" t        |d    d         dk\  xr t        |       Y yw)r   r+   Nr   )r)   rQ   r#   r}   )rh   r?   rZ   s     r   rj   z"guidance_checks.<locals>.<genexpr>  sl      
  !%%-%2**512$> *ai&'1,*q&)*
s   AA r   c              3  (   K   | ]	  }|k    y wr(    )rh   lvlrb   s     r   rj   z"guidance_checks.<locals>.<genexpr>
  s     #@#C#I#@s   EXTREMEHIGHhigh_all_bandsz danger with D3+ avalanches should be assigned to all elevation bands unless there is a specific, explainable reason these avalanches will not affect the other elevations.u   FG §2.1band_without_problemzThe uu    band is rated Considerable or higher but no problem is located there — check the locations or explain in the text.u   FG §3.2r(   )r   r1   r   r1   r   r1   r   r1   r   
int | NonerW   None)rQ   r;   	enumeraterE   r)   
WIDESPREADSTUBBORNanyr6   r+   r@   )inputsrZ   ratingsr   r   r<   ir?   tr   s_maxs_minsens_mindist_maxtypesbigr   levelsnametouchedr>   rb   s    `                  @@r   guidance_checksr      s   Czz*%+HVZZ-34Jo (# M1eeFm7C&	NTuuV}"DHHUO,d488E?.Cu}-388?@~.4"99%@A!2uu}q7Hf  'A  CM  OP  Q;5,AUZbeoZo&  1~  @L  NO  P6 UQYJ(y  |H  JK  L#8(;%v  0w  yE  GH  I6 &  +f  ht  vw  xk"bv'|  I  KL  M'M* &.Kv1JS6^KEK#U
q~ &  +|  ~J  	Kj X#V  .l  nx  	y 
 	
 
 5::q#gkk!n)*::&k3!8#@#@ @ #q9fD &TF  3^  +_  ak  lE 	4Axk 233G	4 	AA7;;q>&Q'1,aw>N*Fd1#  >s  5t  v@  A	A J1 L ;s   :LL)%Lc           
        t        | j                  d      xs g       d |j                  d      xs d }g }|D ]b  }t        ||      }|j                  t	        |d         |rt        |d         t        |d         dnd t        |      t        ||      d       d t        ||      }t        ||t        ||      t        i | d|i||      d	S )
Nr   maxProblemsr   r   r,   r+   rl   )r   likelihoodRangelikelihoodOptionsr   )engineVersionr   suggestionspairingFlagschecks)ru   rQ   rq   r   rE   r   rx   r}   r   ENGINE_VERSIONr   r   )r   rZ   r   per_problemr?   rw   r   s          r   compute_runr     s    FJJz*0b12RFJJ}4M4RQRSHK 	
Q'AfIYZ6!E(+;F1U8DT#U`d%7%:,Q7		
	
 %Xv6K'"%h7!"BV"BZ"BFKX r   c                P   |xs i }g }t        | j                  d      xs g       D ]  \  }}|t        |d         k  r|d   |   ni }|j                  d      s|j                  |ddd       |j                  d      xs i }|j                  d      dv r|j                  |ddd       |j                  d	      rg r|j                  |d
dd        |d   D ]G  }|d   s	|j                  |d         xs dj	                         r0|j                  d|d   dd       I |S )Nr   r   z,Set the sensitivity and distribution ranges.)r   coder   r   r+   )Nr   zSet the expected size range.r=   r   z#Mark at least one aspect/elevation.r   r   rP   r   justificationz<Explain why both problems in the flagged pairing are needed.)r   pairingr   )r   rQ   r4   r   r2   )	r   computedjustificationsissuesr   r?   r|   r   fs	            r   	readinessr   0  s:   #)rNF&**Z06B7 r1'(3x
/C+D'DHZ #"uu\"MM1lLz{|uuV}"88E?j(MM1fFdefk"bMM1jJopqr n% RX; 2 21U8 < BIIKMM?qx  RP  Q  RR Mr   )r   r#   rW   rE   )r   float | NonerW   r   )r   r   rW   r!   )r   r   rW   r   )r   r#   r-   r#   r.   r#   rW   r#   )r7   r1   rW   ztuple[str, str] | None)r=   zlist[str] | NonerW   zset[str])rF   rE   rW   z
str | None)r7   r1   rW   r   )rX   r#   rY   r#   rZ   dictrW   r#   )rn   r   rZ   r   rW   dict | None)rw   r   rW   z	list[int])rn   r   rZ   r   rW   r   )r   r#   rZ   r   rW   rE   )r   rE   r   r#   rZ   r   rW   rE   )r   
list[dict]rZ   r   rW   r   )r   r   r   r   rW   r!   )r   r   r   r   rZ   r   rW   r!   )r   r   rZ   r   rW   r   r(   )r   r   rZ   r   r   r   rW   r   )r   r   rZ   r   rW   r   )r   r   r   r   r   r   rW   r   )"__doc__
__future__r   r   typingr   r   r5   r6   r   r   r   r   r&   r)   r/   r9   r@   rG   rJ   rc   rq   rx   r}   r   r   r   r   r   r   r   r   r   r   r   r   r   <module>r      s    #  
`$

++57(*4#	0A
2(MEY@5v.r   