MATSIM
PopulationSampler.java
Go to the documentation of this file.
1 
2 /* *********************************************************************** *
3  * project: org.matsim.*
4  * PopulationSampler.java
5  * *
6  * *********************************************************************** *
7  * *
8  * copyright : (C) 2019 by the members listed in the COPYING, *
9  * LICENSE and WARRANTY file. *
10  * email : info at matsim dot org *
11  * *
12  * *********************************************************************** *
13  * *
14  * This program is free software; you can redistribute it and/or modify *
15  * it under the terms of the GNU General Public License as published by *
16  * the Free Software Foundation; either version 2 of the License, or *
17  * (at your option) any later version. *
18  * See also COPYING, LICENSE and WARRANTY file *
19  * *
20  * *********************************************************************** */
21 
22 package org.matsim.run.gui;
23 
24 import java.io.BufferedInputStream;
25 import java.io.File;
26 import java.io.FileInputStream;
27 import java.io.IOException;
28 import java.util.Locale;
29 import java.util.zip.GZIPInputStream;
30 
31 import javax.swing.GroupLayout;
32 import javax.swing.GroupLayout.Alignment;
33 import javax.swing.JButton;
34 import javax.swing.JDialog;
35 import javax.swing.JFileChooser;
36 import javax.swing.JFrame;
37 import javax.swing.JLabel;
38 import javax.swing.JOptionPane;
39 import javax.swing.JSpinner;
40 import javax.swing.JTextField;
41 import javax.swing.LayoutStyle.ComponentPlacement;
42 import javax.swing.SpinnerNumberModel;
43 import javax.swing.SwingUtilities;
44 
45 import org.apache.logging.log4j.LogManager;
46 import org.apache.logging.log4j.Logger;
55 
56 import com.github.luben.zstd.ZstdInputStream;
57 
61 final class PopulationSampler extends JDialog {
62 
63  private final static Logger log = LogManager.getLogger(PopulationSampler.class);
64 
65  private static final long serialVersionUID = 1L;
66 
67  private JTextField txtPath;
68  private JSpinner pctSpinner;
69  private JButton btnChoose;
70  private JButton btnCreateSample;
71 
72  PopulationSampler(JFrame parent) {
73  super(parent);
74  setTitle("Create Population Sample");
75 
76  this.btnChoose = new JButton("Choose…");
77 
78  JLabel lblinput = new JLabel("Input Population:");
79  this.txtPath = new JTextField("");
80  JLabel lblpercentage = new JLabel("Sample Size:");
81  this.pctSpinner = new JSpinner(new SpinnerNumberModel(10, 1, 100, 1));
82  JLabel lblPercentage = new JLabel("%");
83  btnCreateSample = new JButton("Create Sample…");
84 
85  GroupLayout groupLayout = new GroupLayout(getContentPane());
86  groupLayout.setHorizontalGroup(groupLayout.createParallelGroup(Alignment.LEADING)
87  .addGroup(groupLayout.createSequentialGroup()
88  .addContainerGap()
89  .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
90  .addGroup(groupLayout.createSequentialGroup()
91  .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
92  .addComponent(lblinput)
93  .addComponent(lblpercentage))
94  .addPreferredGap(ComponentPlacement.RELATED)
95  .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
96  .addGroup(groupLayout.createSequentialGroup()
97  .addComponent(pctSpinner, GroupLayout.PREFERRED_SIZE,
98  GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
99  .addPreferredGap(ComponentPlacement.RELATED)
100  .addComponent(lblPercentage, GroupLayout.DEFAULT_SIZE,
101  GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE)
102  .addGap(0, 20, Short.MAX_VALUE))
103  .addGroup(groupLayout.createSequentialGroup()
104  .addComponent(txtPath, GroupLayout.DEFAULT_SIZE, 170,
105  Short.MAX_VALUE)
106  .addPreferredGap(ComponentPlacement.RELATED)
107  .addComponent(btnChoose))))
108  .addComponent(btnCreateSample, Alignment.TRAILING))
109  .addContainerGap()));
110  groupLayout.setVerticalGroup(groupLayout.createParallelGroup(Alignment.LEADING)
111  .addGroup(groupLayout.createSequentialGroup()
112  .addContainerGap()
113  .addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
114  .addComponent(btnChoose)
115  .addComponent(lblinput)
116  .addComponent(txtPath))
117  .addPreferredGap(ComponentPlacement.RELATED)
118  .addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
119  .addComponent(lblpercentage)
120  .addComponent(lblPercentage)
121  .addComponent(pctSpinner))
122  .addPreferredGap(ComponentPlacement.UNRELATED)
123  .addComponent(btnCreateSample)
124  .addContainerGap()));
125  getContentPane().setLayout(groupLayout);
126 
127  setupComponents();
128  }
129 
130  private void setupComponents() {
131  this.btnChoose.addActionListener(e -> {
132  JFileChooser chooser = new JFileChooser();
133  int result = chooser.showOpenDialog(null);
134  if (result == JFileChooser.APPROVE_OPTION) {
135  File f = chooser.getSelectedFile();
136  String filename = f.getAbsolutePath();
137  PopulationSampler.this.txtPath.setText(filename);
138  }
139  });
140 
141  this.btnCreateSample.addActionListener(e -> {
142  createSample();
143  PopulationSampler.this.setVisible(false);
144  });
145  }
146 
147  private void createSample() {
148  final String srcFilename = PopulationSampler.this.txtPath.getText();
149  File srcFile = new File(srcFilename);
150  if (!srcFile.exists()) {
151  JOptionPane.showMessageDialog(null, "The specified file could not be found: " + srcFilename,
152  "File not found!", JOptionPane.ERROR_MESSAGE);
153  return;
154  }
155 
156  final String namePart = srcFilename.substring(0, srcFilename.toLowerCase(Locale.ROOT).lastIndexOf(".xml"));
157  final int percentage = (Integer)PopulationSampler.this.pctSpinner.getValue();
158  final double samplesize = percentage / 100.0;
159 
160  JFileChooser chooser = new SaveFileSaver();
161  chooser.setCurrentDirectory(srcFile.getParentFile());
162  chooser.setSelectedFile(new File(srcFile.getParentFile(), namePart + "." + percentage + "pct.xml.gz"));
163  int saveResult = chooser.showSaveDialog(PopulationSampler.this);
164  if (saveResult == JFileChooser.APPROVE_OPTION) {
165  File destFile = chooser.getSelectedFile();
166  doCreateSample(srcFile, null, samplesize, destFile);
167  }
168  }
169 
170  private void doCreateSample(File inputPopulationFile, File networkFile, double samplesize,
171  File outputPopulationFile) {
172  AsyncFileInputProgressDialog gui = new AsyncFileInputProgressDialog();
173 
174  new Thread(() -> {
175  MutableScenario sc = ScenarioUtils.createMutableScenario(ConfigUtils.createConfig());
176 
177  if (networkFile != null) {
178  SwingUtilities.invokeLater(() -> gui.setTitle("Loading Network…"));
179  try (FileInputStream fis = new FileInputStream(networkFile);
180  BufferedInputStream is = getBufferedInputStream(networkFile.getName(), fis)) {
181  new MatsimNetworkReader(sc.getNetwork()).parse(is);
182  } catch (IOException | RuntimeException e) {
183  log.error(e.getMessage(), e);
184  SwingUtilities.invokeLater(gui::dispose);
185  SwingUtilities.invokeLater(() -> JOptionPane.showMessageDialog(null,
186  "Error while reading the network file: " + e.getMessage(),
187  "Cannot create population sample", JOptionPane.ERROR_MESSAGE));
188  return;
189  }
190  }
191 
192  SwingUtilities.invokeLater(() -> gui.setTitle("Creating Population Sample…"));
193  StreamingPopulationReader reader = new StreamingPopulationReader(sc);
194  StreamingPopulationWriter writer = null;
195 
196  try (FileInputStream fis = new FileInputStream(inputPopulationFile);
197  BufferedInputStream is = getBufferedInputStream(inputPopulationFile.getName(), fis)) {
198  writer = new StreamingPopulationWriter(new IdentityTransformation(), samplesize);
199  writer.startStreaming(outputPopulationFile.getAbsolutePath());
200  reader.addAlgorithm(writer);
201  reader.parse(is);
202  SwingUtilities.invokeLater(gui::dispose);
203  writer.closeStreaming();
204  } catch (RuntimeException | IOException e) {
205  log.error(e.getMessage(), e);
206  SwingUtilities.invokeLater(gui::dispose);
207 
208  if (writer != null) {
209  writer.closeStreaming();
210  outputPopulationFile.delete();
211  }
212 
213  if (e instanceof RuntimeException && networkFile == null) {
214  //just making a guess that providing the corresponding network will solve the issue
215  SwingUtilities.invokeLater(() -> {
216  JOptionPane.showMessageDialog(null,
217  "<html>It looks like the population file cannot be parsed without a network file.<br />Please select a matching network file in the next dialog.</html>",
218  "Problems creating population sample", JOptionPane.WARNING_MESSAGE);
219  JFileChooser netChooser = new JFileChooser();
220  netChooser.setCurrentDirectory(inputPopulationFile.getParentFile());
221  int result = netChooser.showOpenDialog(this);
222  if (result == JFileChooser.APPROVE_OPTION) {
223  doCreateSample(inputPopulationFile, netChooser.getSelectedFile(), samplesize,
224  outputPopulationFile);
225  }
226  });
227  } else {
228  SwingUtilities.invokeLater(() -> JOptionPane.showMessageDialog(null,
229  "The population sample cannot be created, as not all necessary data is available.",
230  "Cannot create population sample", JOptionPane.ERROR_MESSAGE));
231  }
232  }
233  }, "sampler").start();
234  }
235 
236  private static BufferedInputStream getBufferedInputStream(String filename, FileInputStream fis) throws IOException {
237  String lcFilename = filename.toLowerCase(Locale.ROOT);
238  if (lcFilename.endsWith(".gz")) {
239  return new BufferedInputStream(new UnicodeInputStream(new GZIPInputStream(fis)));
240  }
241  if (lcFilename.endsWith(".zst")) {
242  return new BufferedInputStream(new UnicodeInputStream(new ZstdInputStream(fis)));
243  }
244  return new BufferedInputStream(new UnicodeInputStream(fis));
245  }
246 }