View Javadoc
1   package au.gov.amsa.geo.distance;
2   
3   import static au.gov.amsa.geo.distance.Renderer.saveAsPng;
4   
5   import java.io.File;
6   import java.io.FileInputStream;
7   import java.io.IOException;
8   import java.io.InputStream;
9   import java.io.InputStreamReader;
10  import java.util.ArrayList;
11  import java.util.List;
12  import java.util.Map;
13  import java.util.concurrent.TimeUnit;
14  import java.util.zip.GZIPInputStream;
15  
16  import org.apache.log4j.Logger;
17  
18  import com.google.common.base.Charsets;
19  
20  import au.gov.amsa.geo.BinaryCellValuesObservable;
21  import au.gov.amsa.geo.OperatorCellValuesToBytes;
22  import au.gov.amsa.geo.Util;
23  import au.gov.amsa.geo.distance.DistanceTravelledCalculator.CalculationResult;
24  import au.gov.amsa.geo.model.Bounds;
25  import au.gov.amsa.geo.model.CellValue;
26  import au.gov.amsa.geo.model.Options;
27  import au.gov.amsa.geo.model.SegmentOptions;
28  import au.gov.amsa.navigation.ShipStaticData;
29  import au.gov.amsa.navigation.ShipStaticData.Info;
30  import au.gov.amsa.risky.format.AisClass;
31  import au.gov.amsa.util.identity.MmsiValidator2;
32  import au.gov.amsa.util.rx.OperatorWriteBytes;
33  import rx.Observable;
34  import rx.functions.Func1;
35  
36  public class DistanceTravelledMain {
37      private static Logger log = Logger.getLogger(DistanceTravelledMain.class);
38  
39      private static void run(String directory, Options options, boolean gui, String dataSetName) {
40          InputStream is;
41          try {
42              is = new GZIPInputStream(
43                      new FileInputStream("/media/an/ship-data/ais/ship-data-2014-v2.txt.gz"));
44          } catch (IOException e) {
45              throw new RuntimeException(e);
46          }
47          Map<Integer, Info> shipInfo = ShipStaticData
48                  .getMapFromReader(new InputStreamReader(is, Charsets.UTF_8));
49  
50          List<Setting> settings = new ArrayList<>();
51          settings.add(Setting.create(30, 30, "fishing"));
52          settings.add(Setting.create(52, 52, "tug"));
53          settings.add(Setting.create(60, 69, "passenger"));
54          settings.add(Setting.create(70, 79, "cargo"));
55          settings.add(Setting.create(80, 89, "tanker"));
56          settings.add(Setting.create(90, 99, "other"));
57          settings.add(Setting.create(-1, -1, "class_b"));
58          settings.add(Setting.create(0, 100, "all"));
59  
60          for (Setting setting : settings) {
61              // filter out undesired mmsi numbers and ship types
62              Func1<Info, Boolean> shipSelector = info -> info != null
63                      && ((info.cls == AisClass.B && setting.lowerBound == -1)
64                              || (info.cls == AisClass.A && (info.shipType.isPresent()
65                                      && info.shipType.get() >= setting.lowerBound
66                                      && info.shipType.get() <= setting.upperBound)))
67                      && MmsiValidator2.INSTANCE.isValid(info.mmsi);
68              calculateTrafficDensity(directory, options, gui, shipInfo, shipSelector,
69                      setting.name + "-" + dataSetName);
70          }
71      }
72  
73      private static class Setting {
74          final int lowerBound;
75          final int upperBound;
76          final String name;
77  
78          Setting(int lowerBound, int upperBound, String name) {
79              this.lowerBound = lowerBound;
80              this.upperBound = upperBound;
81              this.name = name;
82          }
83  
84          public static Setting create(int lowerBound, int upperBound, String name) {
85              return new Setting(lowerBound, upperBound, name);
86          }
87      }
88  
89      private static void calculateTrafficDensity(String directory, Options options, boolean gui,
90              Map<Integer, Info> shipInfo, Func1<Info, Boolean> shipSelector, String name) {
91          System.out.println("-----------------------------------------------------");
92          System.out.println("------ " + name);
93          System.out.println("-----------------------------------------------------");
94  
95          final Observable<File> files = Util.getFiles(directory, ".*\\.track")
96                  //
97                  .filter(file -> {
98                      String s = file.getName();
99                      String mmsiString = s.substring(0, s.indexOf(".track"));
100                     long mmsi = Long.parseLong(mmsiString);
101                     Info info = shipInfo.get(mmsi);
102                     return shipSelector.call(info);
103                 });
104 
105         CalculationResult result = DistanceTravelledCalculator.calculateTrafficDensity(options,
106                 files, 1, 1);
107 
108         if (gui) {
109             DisplayPanel.displayGui(files, options, result);
110         }
111         String filename = result.getCells()
112                 // to bytes
113                 .lift(new OperatorCellValuesToBytes(options))
114                 // save bytes to a file
115                 .lift(new OperatorWriteBytes())
116                 // get filename
117                 .toBlocking().single();
118         log.info("result saved to file " + filename);
119 
120         CalculationResult resultFromFile = new CalculationResult(BinaryCellValuesObservable
121                 .readValues(new File(filename)).skip(1).cast(CellValue.class), result.getMetrics());
122 
123         boolean produceImage = false;
124         boolean produceDensitiesText = false;
125         boolean produceDensitiesNetcdf = true;
126 
127         File outputDirectory = new File("/media/an/traffic-density/netcdf");
128 
129         if (produceImage) {
130             // 8:5 is ok ratio
131             saveAsPng(Renderer.createImage(options, 2, 12800, resultFromFile),
132                     new File(outputDirectory, name + "-map.png"));
133         }
134 
135         if (produceDensitiesText) {
136             DistanceTravelledCalculator.saveCalculationResultAsText(options, result,
137                     new File(outputDirectory, name + "-densities.txt").getAbsolutePath());
138         }
139 
140         if (produceDensitiesNetcdf) {
141             DistanceTravelledCalculator.saveCalculationResultAsNetcdf(options, result,
142                     new File(outputDirectory, name + "-densities.nc").getAbsolutePath());
143         }
144     }
145 
146     private static Options createOptions(double cellSizeDegrees) {
147         return Options.builder()
148                 // set origin latitude
149                 .originLat(0)
150                 // set origin longitudue
151                 .originLon(0)
152                 // square cell size in degrees
153                 .cellSizeDegrees(cellSizeDegrees)
154                 // set bounds
155                 .bounds(new Bounds(15, 67, -60, 179))
156                 // sabine bounds:
157                 // .bounds(new Bounds(-10, 110, -45, 158))
158                 // .bounds(new Bounds(15, 90, -20, 125))
159                 // set start
160                 // .startTime("2014-04-20")
161                 // set finish
162                 // .finishTime("2014-06-06")
163                 // set segment options
164                 .segmentOptions(SegmentOptions.builder()
165                         // set max speed knots
166                         .maxSpeedKnots(100)
167                         //
168                         .speedCheckDistanceThresholdNm(30)
169                         //
170                         .speedCheckMinTimeDiff(3, TimeUnit.MINUTES)
171                         // set max time per segment
172                         .maxTimePerSegment(1, TimeUnit.DAYS)
173                         //
174                         .maxDistancePerSegmentNm(500.0)
175                         // build
176                         .build())
177                 // build options
178                 .build();
179     }
180 
181     public static void main(String[] args) throws InterruptedException {
182 
183         log.info("starting");
184 
185         final double cellSizeDegrees;
186         if (args.length > 1)
187             cellSizeDegrees = Double.parseDouble(args[1]);
188         else
189             cellSizeDegrees = 0.02;
190 
191         final Options options = createOptions(cellSizeDegrees);
192         for (int i = 0; i <= 10; i++)
193             System.out.println(options.getGrid().centreLon(i));
194 
195         for (int i = 2014; i <= 2016; i++) {
196             String directory = "/media/an/binary-fixes-5-minute/" + i;
197             run(directory, options, false, i + "");
198         }
199     }
200 }