GHCN

package climate.investigation.ghcn;

import java.awt.*;
import java.awt.image.*;
import java.io.*;
import java.util.*;
import climate.util.*;
import climate.graphics.*;
import climate.graphics.animation.*;

import climate.types.*;
import java.text.DecimalFormat;
// ftp://ftp.ncdc.noaa.gov/pub/data/ushcn/v2.5/
// ftp://ftp.ncdc.noaa.gov/pub/data/ushcn/v2.5/ushcn-v2.5-stations.txt
//
public class GHCN{
public static final climate.util.Time TIME = climate.util.Time.get();
public static final climate.util.File FILE = new climate.util.File();
public static final DecimalFormat ONE=new DecimalFormat(“####.0”);
public static final DecimalFormat NONE=new DecimalFormat(“####”);

private static final int FRAME_DELAY = 200;
private static final int FRAME_DWELL = 3000;

//##############################################################################################################################
public static final int FIRST_YEAR    = StringVal.getInt( System.getProperty( “FIRST_YEAR”, “1965” ), 1965 );
public static final int LAST_YEAR    = StringVal.getInt( System.getProperty( “LAST_YEAR”, “2014” ), 2014 );
public static final int NUM_YEARS = LAST_YEAR-FIRST_YEAR+1;

public static final int DURATION = NUM_YEARS/2;
public static final int FIRST_END    = FIRST_YEAR + DURATION – 1;
public static final int LAST_START    = FIRST_END + 1;

public static final int FIRST50_START  = 1962;
public static final int FIRST50_END    = 1986;
public static final int LAST50_START  = 1987;
public static final int LAST50_END    = 2011;

public static final int MAX_SUMMER_MISSES = 15;
public static final int MAX_CNSCTV_MISSES = 2;

String DESCRIPTION = “NON-US GHCN Raw TMAX [“+FIRST_YEAR+” thru “+LAST_YEAR+”], excld sta mssng >”+MAX_CNSCTV_MISSES+”yrs, excld yrs mssng > “+MAX_SUMMER_MISSES+” summer days”;

//##############################################################################################################################

public static final String DATA_SET = “GHCN”;
public static final String DATA_TYPE = “TMAX”;
public static final String AREA = “NON-US”;

public static final String DATA = System.getProperty(“user.home”,””)+”/Climate/data/GHCN”;
public static final String DAILY_INVENTORY_PATH=DATA+”/ghcnd-inventory.txt”;

public static final String GHCN_DAILY_DIR=DATA+”/ghcnd_all”;
public static final String GHCN_MONTHLY_DIR=DATA+”/MONTHLY/ghcnm.v3.3.0.20161203″;

public static final String GRAPHICS_BASE = System.getProperty(“user.home”,””)+”/Climate/analysis/HOT_DAYS”;
public static final String GRAPHICS_ROOT = DATA_SET+”_”+AREA+”_”+DATA_TYPE+”_”+FIRST_YEAR+”_”+LAST_YEAR;
public static final String GRAPHICS_DIR = GRAPHICS_BASE+”/”+GRAPHICS_ROOT;
public static final String MAP_GRAPHICS_DIR = GRAPHICS_DIR+”/map”;

public static final int WIDTH = 600;
public static final int LENGTH = 400;

public static final int MAP_WIDTH = WIDTH;
public static final int MAP_LENGTH = LENGTH;

public static final int MISSING = -9999;

public static final int F110     = 10 * (int)Units.FtoC( 110f ); // Considering tenths of a degree F
public static final int F100     = 10 * (int)Units.FtoC( 100f ); // Considering tenths of a degree F
public static final int F90         = 10 * (int)Units.FtoC( 90f ); // Considering tenths of a degree F
public static final int F80        = 10 * (int)Units.FtoC( 80f ); // Considering tenths of a degree F

// #####################################################################################################

public int NUM_POSSIBLE_OBS = getNumPossibleObs(FIRST_YEAR,LAST_YEAR);

public float NUM_GOOD[] = new float[NUM_YEARS];

public float DAYS_100[] = new float[NUM_YEARS];

public float PERCENT100[] = new float[NUM_YEARS];
public float ALL_TIME_HIGH[] = new float[NUM_YEARS];

public float PERCENT_MISSING_DOW[] = new float[7];
public float PERCENT_MISSING_MOY[] = new float[12];

//##############################################################################################################################

public static final int getNumPossibleObs(int first,int last){
int num = 0;
for(int year = first; year<=last; year++){
num += 365;

if(TIME.isLeapYear(year)){
num++;
}
}
return num;
}

public boolean expected( int year,int month,int day ){
if(day<=TIME.getDaysInMonth(month)){
return true;
}

if(TIME.isLeapYear(year)&&month==2&&day==29){
return true;
}
return false;
}

// 0         1         2         3         4         5         6         7
// 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
// AEM00041194  25.2550   55.3640   10.4    DUBAI INTL                             41194
// AEM00041217  24.4330   54.6510   26.8    ABU DHABI INTL                         41217

private class COMPARE_STATION implements Comparator{
public int compare(Object g,Object station){
return ( (STATION)g).ID.compareTo(((STATION)station).ID );
}
}
private COMPARE_STATION STATION_COMPARATOR = new COMPARE_STATION();

private class COMPARE_STATION_BY_DISTANCE implements Comparator{
public int compare( Object o, Object station ){
if( ((STATION)o).DISTANCE  <  ((STATION)station).DISTANCE ){ return -1; } if( ((STATION)o).DISTANCE  >  ((STATION)station).DISTANCE ){
return 1;
}

return 0;
}
}
private COMPARE_STATION_BY_DISTANCE STATION_DISTANCE_COMPARATOR = new COMPARE_STATION_BY_DISTANCE();

public class STATION{
public String ID = “”;

public float LAT = MISSING;
public float LON = MISSING;
public float ELV = MISSING;

public float DISTANCE = MISSING;

public String NAME = “”;

public boolean GOOD_YEAR[] = new boolean[NUM_YEARS];
public boolean TRANSIENT = false;

public int YEAR_OF_ALL_TIME_HIGH = MISSING;
public int ALL_TIME_HIGH = MISSING;
public int HIGH_FOR_YEAR[] = new int[NUM_YEARS];

public int DAYS_100[] = new int[NUM_YEARS];

public int TMAX[][][]    = new int[NUM_YEARS][12][31];

public STATION( String id, float lat, float lon ){
ID = id;
LAT = lat;
LON = lon;

for(int Y = 0; Y<NUM_YEARS; Y++){
GOOD_YEAR[Y] = true;

HIGH_FOR_YEAR[Y] = MISSING;
DAYS_100[Y] = MISSING;

for(int M = 0; M<12; M++){
for(int D = 0; D<31; D++){
TMAX[Y][M][D] = MISSING;
}
}
}
}

public void print(){
System.out.println( “[“+ID+”]\t”+ONE.format(LAT)+”,”+ONE.format(LON) );
}

public void analyze(){
// If fewer than xxx missing days, it’s a good year…
for(int Y = 0; Y<NUM_YEARS; Y++){
int NUM_SUMMER_DAYS_MISSING = 0;
for(int M=0; M<12; M++){ int MONTH = M + 1; if( LAT >=0 && ( MONTH==6 || MONTH==7  ||  MONTH==8 ) ){
for(int D=0; D<31; D++){
if( expected( Y,M,D ) ){
if( TMAX[Y][M][D] <= MISSING ){
NUM_SUMMER_DAYS_MISSING++;
}
}
}
}

if( LAT for(int D=0; D<31; D++){
if( expected( Y,M,D ) ){
if( TMAX[Y][M][D] <= MISSING ){ NUM_SUMMER_DAYS_MISSING++; } } } } } if( NUM_SUMMER_DAYS_MISSING > MAX_SUMMER_MISSES ){
GOOD_YEAR[Y] = false;
}
}

int CONSECUTIVE_BAD_YEARS = 0;
int MAX_CONSECUTIVE_BAD_YEARS = 0;
for(int Y=0; Y<NUM_YEARS; Y++){ if( GOOD_YEAR[Y] ){ CONSECUTIVE_BAD_YEARS = 0; } else{ CONSECUTIVE_BAD_YEARS += 1; if( CONSECUTIVE_BAD_YEARS > MAX_CONSECUTIVE_BAD_YEARS ){
MAX_CONSECUTIVE_BAD_YEARS = CONSECUTIVE_BAD_YEARS;
}
}
}

if( MAX_CONSECUTIVE_BAD_YEARS > MAX_CNSCTV_MISSES ){
TRANSIENT = true;
}
}
}

public STATION STATIONS[] = null;

//##############################################################################################################################
//##############################################################################################################################
//##############################################################################################################################

public void readStations(){
String inventory[]=FILE.readList( DAILY_INVENTORY_PATH );
ArrayList al=new ArrayList();

for(int i=0; i<inventory.length; i++){
if(inventory[i]==null){
continue;
}

String tokens[]=StringSplit.split(inventory[i]);

//           0        1         2    3    4    5
// ASN00014628 -16.4550  134.6504 TMAX 1970 1971

if(tokens==null||tokens.length!=6){
System.out.println(“bad inventory[“+inventory[i]+”]”);
continue;
}

String ID = tokens[0];
float LAT=StringVal.getFloat(tokens[1].trim(), MISSING);
float LON=StringVal.getFloat(tokens[2].trim(), MISSING);
String TYPE=tokens[3].trim();
int FIRST=StringVal.getInt(tokens[4].trim(), MISSING);
int LAST=StringVal.getInt(tokens[5].trim(), MISSING);

if(TYPE.compareTo(DATA_TYPE)!=0){
continue;
}

if( ID.length()!=11 ){
System.out.println(“ID length not 11[“+inventory[i]+”]”);
continue;
}

if(LAT<=MISSING){
System.out.println(“bad LAT[“+inventory[i]+”]”);
continue;
}
if(LON<=MISSING){
System.out.println(“bad LON[“+inventory[i]+”]”);
continue;
}

int NUM_YEARS_OF_INTEREST=0;
for(int Y=FIRST_YEAR; Y<=LAST_YEAR; Y++){ if(Y>=FIRST&&Y<=LAST){
NUM_YEARS_OF_INTEREST++;
}
}

if(NUM_YEARS_OF_INTEREST<(.90f*NUM_YEARS)){
continue;
}

if( ID.startsWith(“US”) ){
continue;
}

STATION station = new STATION( ID, LAT, LON );
al.add(station);
}

STATIONS = ( STATION[])al.toArray( new STATION[0] );

System.out.println(“Found [“+STATIONS.length+”] stations for[“+AREA+”] [“+DATA_TYPE+”]  for[“+FIRST_YEAR+”] through [“+LAST_YEAR+”].”);
}

public void readGHCNdaily( int station ){
FileReader fr=null;
BufferedReader br=null;

// — System.out.println( “Reading[“+ GHCN_DAILY_DIR + “/” + ghcn.ID + “.dly] …” );

try{
fr=new FileReader(GHCN_DAILY_DIR+”/”+ STATIONS[station].ID + “.dly”);
br=new BufferedReader(fr);
}
catch(FileNotFoundException e){
e.printStackTrace();
return;
}
catch(SecurityException e){
e.printStackTrace();
return;
}

try{
for(;;){
String s=br.readLine();
if(s==null){
break;
}

//          if( !s.contains( “TMAX” ) ){
//             continue;
//          }
//
// 0         1         2         3         4         5         6         7         8
// 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
// USW00012839194802WT01-9999   -9999   -9999   -9999       1  X-9999       1  X-9999   -9999   -9999   -9999   -9999   -9999   -9999       1  X-9999   -9999   -9999   –
// 9999       1  X-9999       1  X-9999   -9999   -9999   -9999   -9999   -9999   -9999   -9999   -9999

//                USC00212559191106PRCP    0T 6   15  6    0T 6  122  6    0  6    0  6    0  6  170  6    0T 6  284  6   89  6    5  6    0  6    0  6    0T 6    0  6    0  6    0  6
//                  61  6    0  6    0P 6    0  6    0T 6   79  6   51  6  140  6    5  6    0  6   25  6    0  6-9999

int year=StringVal.getInt(s.substring(11, 15), MISSING );
int month=StringVal.getInt(s.substring(15, 17), MISSING );

if(year<FIRST_YEAR||year>LAST_YEAR){
continue;
}

if(month<1||month>12){
continue;
}

//               VALUE1       22-26   Integer
//               MFLAG1       27-27   Character
//               QFLAG1       28-28   Character
//               SFLAG1       29-29   Character

if( s.contains(“TMAX”) ){
for(int day=1; day<=31; day++){
int n = 21+(day-1)*8;
STATIONS[station].TMAX[year-FIRST_YEAR][month-1][day-1]=StringVal.getInt(s.substring(n, n+5).trim(), MISSING );
}
}
}
}
catch(IOException ioe){
ioe.printStackTrace();
return;
}

// Close…
try{
br.close();
fr.close();
br=null;
fr=null;
}
catch(IOException ioe){
ioe.printStackTrace();
}
}

// ###############################################################################################################
// ###############################################################################################################
// ###############################################################################################################

public void readData(){
System.out.println(“Reading Data…”);
long start=TIME.getTime();
int prevSecond=-1, second=0;

for(int s=0; s<STATIONS.length; s++){
readGHCNdaily( s );
//
//          long current=TIME.getTime();
//          long remaining=(current-start)/(s+1)*(STATIONS.length);
//
//          second=TIME.getSecond(current);
//          if(second!=prevSecond){
//             System.out.println(“\t[“+(s+1)+”]\t[“+TIME.getDurationString((current-start))+”]\tETR: “+TIME.getDurationString(remaining));
//             prevSecond=second;
//          }
}

// Analyze for missing data, consecutive bad years…
System.out.println(“Analyzing Data…”);
for(int s=0; s<STATIONS.length; s++){
STATIONS[s].analyze();
}

// Exclude transient stations…
ArrayList al=new ArrayList();
for(int s=0; s<STATIONS.length; s++){
if( ! STATIONS[s].TRANSIENT  &&  STATIONS[s].ID.length()==11 ){
al.add( STATIONS[s] );
}
}
STATIONS = null;
STATIONS = (STATION[])al.toArray( new STATION[0] );

System.out.println(“After selection, [“+ STATIONS.length+”] stations “);

System.out.println(“… done.”);
System.out.println(“Time to read and analyze[“+TIME.getDurationString(TIME.getTime()-start)+”]\n\n”);

// ———————————————————————————————————–

for(int s=0; s<STATIONS.length; s++){
for(int Y=0; Y<NUM_YEARS; Y++){
for(int M=0; M<12; M++){
for(int D=0; D<31; D++){
if( STATIONS[s].TMAX[Y][M][D] <= MISSING ){ continue; } if( STATIONS[s].TMAX[Y][M][D]  >  STATIONS[s].HIGH_FOR_YEAR[Y] ){
STATIONS[s].HIGH_FOR_YEAR[Y] = STATIONS[s].TMAX[Y][M][D];
}

if( STATIONS[s].TMAX[Y][M][D]  >  STATIONS[s].ALL_TIME_HIGH ){
STATIONS[s].ALL_TIME_HIGH = STATIONS[s].TMAX[Y][M][D];
STATIONS[s].YEAR_OF_ALL_TIME_HIGH = FIRST_YEAR + Y;
}
}
}
}
}
}

// ###############################################################################################################
// ###############################################################################################################
// ###############################################################################################################

// ##########################################################################################################################################
// ##########################################################################################################################################
// ##########################################################################################################################################
public void analyze(){

float YEARS[] = new float[NUM_YEARS];

for(int Y=0; Y<NUM_YEARS; Y++){
int YEAR = FIRST_YEAR + Y;
YEARS[Y] = (float)YEAR + 0.5f;

float NUM_STATIONS = 0f;

float SUM_100 = 0f;
for(int s=0; s<STATIONS.length; s++){
if(! STATIONS[s].GOOD_YEAR[Y] ){
continue;
}

NUM_STATIONS += 1f;

for(int M=0; M<12; M++){
for(int D=0; D<31; D++){ if( STATIONS[s].TMAX[Y][M][D] >= F100 ){
SUM_100 += 1f;
}
}
}

DAYS_100[Y] = SUM_100 / NUM_STATIONS;
}
}

float NUM_ATH_FIRST_HALF   = 0f;
float PERCENT_ATH_FIRST_HALF = 0f;
for(int Y=0; Y<NUM_YEARS; Y++){
int YEAR = FIRST_YEAR + Y;

PERCENT100[Y]                = 0f;
ALL_TIME_HIGH[Y]            = 0f;

float NUM_STATIONS            = 0f;

for(int s=0; s<STATIONS.length; s++){ if(! STATIONS[s].GOOD_YEAR[Y] ){ continue; } NUM_STATIONS += 1f; if( STATIONS[s].HIGH_FOR_YEAR[Y]  >  F100 ){
PERCENT100[Y] += 1f;
}

if( YEAR == STATIONS[s].YEAR_OF_ALL_TIME_HIGH ){
ALL_TIME_HIGH[Y] += 1f;

if( YEAR <= FIRST_END ){
NUM_ATH_FIRST_HALF += 1f;
}
}
}

PERCENT100[Y] = PERCENT100[Y] * 100f / NUM_STATIONS ;
}

PERCENT_ATH_FIRST_HALF = 100f * NUM_ATH_FIRST_HALF / STATIONS.length;

float FIRSTPERCENT100 = 0f;
for(int YEAR=FIRST_YEAR; YEAR<=FIRST_END; YEAR++){
int Y = YEAR – FIRST_YEAR;
FIRSTPERCENT100 += PERCENT100[Y];
}
FIRSTPERCENT100 /= DURATION;

float LASTPERCENT100 = 0f;
for(int YEAR=LAST_START; YEAR<=LAST_YEAR; YEAR++){
int Y = YEAR – FIRST_YEAR;
LASTPERCENT100 += PERCENT100[Y];
}
LASTPERCENT100 /= DURATION;

// ———————————————————————————————–
float MAX100 = 0f;

float FIRST100 = 0f;
for(int YEAR=FIRST_YEAR; YEAR<=FIRST_END; YEAR++){ int Y = YEAR – FIRST_YEAR; FIRST100 += DAYS_100[Y]; if( DAYS_100[Y] > MAX100 ){ MAX100 = DAYS_100[Y]; }
}
FIRST100 /= DURATION;

float LAST100 = 0f;
for(int YEAR=LAST_START; YEAR<=LAST_YEAR; YEAR++){ int Y = YEAR – FIRST_YEAR; LAST100 += DAYS_100[Y]; if( DAYS_100[Y] > MAX100 ){ MAX100 = DAYS_100[Y]; }
}
LAST100 /= DURATION;

int ALPHA = 255;
Color TMAX_COLOR = Palettes.Gold;

// ———————————————————————————————–
float mean = Stats.mean( DAYS_100 );
float std = Stats.standardDeviation( DAYS_100 );

MountainPlot heat = new MountainPlot( WIDTH,LENGTH, “Mean # Days that Non-US GHCN TMAX Reached or Exceeded 100F”, 1894,TIME.getYear(), “Year”,0f,20f,”#days”);
heat.plotData( Palettes.applyAlpha( TMAX_COLOR,ALPHA ), YEARS, DAYS_100, “”,   6 );
heat.drawLine( TMAX_COLOR.darker(), 3, FIRST_YEAR+0.5f,FIRST100, FIRST_END+0.5f,FIRST100 );
heat.drawLine( TMAX_COLOR.darker(), 3, LAST_START+0.5f,LAST100,  LAST_YEAR+0.5f,LAST100 );
heat.plotLabel( “Mean[“+FIRST_YEAR+”thru” + FIRST_END + “] “+ONE.format( FIRST100 ),1);
heat.plotLabel( “Mean[“+LAST_START+”thru” + LAST_YEAR + “] “+ONE.format( LAST100 ), 4);
heat.plotSource( DESCRIPTION, 1 );
heat.plotLabel( “POR STD[“+ONE.format(std)+”] is  “+ NONE.format(100*std/mean)+”%  of MEAN[“+ONE.format(mean)+”]”, 6);
heat.savePlot( GRAPHICS_DIR+”/”+GRAPHICS_ROOT+”_DAYS100.png” );

if( FIRST_YEAR <= 1950 ){
float FIRST_COMPARE = 0f;
for(int YEAR=FIRST50_START; YEAR<=FIRST50_END; YEAR++){
int Y = YEAR – FIRST_YEAR;
FIRST_COMPARE += DAYS_100[Y];
}
FIRST_COMPARE /= ( FIRST50_END – FIRST50_START + 1 );

float LAST_COMPARE = 0f;
for(int YEAR=LAST50_START; YEAR<=LAST50_END; YEAR++){
int Y = YEAR – FIRST_YEAR;
LAST_COMPARE += DAYS_100[Y];
}
LAST_COMPARE /= ( LAST50_END – LAST50_START + 1);

heat.drawLine( Color.BLUE, 3, FIRST50_START,FIRST_COMPARE, FIRST50_END+1,FIRST_COMPARE );
heat.drawLine( Color.BLUE, 3, LAST50_START,LAST_COMPARE,  LAST50_END+1,LAST_COMPARE );
heat.plotLabel( “Mean [“+FIRST50_START+” thru “+FIRST50_END+ “] “+ONE.format( FIRST_COMPARE ),8);
heat.plotLabel( “Mean [“+LAST50_START+”  thru ” +LAST50_END+ “] “+ONE.format( LAST_COMPARE ),5);
heat.savePlot( GRAPHICS_DIR+”/”+GRAPHICS_ROOT+”_DAYS100_FIFTY.png” );
}

// ————————————————————————————————————————–
// Plot station history of ALL….
int FACTOR=5;

BufferedImage bi = new BufferedImage( 100+FACTOR*(2016-1895),               STATIONS.length+40+20,BufferedImage.TYPE_INT_RGB);
Graphics2D G = (Graphics2D)bi.getGraphics();
G.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);

G.setColor(Color.WHITE);
G.fillRect(0,0,bi.getWidth(),bi.getHeight());

for(int s=0; s<STATIONS.length; s++){
for(int y=0; y<NUM_YEARS; y++){
int YEAR = FIRST_YEAR + y;

if(STATIONS[s].GOOD_YEAR[y]){
G.setColor(Color.GREEN);
}
else {
G.setColor(Color.GRAY);
}

G.drawLine( 100 + FACTOR*(YEAR-1895),40+s, 100+FACTOR*(YEAR-1895+1),40+s);
}
}

G.setColor(Color.BLACK);

for(int s=0; s<STATIONS.length; s++){
if((s%150)==0){
G.setColor(Color.BLACK);
G.drawString(STATIONS[s].ID,100-2-G.getFontMetrics().stringWidth(STATIONS[s].ID),40+s);
}
}

for(int YEAR=1894; YEAR<TIME.getYear(); YEAR++){ if((YEAR%50)==0){ G.drawString(“”+YEAR, 100+FACTOR*(YEAR-1895), 40+STATIONS.length+16); } if(  YEAR==1975  ){ G.drawString(“Years”, 100+FACTOR*(YEAR-1895), 40+STATIONS.length+18 ); } } G.drawString(“Station”,2,40+STATIONS.length/2+16); G.setColor(Color.BLACK); G.drawString( “USHCN TMAX, exclude missing >3 cnsctv years, [“+STATIONS.length+” stations]”,10,10);
G.drawString( “Green: available, Grey: bad year missing > 30 days”,10,24);
FILE.createDirIfNecessary(GRAPHICS_DIR);
FILE.writeBufferedImage(bi,GRAPHICS_DIR+”/”+GRAPHICS_ROOT+”_STATION_TIMELINES.png”);

// ———————————————————————
float MAXPERCENT = 0f;
for(int y=0; y<NUM_YEARS; y++){ if( PERCENT100[y] > MAXPERCENT ){ MAXPERCENT = PERCENT100[y]; }
}

float BAR = 0.25f;

DataPlot plot=new DataPlot(WIDTH, LENGTH);
plot.plotForm(“% Stations TMAX reaching 100F at least once”, “Year”, “%”, 1894,TIME.getYear(), 0, 1.1f*MAXPERCENT );

for(int y=0; y<NUM_YEARS; y++){
float YEAR=(float)(FIRST_YEAR+y)+0.5f;
plot.plotBar((float)YEAR-BAR, (float)YEAR+BAR, (int)PERCENT100[y], Palettes.applyAlpha( TMAX_COLOR, ALPHA));
}

plot.drawLine( TMAX_COLOR.darker(), 3, FIRST_YEAR, FIRSTPERCENT100, FIRST_END, FIRSTPERCENT100);
plot.drawLine( TMAX_COLOR.darker(), 3, LAST_START, LASTPERCENT100, LAST_YEAR, LASTPERCENT100);

plot.plotDataLabel( NONE.format(FIRSTPERCENT100)+”% Stations 100F at least once [“+FIRST_YEAR+” thru “+FIRST_END+”]”,  TMAX_COLOR.darker(), DataPlot.LEFT, DataPlot.TOP);
plot.plotDataLabel( NONE.format(LASTPERCENT100)+”% Stations 100F at least once [“+LAST_START+” thru “+LAST_YEAR+”]”,  TMAX_COLOR.darker(), DataPlot.RIGHT, DataPlot.TOP);
plot.plotSource( DESCRIPTION, 1 );
plot.savePlot(GRAPHICS_DIR+”/”+GRAPHICS_ROOT+”_PERCENT_100F.png”);

// ———————————————————————

float MAX = 0f;
for(int y=0; y<NUM_YEARS; y++){ if( ALL_TIME_HIGH[y] > MAX ){
MAX = ALL_TIME_HIGH[y];
}
}

plot=new DataPlot(WIDTH, LENGTH);
plot.plotForm(“# Stations with POR Highest Daily TMAX in Year”, “Year”, “#Sta”, 1894,TIME.getYear(), 0, 1.1f*MAX );
String s=”[“+(int)(PERCENT_ATH_FIRST_HALF)+”% of Period of Record High TMAX occurred before “+LAST_START+”]”;
plot.plotDataLabel(s, TMAX_COLOR.darker(), 0, 0);
plot.plotYear(LAST_START, Color.BLACK );
for(int y=0; y<NUM_YEARS; y++){
float YEAR=(float)(FIRST_YEAR+y)+0.5f;
plot.plotBar(YEAR-BAR, YEAR+BAR, ALL_TIME_HIGH[y], Palettes.applyAlpha(TMAX_COLOR, ALPHA));
}
plot.plotSource( DESCRIPTION, 1 );
plot.savePlot(GRAPHICS_DIR+”/”+GRAPHICS_ROOT+”_ALL_TIME_HIGH_TMAX.png”);

}

// #######################################################################################################
// #######################################################################################################
// #######################################################################################################

private static final int W=MAP_WIDTH;
private static final int L=MAP_LENGTH;

private static final float MIN_LAT=-90, MAX_LAT=90;
private static final float MIN_LON=-180, MAX_LON=180;

private static final float LAT_RANGE=MAX_LAT-MIN_LAT;
private static final float LON_RANGE=MAX_LON-MIN_LON;

public int getI(float lon){
return (int)((float)W*(lon-MIN_LON)/LON_RANGE);
}

public int getJ(float lat){
return (int)((float)L*(MAX_LAT-lat)/LAT_RANGE);
}

private void DRAW_LINE(float Lat1, float Lon1, float Lat2, float Lon2, int Code, Graphics2D G){
switch(Code){
default:
G.drawLine(getI(Lon1), getJ(Lat1), getI(Lon2), getJ(Lat2));
}
}

private GeoPoliticalBoundaries GP=new GeoPoliticalBoundaries(){
public void drawLine(float Lat1, float Lon1, float Lat2, float Lon2, int Code){
}

public void drawLine(float Lat1, float Lon1, float Lat2, float Lon2, int Code, Graphics2D G){
DRAW_LINE(Lat1, Lon1, Lat2, Lon2, Code, G);
}

public void setupDraw(java.awt.Graphics2D G){
G.setColor(Color.BLACK);
}
};

public void plotMaxMap(){
Color colors[]={ Color.BLACK, Color.WHITE, Color.GREEN, Palettes.Tan, Color.ORANGE, Color.RED, Palettes.Purple };

AnimatedGifEncoder AGE=new AnimatedGifEncoder();
String ANIM_PATH=GRAPHICS_DIR+”/”+GRAPHICS_ROOT+”_ANNUAL_MAX.gif”;
AGE.start(ANIM_PATH);
AGE.setRepeat(0);
AGE.setDelay(FRAME_DELAY); // 1 frame per sec

for(int Y=0; Y<NUM_YEARS; Y++){
GeoFrameRenderer.setAlpha(false);
BufferedImage BI=new BufferedImage(W, L, BufferedImage.TYPE_INT_RGB);
GeoFrameRenderer.setMap(BI, MIN_LAT, MIN_LON, MAX_LAT, MAX_LON);
Graphics2D G=(Graphics2D)BI.getGraphics();

G.setColor(Color.WHITE);
G.fillRect(0, 0, BI.getWidth(), BI.getHeight());

G.setColor(Color.BLACK);
GP.draw(G);

for(int s=0; s<STATIONS.length; s++){
if( ! STATIONS[s].GOOD_YEAR[Y]){
continue;
}

int x=getI(STATIONS[s].LON);
int y=getJ(STATIONS[s].LAT);

if( ! STATIONS[s].GOOD_YEAR[Y] ){
G.setColor(Color.LIGHT_GRAY);
}
else{
G.setColor(Palettes.Purple);
if(STATIONS[s].HIGH_FOR_YEAR[Y]<F110){
G.setColor(Color.RED);
}
if(STATIONS[s].HIGH_FOR_YEAR[Y]<F100){
G.setColor(Color.ORANGE);
}
if(STATIONS[s].HIGH_FOR_YEAR[Y]<F90){
G.setColor(Palettes.Tan);
}
if(STATIONS[s].HIGH_FOR_YEAR[Y]<F80){
G.setColor(Color.GREEN);
}
if(STATIONS[s].HIGH_FOR_YEAR[Y]<-500){ G.setColor(Color.LIGHT_GRAY); } } G.fillArc( x-2, y-2, 5,5, 0, 360 ); } G.setFont(new Font(null, Font.PLAIN, 12)); G.setColor(Color.WHITE); G.fillRect(0, 0, W, 20); G.setColor(Color.BLACK); G.drawString(“Highest Daily TMAX for year “+(FIRST_YEAR+Y), 1, 10); G.setColor(Palettes.Purple);    G.drawString(“>110F”, 350, 10 );
G.setColor(Color.RED);        G.drawString(“>100F”, 400, 10);
G.setColor(Color.ORANGE);     G.drawString(“>90F”,  450, 10);
G.setColor(Palettes.Tan);     G.drawString(“>80F”,  500, 10);

G.setFont(new Font(null, Font.PLAIN, 10));
G.setColor(Color.WHITE);
G.fillRect(0, L-18, W, 18);
G.setColor(Color.BLACK);
G.drawString( DESCRIPTION, W/2 – G.getFontMetrics().stringWidth(DESCRIPTION)/2, L-4 );

String dir=MAP_GRAPHICS_DIR+”/ANNUAL_MAX”;
FILE.createDirIfNecessary(dir);
String path=dir+”/”+GRAPHICS_ROOT+”___”+(FIRST_YEAR+Y)+”.png”;
FILE.writeBufferedImage(BI, path);

if(Y==(NUM_YEARS-1)){
AGE.setDelay(FRAME_DWELL);
}
else {
AGE.setDelay(FRAME_DELAY);
}
AGE.addFrame(BI, colors);
}
AGE.finish();
AGE=null;
}

public void plotCats(){
int TEMPS[]={  -20,-10,0,    10,20,30,    40,50,60,    70,80,90,    100,110,120,    130 };
int NUM_TEMPS=TEMPS.length;
int NUM_CATS=NUM_TEMPS-2;
// #####################################
float CATS_FIRST[]=new float[NUM_CATS];
float CATS_LAST[]=new float[NUM_CATS];

float NUM_FIRST=0f;
float NUM_LAST=0f;

for(int n=0; n<NUM_CATS; n++){
CATS_FIRST[n]=0f;
CATS_LAST[n]=0f;
}

int c = 0;
int TF = 0;
for(int s=0; s<STATIONS.length; s++){

for(int YEAR=FIRST_YEAR; YEAR<=FIRST_END; YEAR++){
int Y=YEAR-FIRST_YEAR;
if( ! STATIONS[s].GOOD_YEAR[Y] ){
continue;
}

for(int m=0; m<12; m++){
for(int d=0; d<31; d++){ if( STATIONS[s].TMAX[Y][m][d] > MISSING ){
NUM_FIRST+=1f;
for(int t=1; t<NUM_TEMPS-1; t++){ c = t-1; TF = Math.round( Units.CtoF( (float)STATIONS[s].TMAX[Y][m][d]/10f ) ); if( TF >= TEMPS[t-1]  &&  TF < TEMPS[t] ){
CATS_FIRST[c] += 1;
}
}
}
}
}
}

for(int YEAR=LAST_START; YEAR<=LAST_YEAR; YEAR++){
int Y=YEAR-FIRST_YEAR;
if( ! STATIONS[s].GOOD_YEAR[Y] ){
continue;
}

for(int m=0; m<12; m++){
for(int d=0; d<31; d++){ if( STATIONS[s].TMAX[Y][m][d] > MISSING ){
NUM_LAST+=1f;

for(int t=1; t<NUM_TEMPS-1; t++){ c=t-1; TF = Math.round( Units.CtoF( (float)STATIONS[s].TMAX[Y][m][d]/10f ) ); if( TF >= TEMPS[t-1]  &&  TF < TEMPS[t] ){
CATS_LAST[c] += 1;
}
}
}
}
}
}
}

float MAX=-99999f;
float MIN=99999f;
for(c=0; c<NUM_CATS; c++){ CATS_FIRST[c]  = 365.25f * CATS_FIRST[c]  / NUM_FIRST; CATS_LAST[c]   = 365.25f * CATS_LAST[c]   / NUM_LAST; if(CATS_FIRST[c]>MAX){
MAX = CATS_FIRST[c];
}
if(CATS_LAST[c]>MAX){
MAX = CATS_LAST[c];

}
if(CATS_FIRST[c]<MIN){
MIN = CATS_FIRST[c];
}
if(CATS_LAST[c]<MIN){
MIN = CATS_LAST[c];
}
}

// #############################################################################################################################
// #############################################################################################################################
// #############################################################################################################################

DataPlot plot=new DataPlot(WIDTH, LENGTH);
plot.plotForm(“Ave # Days TMAX Occuring For Temperature Band”, “Temperature(F)”, “#Days”, TEMPS[0], TEMPS[NUM_TEMPS-2], 0, 1.1f*MAX );
for(c=0; c<NUM_CATS; c++){
int t = c + 1;
plot.plotBar( (TEMPS[t-1]+TEMPS[t])/2f, CATS_FIRST[c],  Color.GRAY, 10 );
plot.plotBar( (TEMPS[t-1]+TEMPS[t])/2f, CATS_LAST[c],   Palettes.DarkGold,   5 );
}
plot.plotDataLabel(“Mean Occurrence of All Obs[“+FIRST_YEAR+” through “+FIRST_END+”]”, Color.GRAY, 0, 0 );
plot.plotDataLabel(“Mean Occurrence of All Obs[“+LAST_START+” through “+LAST_YEAR+”]”, Palettes.DarkGold,      2, 0 );

plot.plotSource( DESCRIPTION, 1 );
plot.savePlot(GRAPHICS_DIR+”/”+GRAPHICS_ROOT+”_BAND_COMPARISON.png”);
}

public void plotMissing(){
for(int d=0; d<7; d++){
PERCENT_MISSING_DOW[d] = 0f;
}
for(int m=0; m<12; m++){
PERCENT_MISSING_MOY[m] = 0f;
}

float NUM_DAYS = 0f;

for(int s=0; s<STATIONS.length; s++){
for(int YEAR=FIRST_YEAR; YEAR<=FIRST_END; YEAR++){
int Y=YEAR-FIRST_YEAR;
for(int m=0; m<12; m++){
for(int d=0; d<31; d++){
if( ! expected( YEAR, m+1, d+1 ) ){
continue;
}

NUM_DAYS += 1f;

if( STATIONS[s].TMAX[Y][m][d] <= MISSING ){
int DOW = TIME.getDayOfWeek(YEAR,m+1,d+1, 12,0,0 );
PERCENT_MISSING_DOW[DOW-1]    += 1f;
PERCENT_MISSING_MOY[m]        += 1f;
}
}
}
}
}

for(int d=0; d<7; d++){
PERCENT_MISSING_DOW[d] *= 100f;
PERCENT_MISSING_DOW[d] /= NUM_DAYS;
}
for(int m=0; m<12; m++){
PERCENT_MISSING_MOY[m] *= 100f;
PERCENT_MISSING_MOY[m] /= NUM_DAYS;
}

BarChart chart = new BarChart(WIDTH, LENGTH);
chart.plotForm(“Percentage Days missing by Day of the Week”,”%”, 0f,2f );
for(int d=0; d<7; d++){
chart.plot( d,7, 0f,PERCENT_MISSING_DOW[d], TIME.DAYS[d], Color.GRAY );
}
chart.plotSource( DESCRIPTION, 1 );
chart.savePlot(GRAPHICS_DIR+”/”+GRAPHICS_ROOT+”_MISSING_DOW.png”);

chart = new BarChart(WIDTH, LENGTH);
chart.plotForm(“Percentage Days missing by Month”,”%”, 0f,2f );
for(int m=0; m<12; m++){
chart.plot( m,12, 0f,PERCENT_MISSING_MOY[m], TIME.MONTHS[m], Color.GRAY );
}
chart.plotSource( DESCRIPTION, 1 );
chart.savePlot(GRAPHICS_DIR+”/”+GRAPHICS_ROOT+”_MISSING_MOY.png”);
}

public void plotAthMap(){
GeoFrameRenderer.setAlpha(false);
BufferedImage BI=new BufferedImage( W, L, BufferedImage.TYPE_INT_RGB);
GeoFrameRenderer.setMap(BI, MIN_LAT, MIN_LON, MAX_LAT, MAX_LON);
Graphics2D G=(Graphics2D)BI.getGraphics();

G.setColor(Color.WHITE);
G.fillRect(0, 0, BI.getWidth(), BI.getHeight());

G.setColor(Color.BLACK);
GP.draw(G);

for(int s=0; s<STATIONS.length; s++){
int x=getI(STATIONS[s].LON);
int y=getJ(STATIONS[s].LAT);

G.setColor( Palettes.Purple );
if( STATIONS[s].ALL_TIME_HIGH < F110 ){ G.setColor(Color.RED); }
if( STATIONS[s].ALL_TIME_HIGH< F100){
G.setColor(Color.ORANGE);
}
if( STATIONS[s].ALL_TIME_HIGH< F90){
G.setColor(Palettes.Tan);
}
if( STATIONS[s].ALL_TIME_HIGH< F80){ G.setColor(Color.GREEN); } G.fillArc(x-2, y-2, 5, 5, 0, 360); } G.setFont(new Font(null, Font.PLAIN, 12)); G.setColor(Color.WHITE); G.fillRect(0, 0, W, 20); G.setColor(Color.BLACK); G.drawString(“Period of Record Highest Daily TMAX”, 10, 10); G.setColor(Palettes.Purple); G.drawString(“>110F”, 350, 10);
G.setColor(Color.RED);
G.drawString(“>100F”, 400, 10);
G.setColor(Color.ORANGE);
G.drawString(“>90F”, 450, 10);
G.setColor(Palettes.Tan);
G.drawString(“>80F”, 500, 10);
G.setColor(Color.GREEN);
G.drawString(“<=80F”, 550, 10);

G.setFont(new Font(null, Font.PLAIN, 10));
G.setColor(Color.WHITE);
G.fillRect(0, L-18, W, 18);
G.setColor(Color.BLACK);
G.drawString( DESCRIPTION, W/2 – G.getFontMetrics().stringWidth(DESCRIPTION)/2, L-4 );

String path = GRAPHICS_DIR + “/POR_HIGH_MAP.png”;
FILE.writeBufferedImage(BI, path);
}

// #######################################################################################################
// #######################################################################################################
// #######################################################################################################

public static void main(String[] args){
System.out.println(“\n\n################################################################################################\nTMAX…\n”);

FILE.deleteTree(GRAPHICS_DIR);

FILE.createDirIfNecessary(GRAPHICS_DIR);
FILE.createDirIfNecessary(MAP_GRAPHICS_DIR);

GHCN max = new GHCN();

max.readStations();

max.readData();
max.analyze();
max.plotMaxMap();
max.plotCats();
// — max.plotMissing();
max.plotAthMap();
}
}

Advertisements
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s