001/* *********************************************************************** *
002 * project: org.matsim.*
003 * PlansWriter.java
004 *                                                                         *
005 * *********************************************************************** *
006 *                                                                         *
007 * copyright       : (C) 2007, 2012 by the members listed in the COPYING,  *
008 *                   LICENSE and WARRANTY file.                            *
009 * email           : info at matsim dot org                                *
010 *                                                                         *
011 * *********************************************************************** *
012 *                                                                         *
013 *   This program is free software; you can redistribute it and/or modify  *
014 *   it under the terms of the GNU General Public License as published by  *
015 *   the Free Software Foundation; either version 2 of the License, or     *
016 *   (at your option) any later version.                                   *
017 *   See also COPYING, LICENSE and WARRANTY file                           *
018 *                                                                         *
019 * *********************************************************************** */
020
021package org.matsim.core.population.io;
022
023import java.io.IOException;
024import java.io.OutputStream;
025import java.util.HashMap;
026import java.util.Map;
027
028import org.apache.log4j.Logger;
029import org.matsim.api.core.v01.network.Network;
030import org.matsim.api.core.v01.population.Person;
031import org.matsim.api.core.v01.population.Population;
032import org.matsim.core.api.internal.MatsimWriter;
033import org.matsim.core.gbl.MatsimRandom;
034import org.matsim.core.population.PopulationUtils;
035import org.matsim.core.utils.geometry.CoordinateTransformation;
036import org.matsim.core.utils.geometry.transformations.IdentityTransformation;
037import org.matsim.core.utils.io.AbstractMatsimWriter;
038import org.matsim.core.utils.io.UncheckedIOException;
039import org.matsim.core.utils.misc.Counter;
040import org.matsim.utils.objectattributes.AttributeConverter;
041
042public final class PopulationWriter extends AbstractMatsimWriter implements MatsimWriter {
043
044        private final double write_person_fraction;
045
046        private final CoordinateTransformation coordinateTransformation;
047        private PopulationWriterHandler handler = null;
048        private final Population population;
049        private final Network network;
050        private Counter counter = new Counter("[" + this.getClass().getSimpleName() + "] dumped person # ");
051
052        private final static Logger log = Logger.getLogger(PopulationWriter.class);
053        private Map<Class<?>,AttributeConverter<?>> converters = new HashMap<>();
054
055
056        public PopulationWriter(final Population population) {
057                this(population, null, 1.0);
058        }
059
060        public PopulationWriter(
061                        final CoordinateTransformation coordinateTransformation,
062                        final Population population) {
063                this(coordinateTransformation , population, null, 1.0);
064        }
065
066        /**
067         * Creates a new PlansWriter to write out the specified plans to the file and with version
068         * as specified in the {@linkplain org.matsim.core.config.groups.PlansConfigGroup configuration}.
069         * If plans-streaming is on, the file will already be opened and the file-header be written.
070         * If plans-streaming is off, the file will not be created until {@link #write(java.lang.String)} is called.
071         *
072         * @param population the population to write to file
073         */
074        public PopulationWriter(final Population population, final Network network) {
075                this(population, network, 1.0);
076        }
077
078        public PopulationWriter(
079                        final CoordinateTransformation coordinateTransformation,
080                        final Population population,
081                        final Network network) {
082                this(coordinateTransformation , population, network, 1.0);
083        }
084
085        /**
086         * Creates a new PlansWriter to write out the specified plans to the specified file and with
087         * the specified version.
088         * If plans-streaming is on, the file will already be opened and the file-header be written.
089         * If plans-streaming is off, the file will not be created until {@link #write(java.lang.String)} is called.
090         *
091         * @param coordinateTransformation transformation from the internal CRS to the CRS in which the file should be written
092         * @param population the population to write to file
093         * @param fraction of persons to write to the plans file
094         */
095        public PopulationWriter(
096                        final CoordinateTransformation coordinateTransformation,
097                        final Population population,
098                        final Network network,
099                        final double fraction) {
100                this.coordinateTransformation = coordinateTransformation;
101                this.population = population;
102                this.network = network;
103                this.write_person_fraction = fraction;
104                this.handler = new PopulationWriterHandlerImplV6( coordinateTransformation );
105        }
106
107        /**
108         * Creates a new PlansWriter to write out the specified plans to the specified file and with
109         * the specified version.
110         * If plans-streaming is on, the file will already be opened and the file-header be written.
111         * If plans-streaming is off, the file will not be created until {@link #write(java.lang.String)} is called.
112         *
113         * @param population the population to write to file
114         * @param fraction of persons to write to the plans file
115         */
116        public PopulationWriter(
117                        final Population population,
118                        final Network network,
119                        final double fraction) {
120                this( new IdentityTransformation() , population , network , fraction );
121        }
122
123        public void putAttributeConverters( final Map<Class<?>, AttributeConverter<?>> converters ) {
124                this.converters.putAll( converters );
125        }
126
127        public void putAttributeConverter( Class<?> key, AttributeConverter<?> converter ) {
128                this.converters.put( key, converter );
129        }
130
131        /**
132         * Writes all plans to the file.
133         */
134        @Override
135        public final void write(final String filename) {
136                try {
137                        this.handler.putAttributeConverters(converters);
138                        this.openFile(filename);
139                        this.handler.writeHeaderAndStartElement(this.writer);
140                        this.handler.startPlans(this.population, this.writer);
141                        this.handler.writeSeparator(this.writer);
142                        this.writePersons();
143                        this.handler.endPlans(this.writer);
144                        log.info("Population written to: " + filename);
145                } catch (IOException e) {
146                        throw new UncheckedIOException(e);
147                } finally {
148                        this.close();
149                        counter.printCounter();
150                        counter.reset();
151                }
152        }
153
154        /**
155         * Writes all plans to the output stream and closes it.
156         * 
157         */
158        public final void write(OutputStream outputStream) {
159                try {
160                        this.handler.putAttributeConverters(converters);
161                        this.openOutputStream(outputStream);
162                        this.handler.writeHeaderAndStartElement(this.writer);
163                        this.handler.startPlans(this.population, this.writer);
164                        this.handler.writeSeparator(this.writer);
165                        this.writePersons();
166                        this.handler.endPlans(this.writer);
167                } catch (IOException e) {
168                        throw new UncheckedIOException(e);
169                } finally {
170                        this.close();
171                        counter.printCounter();
172                        counter.reset();
173                }
174        }
175
176
177        private  final void writePersons() {
178                for (Person p : PopulationUtils.getSortedPersons(this.population).values()) {
179                        writePerson(p);
180                }
181        }
182
183        private final void writePerson(final Person person) {
184                try {
185                        if ((this.write_person_fraction < 1.0) && (MatsimRandom.getRandom().nextDouble() >= this.write_person_fraction)) {
186                                return;
187                        }
188                        this.handler.writePerson(person, this.writer);
189                        counter.incCounter();
190                } catch (IOException e) {
191                        throw new UncheckedIOException(e);
192                }
193        }
194
195        public final void writeV0(final String filename) {
196                this.handler = new PopulationWriterHandlerImplV0( coordinateTransformation , this.network);
197                write(filename);
198        }
199
200        public final void writeV4(final String filename) {
201                this.handler = new PopulationWriterHandlerImplV4( coordinateTransformation , this.network );
202                write(filename);
203        }
204
205        public final void writeV5(final String filename) {
206                this.handler = new PopulationWriterHandlerImplV5(coordinateTransformation);
207                write(filename);
208        }
209
210        public final void writeV6(final String filename) {
211                this.handler = new PopulationWriterHandlerImplV6(coordinateTransformation);
212                write(filename);
213        }
214
215        public final void writeV6(final OutputStream stream) {
216                this.handler = new PopulationWriterHandlerImplV6(coordinateTransformation);
217                write(stream);
218        }
219
220        public final void setWriterHandler(final PopulationWriterHandler handler) {
221                this.handler = handler;
222        }
223        
224}