Skip to content

Commit 62e08a2

Browse files
committed
Added Inferred Temperature Advection.
1 parent 79cc1a2 commit 62e08a2

6 files changed

Lines changed: 202 additions & 39 deletions

File tree

Binary file not shown.
Binary file not shown.
4.31 KB
Binary file not shown.
168 Bytes
Binary file not shown.

src/com/ameliaWx/soundingViewer/SoundingFrame.java

Lines changed: 187 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ public class SoundingFrame extends JFrame {
215215

216216
private HazType[] hazType = new HazType[3];
217217

218-
private SoundingGraphics g;
218+
private SoundingGraphics sg;
219219
private MapInset mapInset;
220220

221221
private static HashMap<PrecipitationType, String> ptypeNames = new HashMap<>();
@@ -268,7 +268,8 @@ public class SoundingFrame extends JFrame {
268268
}
269269

270270
public SoundingFrame(String soundingSource, Sounding sounding0, DateTime time0, Sounding soundingM, DateTime timeM,
271-
Sounding sounding1, DateTime time1, double lat, double lon, double windOffsetAngle, MapInset mapInset) {
271+
Sounding sounding1, DateTime time1, double lat, double lon, double windOffsetAngle, MapInset mapInset,
272+
JFrame parentFrame) {
272273
this.soundingSource = soundingSource;
273274

274275
this.lat = lat;
@@ -280,15 +281,15 @@ public SoundingFrame(String soundingSource, Sounding sounding0, DateTime time0,
280281
this.windOffsetAngle = windOffsetAngle;
281282

282283
this.setSize(1750, 900);
283-
this.setLocationRelativeTo(null);
284+
this.setLocationRelativeTo(parentFrame);
284285
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
285286

286287
this.setTitle(generateTitle(this.timeM));
287288

288289
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
289290

290-
g = new SoundingGraphics();
291-
this.add(g);
291+
sg = new SoundingGraphics();
292+
this.add(sg);
292293

293294
this.addKeyListener(new SoundingKeyListener());
294295

@@ -645,10 +646,48 @@ public SoundingFrame(String soundingSource, Sounding sounding0, DateTime time0,
645646
hazType[1] = determineHazType();
646647
}
647648

649+
public SoundingFrame(Sounding soundingM, JFrame parentFrame) {
650+
this("", soundingM, null, -1024.0, -1024.0, 0, null, parentFrame);
651+
}
652+
653+
public SoundingFrame(Sounding soundingM, DateTime d, JFrame parentFrame) {
654+
this("", soundingM, d, -1024.0, -1024.0, 0, null, parentFrame);
655+
}
656+
657+
public SoundingFrame(Sounding soundingM, DateTime timeM, double lat, double lon, JFrame parentFrame) {
658+
this("", soundingM, timeM, lat, lon, 0, null, parentFrame);
659+
}
660+
661+
public SoundingFrame(String soundingSource, Sounding soundingM, JFrame parentFrame) {
662+
this(soundingSource, soundingM, null, -1024.0, -1024.0, 0, null, parentFrame);
663+
}
664+
665+
public SoundingFrame(String soundingSource, Sounding soundingM, DateTime timeM, double lat, double lon, JFrame parentFrame) {
666+
this(soundingSource, soundingM, timeM, lat, lon, 0, null, parentFrame);
667+
}
668+
669+
public SoundingFrame(String soundingSource, Sounding soundingM, DateTime timeM, double lat, double lon,
670+
MapInset mapInset, JFrame parentFrame) {
671+
this(soundingSource, soundingM, timeM, lat, lon, 0, mapInset, parentFrame);
672+
}
673+
674+
public SoundingFrame(String soundingSource, Sounding soundingM, DateTime timeM, double lat, double lon,
675+
double windOffsetAngle, MapInset mapInset, JFrame parentFrame) {
676+
this(soundingSource, null, null, soundingM, timeM, null, null, lat, lon, windOffsetAngle, mapInset, parentFrame);
677+
}
678+
679+
public SoundingFrame(String soundingSource, Sounding sounding0, DateTime time0, Sounding soundingM, DateTime timeM,
680+
Sounding sounding1, DateTime time1, double lat, double lon, double windOffsetAngle, MapInset mapInset) {
681+
}
682+
648683
public SoundingFrame(Sounding soundingM) {
649684
this("", soundingM, null, -1024.0, -1024.0, 0, null);
650685
}
651686

687+
public SoundingFrame(Sounding soundingM, DateTime d) {
688+
this("", soundingM, d, -1024.0, -1024.0, 0, null);
689+
}
690+
652691
public SoundingFrame(Sounding soundingM, DateTime timeM, double lat, double lon) {
653692
this("", soundingM, timeM, lat, lon, 0, null);
654693
}
@@ -658,7 +697,10 @@ public SoundingFrame(String soundingSource, Sounding soundingM) {
658697
}
659698

660699
public SoundingFrame(String soundingSource, Sounding soundingM, DateTime timeM, double lat, double lon) {
661-
this(soundingSource, soundingM, timeM, lat, lon, 0, null);
700+
// String soundingSource, Sounding sounding0, DateTime time0, Sounding soundingM, DateTime timeM,
701+
// Sounding sounding1, DateTime time1, double lat, double lon, double windOffsetAngle, MapInset mapInset,
702+
// JFrame parentFrame
703+
this(soundingSource, soundingM, timeM, lat, lon, 0, null, null);
662704
}
663705

664706
public SoundingFrame(String soundingSource, Sounding soundingM, DateTime timeM, double lat, double lon,
@@ -675,6 +717,27 @@ public SoundingFrame(String soundingSource, Sounding soundingM, DateTime timeM,
675717
private int activeReadoutSet = 1;
676718

677719
private int stormMotionVector = 2; // 0 = LM, 1 = MW, 2 = RM
720+
721+
public BufferedImage printChart(int width, int height, String text) {
722+
System.out.println(sg);
723+
BufferedImage chart = sg.drawSoundingChart(width, height);
724+
725+
BufferedImage bg = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
726+
Graphics g = bg.createGraphics();
727+
728+
g.setColor(Color.BLACK);
729+
g.fillRect(0, 0, width, height);
730+
731+
g.drawImage(chart, 0, 0, null);
732+
733+
g.setFont(new Font(Font.MONOSPACED, Font.BOLD, 24));
734+
735+
g.setColor(Color.WHITE);
736+
drawCenteredString(text, (Graphics2D) g, width/2, 20);
737+
738+
g.dispose();
739+
return bg;
740+
}
678741

679742
private class SoundingGraphics extends JComponent {
680743
private static final long serialVersionUID = 1649550301315411744L;
@@ -700,12 +763,12 @@ public void paintComponent(Graphics g) {
700763
private static final String AUTHOR_MESSAGE = "MADE BY AMELIA URQUHART | PRESS 'C' FOR CONTROLS";
701764

702765
private BufferedImage drawSoundingChart(int width, int height) {
703-
double scaleW = width / 1750.0;
766+
double scaleW = width / 1850.0;
704767
double scaleH = height / 900.0;
705768

706769
double scale = Double.min(scaleW, scaleH);
707770

708-
BufferedImage chart = new BufferedImage((int) (1750 * scale), (int) (900 * scale),
771+
BufferedImage chart = new BufferedImage((int) (1850 * scale), (int) (900 * scale),
709772
BufferedImage.TYPE_4BYTE_ABGR);
710773
Graphics2D g = chart.createGraphics();
711774
g.setStroke(thickStroke);
@@ -717,59 +780,66 @@ private BufferedImage drawSoundingChart(int width, int height) {
717780
g.drawImage(skewT, (int) (50 * scale), (int) (50 * scale), (int) (850 * scale), (int) (850 * scale), 0, 0,
718781
skewT.getWidth(), skewT.getHeight(), null);
719782

783+
BufferedImage tempAdvection = drawTemperatureAdvection(scale);
784+
g.drawImage(tempAdvection, (int) (875 * scale), (int) (50 * scale), (int) (950 * scale), (int) (850 * scale),
785+
0, 0, tempAdvection.getWidth(), tempAdvection.getHeight(), null);
786+
720787
BufferedImage hodograph = drawHodograph(scale);
721-
g.drawImage(hodograph, (int) (875 * scale), (int) (50 * scale), (int) (1275 * scale), (int) (450 * scale),
788+
g.drawImage(hodograph, (int) (975 * scale), (int) (50 * scale), (int) (1375 * scale), (int) (450 * scale),
722789
0, 0, hodograph.getWidth(), hodograph.getHeight(), null);
723790

724791
if (mapInset != null) {
725792
BufferedImage mapInsetImg = mapInset.drawMapInset(lat, lon, 1, (int) (400 * scale));
726-
g.drawImage(mapInsetImg, (int) (1300 * scale), (int) (50 * scale), (int) (1700 * scale),
793+
g.drawImage(mapInsetImg, (int) (1400 * scale), (int) (50 * scale), (int) (1800 * scale),
727794
(int) (450 * scale), 0, 0, mapInsetImg.getWidth(), mapInsetImg.getHeight(), null);
728795
}
729796

730797
BufferedImage stormSlinky = drawStormSlinky(scale);
731-
g.drawImage(stormSlinky, (int) (875 * scale), (int) (475 * scale), (int) (1062.5 * scale),
798+
g.drawImage(stormSlinky, (int) (975 * scale), (int) (475 * scale), (int) (1162.5 * scale),
732799
(int) (650 * scale), 0, 0, stormSlinky.getWidth(), stormSlinky.getHeight(), null);
733800

734801
BufferedImage streamwiseVorticity = drawVorticityPlot(scale);
735-
g.drawImage(streamwiseVorticity, (int) (875 * scale), (int) (675 * scale), (int) (1062.5 * scale),
802+
g.drawImage(streamwiseVorticity, (int) (975 * scale), (int) (675 * scale), (int) (1162.5 * scale),
736803
(int) (850 * scale), 0, 0, streamwiseVorticity.getWidth(), streamwiseVorticity.getHeight(), null);
737804

738805
BufferedImage severeReadouts = drawSevereReadouts(scale);
739-
g.drawImage(severeReadouts, (int) (1087.5 * scale), (int) (475 * scale), (int) (1487.5 * scale),
806+
g.drawImage(severeReadouts, (int) (1187.5 * scale), (int) (475 * scale), (int) (1587.5 * scale),
740807
(int) (850 * scale), 0, 0, severeReadouts.getWidth(), severeReadouts.getHeight(), null);
741808

742809
BufferedImage winterReadouts = drawWinterReadouts(scale);
743-
g.drawImage(winterReadouts, (int) (1512.5 * scale), (int) (475 * scale), (int) (1700 * scale),
810+
g.drawImage(winterReadouts, (int) (1612.5 * scale), (int) (475 * scale), (int) (1800 * scale),
744811
(int) (650 * scale), 0, 0, winterReadouts.getWidth(), winterReadouts.getHeight(), null);
745812

746813
BufferedImage hazardType = drawHazardType(scale);
747-
g.drawImage(hazardType, (int) (1512.5 * scale), (int) (675 * scale), (int) (1700 * scale),
814+
g.drawImage(hazardType, (int) (1612.5 * scale), (int) (675 * scale), (int) (1800 * scale),
748815
(int) (850 * scale), 0, 0, hazardType.getWidth(), hazardType.getHeight(), null);
749816

750817
// skew-t frame
751818
g.drawRect((int) (50 * scale), (int) (50 * scale), (int) (800 * scale), (int) (800 * scale));
819+
820+
// temperature advection frame
821+
g.drawRect((int) (875 * scale), (int) (50 * scale), (int) (75 * scale), (int) (800 * scale));
752822

753823
// hodograph frame
754-
g.drawRect((int) (875 * scale), (int) (50 * scale), (int) (400 * scale), (int) (400 * scale));
824+
g.drawRect((int) (975 * scale), (int) (50 * scale), (int) (400 * scale), (int) (400 * scale));
755825

756826
// map inset frame
757-
g.drawRect((int) (1300 * scale), (int) (50 * scale), (int) (400 * scale), (int) (400 * scale));
827+
g.drawRect((int) (1400 * scale), (int) (50 * scale), (int) (400 * scale), (int) (400 * scale));
758828

759829
// storm slinky frame
760-
g.drawRect((int) (875 * scale), (int) (475 * scale), (int) (187.5 * scale), (int) (175 * scale));
830+
g.drawRect((int) (975 * scale), (int) (475 * scale), (int) (187.5 * scale), (int) (175 * scale));
761831

762832
// streamwise vorticity frame
763-
g.drawRect((int) (875 * scale), (int) (675 * scale), (int) (187.5 * scale), (int) (175 * scale));
833+
g.drawRect((int) (975 * scale), (int) (675 * scale), (int) (187.5 * scale), (int) (175 * scale));
764834

765835
// severe readout frame
766-
g.drawRect((int) (1087.5 * scale), (int) (475 * scale), (int) (400 * scale), (int) (375 * scale));
836+
g.drawRect((int) (1187.5 * scale), (int) (475 * scale), (int) (400 * scale), (int) (375 * scale));
767837

768838
// winter readout frame
769-
g.drawRect((int) (1512.5 * scale), (int) (475 * scale), (int) (187.5 * scale), (int) (175 * scale));
839+
g.drawRect((int) (1612.5 * scale), (int) (475 * scale), (int) (187.5 * scale), (int) (175 * scale));
770840

771841
// haz type frame
772-
g.drawRect((int) (1512.5 * scale), (int) (675 * scale), (int) (187.5 * scale), (int) (175 * scale));
842+
g.drawRect((int) (1612.5 * scale), (int) (675 * scale), (int) (187.5 * scale), (int) (175 * scale));
773843

774844
// skew-t labels
775845
if (scale > 0.693) {
@@ -783,9 +853,12 @@ private BufferedImage drawSoundingChart(int width, int height) {
783853
drawCenteredString(i + "C", g, x, (int) (860 * scale));
784854
}
785855
}
856+
857+
// temp advection label
858+
drawCenteredString("K hr^-1", g, (int) (912.5 * scale), (int) (860 * scale));
786859

787860
// hodograph label
788-
drawCenteredString("1 RING = 10 KT", g, (int) (1075 * scale), (int) (460 * scale));
861+
drawCenteredString("1 RING = 10 KT", g, (int) (1175 * scale), (int) (460 * scale));
789862

790863
// time labels
791864
g.setColor(Color.WHITE);
@@ -1259,6 +1332,82 @@ private BufferedImage drawSkewT(double scale, ParcelPath pathType) {
12591332
return skewT;
12601333
}
12611334

1335+
private static final double THERMAL_WIND_DP = 5000;
1336+
private BufferedImage drawTemperatureAdvection(double scale) {
1337+
BufferedImage advection = new BufferedImage((int) (75 * scale), (int) (800 * scale),
1338+
BufferedImage.TYPE_4BYTE_ABGR);
1339+
Graphics2D g = advection.createGraphics();
1340+
g.setStroke(thickStroke);
1341+
g.setFont(CAPTION_FONT);
1342+
1343+
double[] pressure = activeSounding.getPressureLevels();
1344+
double[] height = activeSounding.getHeight();
1345+
double[] uWind = activeSounding.getUWind();
1346+
double[] vWind = activeSounding.getVWind();
1347+
1348+
double surfacePressure = pressure[pressure.length - 1];
1349+
1350+
ArrayList<Double> temperatureAdvection = new ArrayList<>();
1351+
ArrayList<Double> lowerLimits = new ArrayList<>();
1352+
ArrayList<Double> upperLimits = new ArrayList<>();
1353+
1354+
double tempAdvMax = 0.0;
1355+
1356+
for(double i = 10000; i < 100000; i += THERMAL_WIND_DP) {
1357+
double upperLimitPres = i;
1358+
double lowerLimitPres = i + THERMAL_WIND_DP;
1359+
1360+
if(upperLimitPres > surfacePressure) {
1361+
break;
1362+
}
1363+
1364+
if(lowerLimitPres > surfacePressure) {
1365+
lowerLimitPres = surfacePressure;
1366+
}
1367+
1368+
// System.out.println(upperLimitPres);
1369+
// System.out.println(lowerLimitPres);
1370+
1371+
double tempAdv = WeatherUtils.inferredTemperatureAdvection(pressure, height, uWind, vWind, lat, upperLimitPres, lowerLimitPres);
1372+
1373+
temperatureAdvection.add(tempAdv * 3600);
1374+
lowerLimits.add(lowerLimitPres);
1375+
upperLimits.add(upperLimitPres);
1376+
1377+
tempAdvMax = Double.max(Math.abs(tempAdvMax), Math.abs(tempAdv * 3600));
1378+
}
1379+
1380+
// System.out.println(tempAdvMax);
1381+
1382+
g.setColor(Color.GRAY);
1383+
g.drawLine((int) (37.5 * scale), (int) (0 * scale), (int) (37.5 * scale), (int) (800 * scale));
1384+
1385+
double tempAdvScaleMax = Double.max(1.2 * tempAdvMax, 3);
1386+
for (int i = 0; i < temperatureAdvection.size(); i++) {
1387+
double y1 = linScale(Math.log(10000), Math.log(110000), 0, 800, Math.log(upperLimits.get(i)));
1388+
double y2 = linScale(Math.log(10000), Math.log(110000), 0, 800, Math.log(lowerLimits.get(i)));
1389+
1390+
// System.out.printf("%5.2fK hr^-1 %6.1f mb %6.1f mb\n", temperatureAdvection.get(i), upperLimits.get(i)/100.0, lowerLimits.get(i)/100.0);
1391+
1392+
double x1 = 37.5;
1393+
double x2 = linScale(-tempAdvScaleMax, tempAdvScaleMax, 0, 75, temperatureAdvection.get(i));
1394+
1395+
if(x2 < x1) {
1396+
g.setColor(new Color(64, 64, 255));
1397+
g.drawRect((int) (x2 * scale), (int) (y1 * scale), (int) ((x1 - x2) * scale), (int) ((y2 - y1) * scale));
1398+
drawCenteredString(String.format("%3.1f", temperatureAdvection.get(i)), g, (int) (scale*23*x1/16.0), (int) (scale*(y1+y2)/2.0));
1399+
} else {
1400+
g.setColor(new Color(255, 0, 0));
1401+
g.drawRect((int) (x1 * scale), (int) (y1 * scale), (int) ((x2 - x1) * scale), (int) ((y2 - y1) * scale));
1402+
drawCenteredString(String.format("%3.1f", temperatureAdvection.get(i)), g, (int) (scale * x1/2.0), (int) (scale*(y1+y2)/2.0));
1403+
}
1404+
}
1405+
1406+
g.dispose();
1407+
1408+
return advection;
1409+
}
1410+
12621411
private BufferedImage drawHodograph(double scale) {
12631412
BufferedImage hodograph = new BufferedImage((int) (400 * scale), (int) (400 * scale),
12641413
BufferedImage.TYPE_4BYTE_ABGR);
@@ -2387,10 +2536,15 @@ private BufferedImage drawStormSlinky(double scale) {
23872536
drawLeftCenterAlignedString((int) (xArr.size() * dT) + " s", g, (int) (5 * scale), (int) (8 * scale));
23882537

23892538
// updraft tilt
2390-
double updraftHeight = zArr.get(zArr.size() - 1) - zArr.get(0);
2391-
2392-
double deltaX = xArr.get(xArr.size() - 1) - xArr.get(0);
2393-
double deltaY = yArr.get(yArr.size() - 1) - yArr.get(0);
2539+
double updraftHeight = 0;
2540+
double deltaX = 0;
2541+
double deltaY = 0;
2542+
if(zArr.size() > 0) {
2543+
updraftHeight = zArr.get(zArr.size() - 1) - zArr.get(0);
2544+
deltaX = xArr.get(xArr.size() - 1) - xArr.get(0);
2545+
deltaY = yArr.get(yArr.size() - 1) - yArr.get(0);
2546+
}
2547+
23942548
double updraftTopOffset = Math.hypot(deltaX, deltaY);
23952549

23962550
double updraftTilt = Math.toDegrees(Math.atan2(updraftTopOffset, updraftHeight));
@@ -2545,7 +2699,7 @@ public void keyPressed(KeyEvent e) {
25452699

25462700
setTitle(generateTitle(time0));
25472701

2548-
g.repaint();
2702+
sg.repaint();
25492703
}
25502704
break;
25512705
case KeyEvent.VK_2:
@@ -2555,7 +2709,7 @@ public void keyPressed(KeyEvent e) {
25552709

25562710
setTitle(generateTitle(timeM));
25572711

2558-
g.repaint();
2712+
sg.repaint();
25592713
}
25602714
break;
25612715
case KeyEvent.VK_3:
@@ -2565,23 +2719,23 @@ public void keyPressed(KeyEvent e) {
25652719

25662720
setTitle(generateTitle(time1));
25672721

2568-
g.repaint();
2722+
sg.repaint();
25692723
}
25702724
break;
25712725
case KeyEvent.VK_C:
25722726
openControlsPage();
25732727
break;
25742728
case KeyEvent.VK_E:
25752729
showEntrainment = !showEntrainment;
2576-
g.repaint();
2730+
sg.repaint();
25772731
break;
25782732
case KeyEvent.VK_P:
25792733
selectParcelPathType();
2580-
g.repaint();
2734+
sg.repaint();
25812735
break;
25822736
case KeyEvent.VK_S:
25832737
selectStormMotionVector();
2584-
g.repaint();
2738+
sg.repaint();
25852739
break;
25862740
}
25872741
}

0 commit comments

Comments
 (0)