溃变(Blowup)理论之V-3θ图

    传统的气象预测立足于气压梯度力的推动,相应的信息序是气压、温度、湿度和风,并以气压系统为核心。但实际应用中,所得到的气压(或高度场)的数值是经过静力订正的,且没有大气密度的观测,使得可使用的气压信息成为了滞后信息。为此,实际重要天气往往发生于气压系统之前,降水后才见到气压系统,而致转折性天气预测屡屡失误。为此,Blowup的V-3θ预测方法中,改变了传统的信息序,即风向、风速、湿度、温度和气压,并以风向为核心。——《走进非规则》,欧阳首承、D.H.McNeil、林益著。

 附图:
溃变理论之V-3θ图

(蒋MM写的使用方法)

         V-3θ图是成都气象学院欧阳首承教授设计出来的运用图像结构来预测天气的结构预测方法,主要是根据大气中压、温、湿、风的垂直分布,判断大气滚流对天气演变的影响来预报天气转折性变化。V-3θ中的3θ指的是θ(位温)、θse(假相当位温)、θ*(假定为饱和状态下的计算值),在图中θ线位于左边,θse居中,θ*居右;而V则是探空资料中各层风向、风速的实际观测值,在图中标在θ*线上。

        滚流(即垂直方向上的涡旋流)的判断:

  • 潜在的滚流效应:
    若三条θ曲线左倾,则为非均匀结构,潜在顺时针滚流,若三条曲线右倾,潜在无滚流或逆时针滚流。
  • 现有流场的滚流效应:
    在V-3θ图上,风场在中、下层为偏南风(或东风),上层为偏北风(或西风),为顺时针滚流,有利于降水,天气将发生由好向坏的转折性变化。而风场在中、下层为偏北风(或西风),上层为偏南风(或东风),则为逆时针滚流,对降水不利,是坏天气向好天气转换的特征。

        强对流天气和暴雨天气在V-3θ图上的区别:

  • 强对流天气的主要特征:
    (1) 图中低层的θ*线与T轴成钝角,是强对流不同于暴雨的特征;
    (2) θ曲线在200hPa附近成陡然左倾或平行于P轴成拐角状态分布,表示对流层顶有超低温现象,也是强对流天气的一个特征。
    (3) 较强的强对流的“罗锅”(罗锅指θ线向左弯曲的现象)可出现3~4个,并且低层(850hPa)以下的θ*可达到360°K以上;
    (4) 大气层中层偏湿,上、下偏干;或上、下偏湿,中层偏干,即θse和θ*线形成“蜂腰”结构;
    (5) 有较强的上、下层温差(40~50℃)。
  • 暴雨天气的主要特征:
    (1) 一般暴雨基本上在对流层顶附近没有超低温现象,θ曲线原则上呈整体性向左弯曲,或中、低空呈多曲折式向左弯曲;
    (2) θse、θ*曲线以θ*-θse≤10~8℃的准平行的形式,垂直于T轴;
    (3) 风场的明显特征是大气的滚流中心下边为暖湿气流,中心的上边则为干、冷气流;
    (4) 暖湿气流至少在500hPa的高度,特大暴雨时要达到400hPa;
    (5) 降水量的等级参照预报站点东侧反气旋流场的高度。


    V3Theta.java
    001  /**
    002 
    003    处理溃变理论(成气院欧阳首承教授创立)的V-3θ资料
    004 
    005        PACKAGE: cma.cuit.blowup
    006       FILENAME: V3Theta.java
    007       LANGUAGE: Java2 v1.4
    008       ORIGINAL: c++ (CDiamondV3Theta.cpp)
    009    DESCRIPTION:
    010         CREATE: 2003-08-20
    011         UPDATE: 2006-10-02 01:31:23 根据桂林局蒋MM的要求改写为 Java 版
    012         AUTHOR: 刘泽军 (BJ0773@gmail.com)
    013     DEPARTMENT: 广西柳州市气象台/广西气象减灾研究所
    014 
    015  */
    016 
    017  /*
    018  用法:
    019       String  yyyymmddhh  = "2005072800";//UTC
    020       int width=640,height=480;
    021       BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    022       Graphics2D g = image.createGraphics();
    023 
    024       //以下两行改进线条的锯齿
    025       RenderingHints renderHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
    026       g.setRenderingHints(renderHints);
    027 
    028       //数据来源自TlogP文件(包含特性层)
    029       String  filename    = "/path/to/micaps/high/Tlogp/" + yyyymmddhh.substring(2,8) + ("00".equals(yyyymmddhh.substring(8,10))?"08":"20") + ".000";
    030       V3Theta v3t         = new V3Theta(filename);
    031 
    032       //数据来源自Micaps探空A报文处理结果(不包含特性层),可先调用cma.gmb.gmiss.GAKO来处理探空报文
    033  //  String  filename    = "/path/to/micaps/datatran/gg" + yyyymmddhh.substring(6,10) + ".dat";
    034  //  V3Theta v3t         = new V3Theta(filename, yyyymmddhh);
    035 
    036       //设置
    037       v3t.HEIGHT      = false;    //填高度值
    038       v3t.TEMPER      = false;    //填温度值
    039       v3t.DEWPT       = false;    //填露点温度值
    040       v3t.LOGP        = true;     //对数压力坐标
    041       v3t.WIND        = true;     //填风向风速
    042       v3t.BACKGROUND  = false;    //填背景网格
    043       v3t.SPECIAL     = false;    //特性层
    044 
    045       //填图
    046       v3t.plot(g, 40, 40, "59431");
    047 
    048       g.dispose();
    049 
    050  */
    051 
    052  package  cma.cuit.blowup;
    053 
    054  import  java.io.*;
    055  import  java.util.*;
    056  import  java.awt.*;
    057  import  java.lang.Math.*;
    058  import  java.text.DecimalFormat;
    059 
    060  import  cma.common.atmos.*;
    061  import  cma.micaps.diamond.datatype.*;
    062  import  cma.micaps.diamond.*;
    063 
    064  public class  V3Theta  {
    065 
    066       public static  double     VALUE   = Formula.VALUE;
    067       public  double    value   = VALUE;
    068 
    069       public  Vector   Data;        //数据
    070       public  Vector   Stations;    //区站号列表
    071       public  int       Year, Month, Day, Hour, Validate;
    072       public  boolean   Enabled;
    073 
    074       public  boolean   BACKGROUND  =  false ;         //背景网格
    075 
    076       public  boolean   LOGP        =  false ;         //对数坐标
    077       public  boolean   SPECIAL     =  false ;         //显示特性层(TlogP文件包含有特性层,DiamondGG文件不包含)
    078 
    079       public  boolean   WIND        =  true ;          //填风向风速
    080       public  boolean   HEIGHT      =  false ;         //填高度值
    081       public  boolean   TEMPER      =  false ;         //填温度值
    082       public  boolean   DEWPT       =  false ;         //填露点温度值
    083 
    084       public static  int    xZoom   =  4 ;
    085       public static  int    yZoom   =  360 ;
    086 
    087  /**
    088    * 功能:构造函数
    089    * 参数:
    090    *  filename    - DiamondGG 文件名
    091    *  yyyymmddhh  - DiamondGG 文件对应时次
    092    * 返回值:
    093    *      无
    094    */
    095       public  V3Theta ( String filename, String yyyymmddhh ) {
    096           Data        =  new  Vector () ;
    097           Stations    =  new  Vector () ;
    098           Enabled     = loadFromFile ( filename, yyyymmddhh ) ;
    099       }
    100 
    101  /**
    102    * 功能:构造函数
    103    * 参数:
    104    *  filename    - DiamondGG 文件名
    105    *  yyyymmddhh  - DiamondGG 文件对应时次
    106    * 返回值:
    107    *      无
    108    */
    109       public  V3Theta ( String filename ) {
    110           Data        =  new  Vector () ;
    111           Stations    =  new  Vector () ;
    112           Enabled     = loadFromFile ( filename ) ;
    113       }
    114 
    115  /**
    116    * 功能:加载数据(读取探空资料解码结果文件DiamondGG并计算V3Theta数据)
    117    * 参数:
    118    *  filename    - DiamondGG 文件名
    119    *  yyyymmddhh  - DiamondGG 文件对应时次
    120    * 返回值:
    121    *      无
    122    */
    123       public  boolean  loadFromFile ( String filename, String yyyymmddhh ) {
    124           try  {
    125               DiamondGG  gg =  new  DiamondGG ( filename, yyyymmddhh ) ;
    126               if !gg.Enabled  ) {
    127                   return ( false ) ;
    128               }
    129               Data.clear () ;
    130               Stations.clear () ;
    131               Year        = gg.Year;
    132               Month       = gg.Month;
    133               Day         = gg.Day;
    134               Hour        = gg.Hour;
    135               Validate    =  0 ;
    136 
    137               for ( int  i= 0 ;i<gg.Data.size () ;i++ ) {
    138                   V3ThetaData     data    =  new  V3ThetaData () ;
    139                   DiamondDataGG   temp    =  ( DiamondDataGG ) gg.Data.get ( i ) ;
    140                   data.Station    = temp.Station;
    141                   data.Longitude  = temp.Longitude;
    142                   data.Latitude   = temp.Latitude;
    143                   data.Layers     =  12 ; //探空资料解码结果仅有12层
    144                   for ( int  j= 0 ;j<data.Layers;j++ ) {
    145                       data.Item [ j ] .reset (
    146                           temp.Item [ j ] .Layer,
    147                           temp.Item [ j ] .H,
    148                           temp.Item [ j ] .T,
    149                           temp.Item [ j ] .T_Td,
    150                           temp.Item [ j ] .dd,
    151                           temp.Item [ j ] .ff
    152                       ) ;
    153                       if temp.Item [ j ] .Layer !=  600.0  ) {
    154                           data.Item [ j ] .proc () ;
    155                       }
    156                   }
    157                   Data.add ( data ) ;
    158                   Stations.add ( data.Station ) ;
    159               }
    160               return ( Data.size () > 0 ) ;
    161           }
    162           catch ( Exception ex ) {
    163               System.out.println ( ex.getMessage ()) ;
    164               ex.printStackTrace () ;
    165               return ( false ) ;
    166           }
    167       }
    168 
    169  /**
    170    * 功能:加载数据(读取探空资料解码后生成的TlogP文件Diamond05并计算V3Theta数据)
    171    * 参数:
    172    *  filename    - TlogP 文件名
    173    * 返回值:
    174    *      无
    175    */
    176       public  boolean  loadFromFile ( String filename ) {
    177           if ! ( new  File ( filename )) .exists () ) {
    178               return ( false ) ;
    179           }
    180           try  {
    181               Data.clear () ;
    182               Stations.clear () ;
    183               DecimalFormat       df          =  new  DecimalFormat ( "0" ) ;
    184               InputStreamReader   isReader    =  new  InputStreamReader ( new  FileInputStream ( filename ) "gb2312" ) ; //支持汉字
    185               BufferedReader      bufReader   =  new  BufferedReader ( isReader ) ;
    186 
    187               String  lineString;
    188               StringTokenizer st;
    189               Vector  vectorData  =  new  Vector () ;
    190               while null  !=  lineString = bufReader.readLine () ) ) {
    191                   st  =  new  StringTokenizer ( lineString, " /r/n" ) ;
    192                   while st.hasMoreTokens () ) {
    193                       vectorData.add ( st.nextToken ()) ;
    194                   }
    195               }
    196               isReader.close () ;
    197               if vectorData.size ()  ||
    198                   ! "diamond" .equalsIgnoreCase (( String ) vectorData.get ( 0 ))  || //不是Micaps数据文件
    199                   != Integer.parseInt (( String ) vectorData.get ( 1 )) ) { //不是TlogP数据文件
    200                   return ( false ) ;
    201               }
    202 
    203               Year        = Integer.parseInt (( String ) vectorData.get ( 3 )) ;
    204               Month       = Integer.parseInt (( String ) vectorData.get ( 4 )) ;
    205               Day         = Integer.parseInt (( String ) vectorData.get ( 5 )) ;
    206               Hour        = Integer.parseInt (( String ) vectorData.get ( 6 )) ;
    207               int  count   = Integer.parseInt (( String ) vectorData.get ( 7 )) ;
    208               Validate    =  0 ;
    209               int  index           =  8 ;
    210               for ( int  i= 0 ;i<count;i++ ) {
    211               if vectorData.size ()  - index >  && vectorData.size ()  - index >= Integer.parseInt (( String ) vectorData.get ( index+ 4 )) ) { //存在某站点数据且数据完整
    212                   V3ThetaData     data    =  new  V3ThetaData () ;
    213                   data.Station    =  ( String ) vectorData.get ( index++ ) ;                       //0
    214                   data.Longitude  = Double.parseDouble (( String ) vectorData.get ( index++ )) ;   //1
    215                   data.Latitude   = Double.parseDouble (( String ) vectorData.get ( index++ )) ;   //2
    216                   data.Altitude   = Double.parseDouble (( String ) vectorData.get ( index++ )) ;   //3
    217                   data.Layers     = Integer.parseInt (( String ) vectorData.get ( index++ )) / 6 ;   //4
    218  //              System.out.println(data.Station + " " + data.Longitude + " " + data.Latitude + " " + data.Altitude + " " + data.Layers);
    219                   for ( int  j= 0 ;j<data.Layers;j++ ) { //每层6个数据
    220                       data.Item [ j%V3ThetaData.LAYERS ] .layer   = Integer.parseInt (( String ) vectorData.get ( index++ )) ;     //0
    221                       data.Item [ j%V3ThetaData.LAYERS ] .h       = Double.parseDouble (( String ) vectorData.get ( index++ )) ;   //1
    222                       data.Item [ j%V3ThetaData.LAYERS ] .t       = Double.parseDouble (( String ) vectorData.get ( index++ )) ;   //2
    223                       data.Item [ j%V3ThetaData.LAYERS ] .t_td    = Double.parseDouble (( String ) vectorData.get ( index++ )) ;   //3
    224                       data.Item [ j%V3ThetaData.LAYERS ] .dd      = Integer.parseInt (( String ) vectorData.get ( index++ )) ;     //4
    225                       data.Item [ j%V3ThetaData.LAYERS ] .ff      = Integer.parseInt (( String ) vectorData.get ( index++ )) ;     //5
    226                       if data.Item [ j%V3ThetaData.LAYERS ] .t != value && data.Item [ j%V3ThetaData.LAYERS ] .t_td != value  ) {
    227                           data.Item [ j%V3ThetaData.LAYERS ] .t_td = data.Item [ j%V3ThetaData.LAYERS ] .t - data.Item [ j%V3ThetaData.LAYERS ] .t_td;
    228                       }
    229                       else  {
    230                           data.Item [ j%V3ThetaData.LAYERS ] .t_td = value;
    231                       }
    232                       data.Item [ j%V3ThetaData.LAYERS ] .proc () ;
    233                       Data.add ( data ) ;
    234                       Stations.add ( data.Station ) ;
    235                   }
    236               }
    237               }
    238               return ( Data.size () > 0 ) ;
    239           }
    240           catch ( Exception ex ) {
    241               System.out.println ( ex.getMessage ()) ;
    242               ex.printStackTrace () ;
    243               return ( false ) ;
    244           }
    245       }
    246 
    247  /**
    248    * 功能:计算V3Theta的最大值
    249    * 参数:
    250    *  data    - 站点的V-3Theta数据
    251    * 返回值:
    252    *      该站点所有层次的Theta、Thetase、Theta*的最大值
    253    */
    254       public  double  maxTheta ( V3ThetaData data ) {
    255           DecimalFormat   df      =  new  DecimalFormat ( "0" ) ;
    256           double   qMax    =  390.0 ;
    257           for ( int  i= 0 ;i<data.Layers;i++ ) {
    258               if data.Item [ i ] .q1 != value && data.Item [ i ] .q1 > qMax  ) {
    259                   qMax = data.Item [ i ] .q1;
    260               }
    261               if data.Item [ i ] .q2 != value && data.Item [ i ] .q2 > qMax  ) {
    262                   qMax = data.Item [ i ] .q2;
    263               }
    264               if data.Item [ i ] .q3 != value && data.Item [ i ] .q3 > qMax  ) {
    265                   qMax = data.Item [ i ] .q3;
    266               }
    267           }
    268           return ( qMax ) ;
    269       }
    270 
    271  /**
    272    * 功能:计算V3Theta的最小值
    273    * 参数:
    274    *  data    - 站点的V-3Theta数据
    275    * 返回值:
    276    *      该站点所有层次的Theta、Thetase、Theta*的最小值
    277    */
    278       public  double  minTheta ( V3ThetaData data ) {
    279           DecimalFormat   df      =  new  DecimalFormat ( "0" ) ;
    280           double   qMin    =  290.0 ;
    281           for ( int  i= 0 ;i<data.Layers;i++ ) {
    282               if data.Item [ i ] .q1 != value && data.Item [ i ] .q1 < qMin  ) {
    283                   qMin = data.Item [ i ] .q1;
    284               }
    285               if data.Item [ i ] .q2 != value && data.Item [ i ] .q2 < qMin  ) {
    286                   qMin = data.Item [ i ] .q2;
    287               }
    288               if data.Item [ i ] .q3 != value && data.Item [ i ] .q3 < qMin  ) {
    289                   qMin = data.Item [ i ] .q3;
    290               }
    291           }
    292           return ( qMin ) ;
    293       }
    294 
    295  /**
    296    * 功能:获得指定站号的V-3Theta数据
    297    * 参数:
    298    *  data    - 返回的数据克隆(对返回的data进行修改并不影响原始数据)
    299    *  station - 探空站的站号
    300    * 返回值:
    301    *      存在该数据并复制成功则返回true,否则返回false。
    302    */
    303       public  boolean  get ( V3ThetaData data, String station ) {
    304           if !Enabled || Data.size ()  != Stations.size ()  ||
    305               null  == station ||  "" .equals ( station ) ) {
    306               return ( false ) ;
    307           }
    308           try  {
    309               int  index   = Stations.indexOf ( station ) ;
    310               if index == - ) {
    311                   return ( false ) ;
    312               }
    313               V3ThetaData tmp =  ( V3ThetaData ) Data.get ( index ) ;
    314               if !station.equalsIgnoreCase ( tmp.Station ) ) {
    315                   return ( false ) ;
    316               }
    317               data.Station    = tmp.Station;
    318               data.Longitude  = tmp.Longitude;
    319               data.Latitude   = tmp.Latitude;
    320               data.Altitude   = tmp.Altitude;
    321               data.Layers     = tmp.Layers;
    322               for ( int  j= 0 ;j<data.Item.length;j++ ) {
    323                   data.Item [ j ] .layer  = tmp.Item [ j ] .layer;
    324                   data.Item [ j ] .h      = tmp.Item [ j ] .h;
    325                   data.Item [ j ] .t      = tmp.Item [ j ] .t;
    326                   data.Item [ j ] .t_td   = tmp.Item [ j ] .t_td;
    327                   data.Item [ j ] .dd     = tmp.Item [ j ] .dd;
    328                   data.Item [ j ] .ff     = tmp.Item [ j ] .ff;
    329                   data.Item [ j ] .q1     = tmp.Item [ j ] .q1;
    330                   data.Item [ j ] .q2     = tmp.Item [ j ] .q2;
    331                   data.Item [ j ] .q3     = tmp.Item [ j ] .q3;
    332               }
    333               return ( true ) ;
    334           }
    335           catch ( Exception ex ) {
    336               System.out.println ( ex.getMessage ()) ;
    337               ex.printStackTrace () ;
    338               return ( false ) ;
    339           }
    340       }
    341 
    342  /**
    343    * 功能:V3Theta填图
    344    * 参数:
    345    *  filename    - DiamondGG 文件名
    346    *  yyyymmddhh  - DiamondGG 文件对应时次
    347    * 返回值:
    348    *      无
    349    */
    350       public  boolean  plot ( Graphics2D g,  int  left,  int  top, String station ) {
    351           if !Enabled  ) {
    352               return ( false ) ;
    353           }
    354           V3ThetaData data =  new  V3ThetaData () ;
    355           if !get ( data, station ) ) {
    356               return ( false ) ;
    357           }
    358           DecimalFormat   df      =  new  DecimalFormat ( "0.#" ) ;
    359           DecimalFormat   dfInt   =  new  DecimalFormat ( "0" ) ;
    360           int  x [][] = {{ 0 , 0 } , { 0 , 0 } , { 0 , 0 }} , y [][] = {{ 0 , 0 } , { 0 , 0 } , { 0 , 0 }} ;
    361           boolean     p [] = { false,false,false } ;
    362           boolean     pp [] = { false,false,false } ;
    363           double   minLayerValue =  100 ;
    364           double   maxLayerValue =  1032 ;
    365           double   LayerIndex [] = { 100 , 150 , 200 , 250 , 300 , 400 , 500 , 600 , 700 , 850 , 925 , 1000 } ; //固定层次
    366           Vector  layers =  new  Vector () ;
    367           for ( int  i= 0 ;i< 12 ;i++ ) {
    368               layers.add ( df.format ( LayerIndex [ i ])) ;
    369           }
    370 
    371           FontMetrics fm  = g.getFontMetrics () ;
    372 
    373           double   qMin    = minTheta ( data ) ;
    374           double   qMax    = maxTheta ( data ) ;
    375           background ( g, left, top, data ) ; //画背景图
    376           for int  j= 0 ;j<data.Layers;j++  )
    377           if SPECIAL || //显示所有层次
    378               layers.indexOf ( df.format ( data.Item [ j ] .layer ))  != - ) { //是固定层次
    379               pp [ 0 ] = false ;
    380               pp [ 1 ] = false ;
    381               pp [ 2 ] = false ;
    382               if data.Item [ j ] .layer !=  && data.Item [ j ] .layer !=  9999  && data.Item [ j ] .q1 !=  9999  ) {
    383                   if LOGP  ) {
    384                       y [ 0 ][ 1 = Integer.parseInt ( dfInt.format ( top  +  ( Math.log ( data.Item [ j ] .layer ) -Math.log ( minLayerValue )) / ( Math.log ( maxLayerValue ) -Math.log ( minLayerValue )) *yZoom )) ;
    385                   }
    386                   else  {
    387                       y [ 0 ][ 1 = Integer.parseInt ( dfInt.format ( top  +  ( data.Item [ j ] .layer-minLayerValue ) / ( maxLayerValue-minLayerValue ) *yZoom )) ;
    388                   }
    389                   x [ 0 ][ 1 = Integer.parseInt ( dfInt.format ( left +  ( data.Item [ j ] .q1 - qMin * xZoom )) ;
    390                   if p [ 0 ==  false  ) {
    391                       p [ 0 true ;
    392                   }
    393                   else  {
    394                       g.setColor ( Color.green ) ;
    395                       g.drawLine ( x [ 0 ][ 0 ] , y [ 0 ][ 0 ] , x [ 0 ][ 1 ] , y [ 0 ][ 1 ]) ;
    396                       g.fillArc ( x [ 0 ][ 1 ] , y [ 0 ][ 1 ] 2 2 0 360 ) ;
    397                   }
    398                   x [ 0 ][ 0 = x [ 0 ][ 1 ] ;
    399                   y [ 0 ][ 0 = y [ 0 ][ 1 ] ;
    400                   pp [ 0 ] = true ;
    401               }
    402 
    403               if data.Item [ j ] .layer !=  && data.Item [ j ] .layer !=  9999  && data.Item [ j ] .q2 !=  9999  ) {
    404                   if LOGP  ) {
    405                       y [ 1 ][ 1 = Integer.parseInt ( dfInt.format ( top  +  ( Math.log ( data.Item [ j ] .layer ) -Math.log ( minLayerValue )) / ( Math.log ( maxLayerValue ) -Math.log ( minLayerValue )) *yZoom )) ;
    406                   }
    407                   else  {
    408                       y [ 1 ][ 1 = Integer.parseInt ( dfInt.format ( top  +  ( data.Item [ j ] .layer-minLayerValue ) / ( maxLayerValue-minLayerValue ) *yZoom )) ;
    409                   }
    410                   x [ 1 ][ 1 = Integer.parseInt ( dfInt.format ( left +  ( data.Item [ j ] .q2 - qMin * xZoom )) ;
    411                   if p [ 1 ==  false  ) {
    412                       p [ 1 true ;
    413                   }
    414                   else  {
    415                       g.setColor ( Color.red ) ;
    416                       g.drawLine ( x [ 1 ][ 0 ] , y [ 1 ][ 0 ] , x [ 1 ][ 1 ] , y [ 1 ][ 1 ]) ;
    417                       g.fillArc ( x [ 1 ][ 1 ] , y [ 1 ][ 1 ] 2 2 0 360 ) ;
    418                   }
    419                   x [ 1 ][ 0 = x [ 1 ][ 1 ] ;
    420                   y [ 1 ][ 0 = y [ 1 ][ 1 ] ;
    421                   pp [ 1 ] = true ;
    422               }
    423 
    424               if data.Item [ j ] .layer !=  && data.Item [ j ] .layer !=  9999  && data.Item [ j ] .q3 !=  9999  ) {
    425                   if LOGP  ) {
    426                       y [ 2 ][ 1 = Integer.parseInt ( dfInt.format ( top  +  ( Math.log ( data.Item [ j ] .layer ) -Math.log ( minLayerValue )) / ( Math.log ( maxLayerValue ) -Math.log ( minLayerValue )) *yZoom )) ;
    427                   }
    428                   else  {
    429                       y [ 2 ][ 1 = Integer.parseInt ( dfInt.format ( top  +  ( data.Item [ j ] .layer-minLayerValue ) / ( maxLayerValue-minLayerValue ) *yZoom )) ;
    430                   }
    431                   x [ 2 ][ 1 = Integer.parseInt ( dfInt.format ( left +  ( data.Item [ j ] .q3 - qMin * xZoom )) ;
    432                   if p [ 2 ==  false  ) {
    433                       p [ 2 true ;
    434                   }
    435                   else  {
    436                       g.setColor ( Color.blue ) ;
    437                       g.drawLine ( x [ 2 ][ 0 ] , y [ 2 ][ 0 ] , x [ 2 ][ 1 ] , y [ 2 ][ 1 ]) ;
    438                       g.fillArc ( x [ 2 ][ 1 ] , y [ 2 ][ 1 ] 2 2 0 360 ) ;
    439                   }
    440                   x [ 2 ][ 0 = x [ 2 ][ 1 ] ;
    441                   y [ 2 ][ 0 = y [ 2 ][ 1 ] ;
    442                   pp [ 2 ] = true ;
    443               }
    444 
    445               if pp [ 2 || pp [ 1 || pp [ 0 ] ) {
    446                   if WIND && data.Item [ j ] .dd != value && data.Item [ j ] .ff != value  ) {
    447                       g.setColor ( Color.black ) ;
    448                       Meteorology.plotWind (
    449                           g,
    450                           new  Point ( pp [ 2 ? x [ 2 ][ 1 : pp [ 1 ? x [ 1 ][ 1 : x [ 0 ][ 1 ] , pp [ 2 ? y [ 2 ][ 1 : pp [ 1 ? y [ 1 ][ 1 : y [ 0 ][ 1 ]) ,
    451                           data.Latitude >  0 ,
    452                           0 ,
    453                           data.Item [ j ] .dd,
    454                           data.Item [ j ] .ff ) ;
    455                   }
    456                   if HEIGHT && data.Item [ j ] .h != value  ) {
    457                       g.setColor ( Color.blue ) ;
    458                       g.drawString (
    459                           df.format ( data.Item [ j ] .h ) ,
    460                           ( pp [ 2 ? x [ 2 ][ 1 : pp [ 1 ? x [ 1 ][ 1 : x [ 0 ][ 1 ])  8 ,
    461                           ( pp [ 2 ? y [ 2 ][ 1 : pp [ 1 ? y [ 1 ][ 1 : y [ 0 ][ 1 ])  + fm.getHeight () / 4
    462                           ) ;
    463                   }
    464 
    465                   if TEMPER && data.Item [ j ] .t != value  ) {
    466                       g.setColor ( Color.red ) ;
    467                       g.drawString (
    468                           df.format ( data.Item [ j ] .t ) ,
    469                           ( pp [ 2 ? x [ 2 ][ 1 : pp [ 1 ? x [ 1 ][ 1 : x [ 0 ][ 1 ])  +
    470                               ( HEIGHT ? fm.bytesWidth ( df.format ( data.Item [ j ] .h ) .getBytes () 0 , df.format ( data.Item [ j ] .h ) .getBytes () .length 0 ) ,
    471                           ( pp [ 2 ? y [ 2 ][ 1 : pp [ 1 ? y [ 1 ][ 1 : y [ 0 ][ 1 ])  + fm.getHeight () / 4
    472                           ) ;
    473                   }
    474 
    475                   if DEWPT && data.Item [ j ] .t != value && data.Item [ j ] .t_td != value  ) {
    476                       g.setColor ( Color.darkGray ) ;
    477                       g.drawString (
    478                           df.format ( data.Item [ j ] .t - data.Item [ j ] .t_td ) ,
    479                           ( pp [ 2 ? x [ 2 ][ 1 : pp [ 1 ? x [ 1 ][ 1 : x [ 0 ][ 1 ])  +
    480                               ( HEIGHT ? fm.bytesWidth ( df.format ( data.Item [ j ] .h ) .getBytes () 0 , df.format ( data.Item [ j ] .h ) .getBytes () .length 0 +
    481                               ( TEMPER ? fm.bytesWidth ( df.format ( data.Item [ j ] .t ) .getBytes () 0 , df.format ( data.Item [ j ] .t ) .getBytes () .length 0 ) ,
    482                           ( pp [ 2 ? y [ 2 ][ 1 : pp [ 1 ? y [ 1 ][ 1 : y [ 0 ][ 1 ])  + fm.getHeight () / 4
    483                           ) ;
    484                   }
    485               }
    486           }
    487           return ( true ) ;
    488       }
    489 
    490  /**
    491    * 功能:画V-3Theta的背景图
    492    * 参数:
    493    *  g           - 图形设备
    494    *  left,top    - 背景图的左上角位置
    495    *  data        - 站点的V-3Theta数据
    496    * 返回值:
    497    *      无
    498    */
    499       public  void  background ( Graphics2D g,int left,int top, V3ThetaData data ) {
    500           DecimalFormat   df      =  new  DecimalFormat ( "0.#" ) ;
    501           DecimalFormat   dfInt   =  new  DecimalFormat ( "0" ) ;
    502           DecimalFormat   dfDate  =  new  DecimalFormat ( "00" ) ;
    503 
    504           int      x, y;
    505           double   maxLayerValue =  1032 ;
    506           double   minLayerValue =  100 ;
    507           Rectangle   r   =  new  Rectangle ( 0 0 1024 768 ) ;
    508           r   = g.getClipBounds ( r ) ;
    509           g.setColor ( Color.white ) ;
    510           g.fillRect ( 0 0 1024 768 ) ;
    511           g.setColor ( Color.black ) ;
    512           Font    fnt =  new  Font ( "Times New Roman" , Font.BOLD,  11 ) ;
    513           g.setFont ( fnt ) ;
    514           FontMetrics fm  = g.getFontMetrics () ;
    515           double   qMin = minTheta ( data ) ;
    516           double   qMax = maxTheta ( data ) ;
    517           double   LayerIndex [] = { 100 , 150 , 200 , 250 , 300 , 400 , 500 , 600 , 700 , 850 , 925 , 1000 } ;
    518           Vector  layers  =  new  Vector () ;
    519           for ( int  i= 0 ;i< 12 ;i++ ) {
    520               layers.add ( df.format ( LayerIndex [ i ])) ;
    521           }
    522 
    523  //数据包含的层次 - 纵坐标
    524           int  x0, y0;
    525           for int  i= 0 ;i<data.Layers;i++  )
    526           if SPECIAL || //显示所有层次
    527               layers.indexOf ( df.format ( data.Item [ i ] .layer ))  != - ) { //是固定层次
    528               x0 = left;
    529               if LOGP  ) {
    530                   y0 = Integer.parseInt ( dfInt.format ( top  +  ( Math.log ( data.Item [ i ] .layer ) -Math.log ( minLayerValue )) / ( Math.log ( maxLayerValue ) -Math.log ( minLayerValue )) *yZoom )) ;
    531               }
    532               else  {
    533                   y0 = Integer.parseInt ( dfInt.format ( top  +  ( data.Item [ i ] .layer-minLayerValue ) / ( maxLayerValue-minLayerValue ) *yZoom )) ;
    534               }
    535  //          if( i != 11 )
    536               g.setColor ( Color.black ) ;
    537                   g.drawString (
    538                       df.format ( data.Item [ i ] .layer ) ,
    539                       x0 - fm.bytesWidth ( df.format ( data.Item [ i ] .layer ) .getBytes () 0 , df.format ( data.Item [ i ] .layer ) .getBytes () .length ) - 8 ,
    540                       y0 + fm.getHeight () / 2 ) ;
    541               x = Integer.parseInt ( dfInt.format ( left +  ( qMax - qMin * xZoom )) ;
    542               if LOGP  ) {
    543                   y = Integer.parseInt ( dfInt.format ( top  +  ( Math.log ( data.Item [ i ] .layer ) -Math.log ( minLayerValue )) / ( Math.log ( maxLayerValue ) -Math.log ( minLayerValue )) *yZoom )) ;
    544               }
    545               else  {
    546                   y = Integer.parseInt ( dfInt.format ( top  +  ( data.Item [ i ] .layer-minLayerValue ) / ( maxLayerValue-minLayerValue ) *yZoom )) ;
    547               }
    548               if BACKGROUND  ) { //纵坐标网格线
    549                   g.setColor ( Color.gray ) ;
    550                   g.drawLine ( x0, y0, x, y ) ;
    551               }
    552           }
    553 
    554  //3Theta值 - 横坐标
    555           for int  i= ( new  Double ( qMin )) .intValue () ;i<= ( new  Double ( qMax )) .intValue () ;i=i+ 10  ) {
    556               x0 = Integer.parseInt ( dfInt.format ( left +  ( i - qMin * xZoom )) ;
    557               if LOGP  ) {
    558                   y0 = Integer.parseInt ( dfInt.format ( top  +  ( Math.log ( minLayerValue ) -Math.log ( minLayerValue )) / ( Math.log ( maxLayerValue ) -Math.log ( minLayerValue )) *yZoom )) ;
    559               }
    560               else  {
    561                   y0 = Integer.parseInt ( dfInt.format ( top  +  ( minLayerValue-minLayerValue ) / ( maxLayerValue-minLayerValue ) *yZoom )) ;
    562               }
    563               x = Integer.parseInt ( dfInt.format ( left +  ( i - qMin * xZoom )) ;
    564               if LOGP  ) {
    565                   y = Integer.parseInt ( dfInt.format ( top  +  ( Math.log ( maxLayerValue ) -Math.log ( minLayerValue )) / ( Math.log ( maxLayerValue ) -Math.log ( minLayerValue )) *yZoom )) ;
    566               }
    567               else  {
    568                   y = top  + yZoom;
    569               }
    570               if BACKGROUND  ) { //横坐标网格线
    571                   g.setColor ( Color.gray ) ;
    572                   g.drawLine ( x0, y0, x, y ) ;
    573               }
    574               g.setColor ( Color.black ) ;
    575               g.drawString ( df.format ( i ) , x-fm.bytesWidth ( df.format ( i ) .getBytes () 0 , df.format ( i ) .getBytes () .length ) / 2 ,y+ 5 +fm.getHeight ()) ;
    576           }
    577 
    578  //横坐标轴
    579           x = Integer.parseInt ( dfInt.format ( left +  ( qMax +  - qMin * xZoom )) ;
    580           y = Integer.parseInt ( dfInt.format ( top  + yZoom )) ;
    581           g.setColor ( Color.black ) ;
    582           g.drawLine ( left, top+yZoom, x, y ) ;
    583           g.drawLine ( x,y,x- 8 ,y+ 4 ) ; //坐标轴箭头
    584           g.drawLine ( x,y,x- 8 ,y- 4 ) ;
    585           g.setColor ( Color.black ) ;
    586           g.drawString ( "T" , x+ 12 -fm.bytesWidth ( "T" .getBytes () 0 "T" .getBytes () .length ) / 2 , y- 6 +fm.getHeight () / 2 ) ;
    587           g.drawString ( "(K)" ,x+ 12 -fm.bytesWidth ( "(K)" .getBytes () 0 "(K)" .getBytes () .length ) / 2 , y+ 6 +fm.getHeight () / 2 ) ;
    588           x = Integer.parseInt ( dfInt.format ( left +  ( qMax +  - qMin * xZoom /  2 )) ;
    589           y = Integer.parseInt ( dfInt.format ( top  + yZoom +  32 )) ;
    590           String  sTitle =  "V-3Theta"  ( Enabled ?  " " +dfDate.format ( Year ) + "-" +dfDate.format ( Month ) + "-" +dfDate.format ( Day ) + " " +dfDate.format ( Hour ) + ( Validate== 0 ? "h  " : "+" +Validate+ "h  " ) + "(" +data.Station+ ")" : "" ) ;
    591           g.drawString ( sTitle, x - fm.bytesWidth ( sTitle.getBytes () 0 , sTitle.getBytes () .length ) / 2 , y+fm.getHeight () / 2 ) ;
    592 
    593  //纵坐标轴
    594           x = left;
    595           y = Integer.parseInt ( dfInt.format ( top -  5 * 3.5 )) ;
    596           g.setColor ( Color.black ) ;
    597           g.drawLine ( left, Integer.parseInt ( dfInt.format ( top+yZoom )) , left, Integer.parseInt ( dfInt.format ( top -  5 * 3.5 ))) ;
    598           g.drawLine ( x, y, x+ 4 , y+ 8 ) ; //坐标轴箭头
    599           g.drawLine ( x, y, x- 4 , y+ 8 ) ;
    600           g.setColor ( Color.black ) ;
    601           if LOGP  ) {
    602               g.drawString ( "ln(P)" , x+ 6 , y-fm.getHeight () / 2 ) ;
    603           }
    604           else  {
    605               g.drawString ( "P" , x+ 6 , y-fm.getHeight () / 2 ) ;
    606           }
    607           g.drawString ( "hPa" , x-fm.bytesWidth ( "hPa" .getBytes () 0 "hpa" .getBytes () .length ) - 6 , y-fm.getHeight () / 2 ) ;
    608 
    609  //数据线图例
    610           g.setColor ( Color.green ) ;
    611           sTitle =  "Theta" ;
    612           x = left;
    613           y = Integer.parseInt ( dfInt.format ( top  +  ( 1 * 100 - 50 ) * 3 / 10 )) ;
    614           g.drawString ( sTitle, x+ 35 , y+fm.getHeight () / 4 ) ;
    615           g.drawLine ( x+ 10 , y, x+ 30 , y ) ;
    616 
    617           g.setColor ( Color.red ) ;
    618           sTitle =  "Theta se" ;
    619           x = left;
    620           y = Integer.parseInt ( dfInt.format ( top  +  ( 2 * 100 - 50 ) * 3 / 10 )) ;
    621           g.drawString ( sTitle, x+ 35 , y+fm.getHeight () / 4 ) ;
    622           g.drawLine ( x+ 10 , y, x+ 30 , y ) ;
    623 
    624           g.setColor ( Color.blue ) ;
    625           sTitle =  "Theta *" ;
    626           x = left;
    627           y = Integer.parseInt ( dfInt.format ( top  +  ( 3 * 100 - 50 ) * 3 / 10 )) ;
    628           g.drawString ( sTitle, x+ 35 , y+fm.getHeight () / 4 ) ;
    629           g.drawLine ( x+ 10 , y, x+ 30 , y ) ;
    630       }
    631  }

     


    V3ThetaData.java
    01  /*******************************************************************************
    02  *                                                                              *
    03  * 处理溃变理论(成气院欧阳首承教授创立)的V-3θ单层资料                           *
    04  *                                                                              *
    05  *     PACKAGE: cma.cuit.blowup                                                 *
    06  *    FILENAME: V3ThetaData.java                                                *
    07  *    LANGUAGE: Java2 v1.4                                                      *
    08  *    ORIGINAL: c++                                                             *
    09  * DESCRIPTION:                                                                 *
    10  *      CREATE: 2006-10-02 01:41:18                                             *
    11  *      UPDATE: 2006-10-02                                                      *
    12  *      AUTHOR: 刘泽军 (BJ0773@gmail.com)                                      *
    13  *                                                                              *
    14  *******************************************************************************/
    15 
    16  package  cma.cuit.blowup;
    17 
    18  public class  V3ThetaData  { //计算成都气象学院欧阳首承教授的V-3θ图单层的3个θ值
    19 
    20       public static  int  LAYERS    =  72 ; //最多层次数(根据探空资料的TlogP数据,最多有39层)
    21       public  String   Station;                          //区站号
    22       public  double    Longitude, Latitude, Altitude;       //经度  纬度  拔海高度
    23       public  int       Layers  =  12 ; //实际层次数,一般为 100 150 200 250 300 400 500 600 700 850 925 1000 标准层
    24       public  V3ThetaLayer Item []   { //72层
    25           null, null, null, null, null, null, null, null, null, null,
    26           null, null, null, null, null, null, null, null, null, null,
    27           null, null, null, null, null, null, null, null, null, null,
    28           null, null, null, null, null, null, null, null, null, null,
    29           null, null, null, null, null, null, null, null, null, null,
    30           null, null, null, null, null, null, null, null, null, null,
    31           null, null, null, null, null, null, null, null, null, null,
    32           null,  null } ;
    33 
    34       public  V3ThetaData () {
    35           for ( int  i= 0 ;i<LAYERS;i++ ) {
    36               Item [ i new  V3ThetaLayer () ;
    37           }
    38       }
    39 
    40       public  String toString () {
    41           return ( "" ) ;
    42       }
    43  }

     


    V3ThetaLayer.java
    01  /*******************************************************************************
    02  *                                                                              *
    03  * 处理溃变理论(成气院欧阳首承教授创立)的V-3θ单层资料                           *
    04  *                                                                              *
    05  *     PACKAGE: cma.cuit.blowup                                                 *
    06  *    FILENAME: V3ThetaLayer.java                                               *
    07  *    LANGUAGE: Java2 v1.4                                                      *
    08  *    ORIGINAL: c++                                                             *
    09  * DESCRIPTION:                                                                 *
    10  *      CREATE: 2006-10-02 01:36:20                                             *
    11  *      UPDATE: 2006-10-02                                                      *
    12  *      AUTHOR: 刘泽军 (BJ0773@gmail.com)                                         *
    13  *                                                                              *
    14  *******************************************************************************/
    15 
    16  package  cma.cuit.blowup;
    17 
    18  import  java.lang.*;
    19  import  java.text.DecimalFormat;
    20 
    21  import  cma.common.atmos.*;
    22  import  cma.micaps.diamond.datatype.*;
    23  import  cma.micaps.diamond.*;
    24 
    25  public class  V3ThetaLayer  { //计算成都气象学院欧阳首承教授的V-3θ图单层的3个θ值
    26       public  double    value   = Formula.VALUE; //缺省值
    27       public  int       layer; //=p
    28       public  double    h,t,t_td; //高度 温度 温度露点差
    29       public  int       dd, ff;
    30       public  double    q1,q2,q3; //位温θ(Theta),假相当位温θse(Thetase),θ*(Theta*)
    31       public  V3ThetaLayer ( int  _layer,double _h,double _t,double _t_td,int _dd,int _ff ) {
    32           reset ( _layer, _h, _t, _t_td, _dd, _ff ) ;
    33           proc () ;
    34       }
    35       public  void  reset ( int  _layer,double _h,double _t,double _t_td,int _dd,int _ff ) {
    36           DecimalFormat   df  =  new  DecimalFormat ( "0" ) ;
    37           layer   = _layer;
    38           h       = DiamondGG.VALUE == _h    ? value : _h;
    39           t       = DiamondGG.VALUE == _t    ? value : _t;
    40           t_td    = DiamondGG.VALUE == _t_td ? value : _t_td;
    41           dd      = DiamondGG.VALUE == _dd   ? Integer.parseInt ( df.format ( value ))  : _dd;
    42           ff      = DiamondGG.VALUE == _ff   ? Integer.parseInt ( df.format ( value ))  : _ff;
    43           q1      = value;
    44           q2      = value;
    45           q3      = value;
    46       }
    47       public  V3ThetaLayer () {
    48           reset ( 0 , value, value, value,  ( new  Double ( value )) .intValue () ( new  Double ( value )) .intValue ()) ;
    49       }
    50       void  proc () {
    51           double    p = layer, td = value;
    52           if t == value || t_td == value  td = value;
    53           else     td = t - t_td;
    54           q1 = Formula.blowupTheta1 ( p,t,td ) ;
    55           q2 = Formula.blowupTheta2 ( p,t,td ) ;
    56           q3 = Formula.blowupTheta3 ( p,t,td ) ;
    57       }
    58  }
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值