Skip to content

Commit a927bac

Browse files
authored
post process option to run commands after sim has finished (#1934)
1 parent 81edf41 commit a927bac

File tree

4 files changed

+131
-18
lines changed

4 files changed

+131
-18
lines changed

contribs/application/src/main/java/org/matsim/application/MATSimAppCommand.java

+14
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,18 @@ default void execute(String... args) {
4646

4747
}
4848
}
49+
50+
/**
51+
* Apply the given command line arguments to this instance and return it.
52+
*/
53+
default MATSimAppCommand withArgs(String... args) {
54+
CommandLine cli = new CommandLine(this);
55+
CommandLine.ParseResult parseResult = cli.parseArgs(args);
56+
57+
if (!parseResult.errors().isEmpty())
58+
throw new IllegalStateException("Error parsing arguments", parseResult.errors().get(0));
59+
60+
return cli.getCommand();
61+
}
62+
4963
}

contribs/application/src/main/java/org/matsim/application/MATSimApplication.java

+54-4
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
import java.util.*;
3636
import java.util.concurrent.Callable;
3737
import java.util.concurrent.atomic.AtomicReference;
38-
import java.util.stream.Collectors;
3938

4039
/**
4140
* A helper class to define and execute MATSim scenarios, including a pipeline of prepare and analysis scripts.
@@ -101,6 +100,9 @@ public abstract class MATSimApplication implements Callable<Integer>, CommandLin
101100
@CommandLine.Option(names = "--output", description = "Overwrite output folder defined by the application")
102101
protected Path output;
103102

103+
@CommandLine.Option(names = "--post-processing", description = "Option for post-processing", defaultValue = "enabled")
104+
protected PostProcessOption post;
105+
104106
/**
105107
* This Map will never contain anything, because this argument is not parsed correctly, but instead will go into remainingArgs field.
106108
*
@@ -191,7 +193,28 @@ public Integer call() throws Exception {
191193

192194
prepareControler(controler);
193195

194-
controler.run();
196+
// Check if simulation needs to be run
197+
if (post != PostProcessOption.post_process_only)
198+
controler.run();
199+
200+
if (post != PostProcessOption.disabled) {
201+
202+
List<MATSimAppCommand> commands = preparePostProcessing(Path.of(config.controler().getOutputDirectory()), config.controler().getRunId());
203+
204+
for (MATSimAppCommand command : commands) {
205+
206+
try {
207+
log.info("Running post-process command {}", command.getClass().getSimpleName());
208+
command.call();
209+
} catch (Exception e) {
210+
log.error("Error running post-processing", e);
211+
}
212+
213+
}
214+
215+
}
216+
217+
195218
return 0;
196219
}
197220

@@ -318,10 +341,19 @@ protected void prepareScenario(Scenario scenario) {
318341
protected void prepareControler(Controler controler) {
319342
}
320343

344+
/**
345+
* Preparation of {@link MATSimAppCommand} to run after the simulation has finished. The instances have to be fully constructed in this method
346+
* no further arguments are passed down to them.
347+
* @return list of commands to run.
348+
*/
349+
protected List<MATSimAppCommand> preparePostProcessing(Path outputFolder, String runId) {
350+
return List.of();
351+
}
352+
321353
/**
322354
* Add and an option and value to run id and output folder.
323355
*/
324-
protected void addRunOption(Config config, String option, Object value) {
356+
protected final void addRunOption(Config config, String option, Object value) {
325357

326358
String postfix;
327359
if ("".equals(value))
@@ -342,7 +374,7 @@ protected void addRunOption(Config config, String option, Object value) {
342374
/**
343375
* Add and an option to run id and output folder, delimited by "_".
344376
*/
345-
protected void addRunOption(Config config, String option) {
377+
protected final void addRunOption(Config config, String option) {
346378
addRunOption(config, option, "");
347379
}
348380

@@ -685,4 +717,22 @@ public Integer call() throws Exception {
685717
Class<? extends MATSimAppCommand>[] value() default {};
686718
}
687719

720+
/**
721+
* Option to switch post processing behavour
722+
*/
723+
public enum PostProcessOption {
724+
725+
enabled,
726+
727+
/**
728+
* Does not run the post-processing.
729+
*/
730+
disabled,
731+
732+
/**
733+
* Does not run the simulation, but only post-processing.
734+
*/
735+
post_process_only
736+
737+
}
688738
}

contribs/application/src/test/java/org/matsim/application/MATSimApplicationTest.java

+36-14
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
11
package org.matsim.application;
22

3-
import static org.assertj.core.api.Assertions.assertThat;
4-
import static org.junit.Assert.assertEquals;
5-
6-
import java.net.MalformedURLException;
7-
import java.nio.file.Files;
8-
import java.nio.file.Path;
9-
103
import org.junit.Assume;
114
import org.junit.Rule;
125
import org.junit.Test;
136
import org.matsim.application.options.SampleOptions;
147
import org.matsim.application.prepare.freight.tripExtraction.ExtractRelevantFreightTrips;
15-
import org.matsim.application.prepare.freight.toBeDeleted.GenerateGermanWideFreightTrips;
168
import org.matsim.application.prepare.population.GenerateShortDistanceTrips;
179
import org.matsim.application.prepare.population.MergePopulations;
1810
import org.matsim.application.prepare.population.TrajectoryToPlans;
1911
import org.matsim.core.config.Config;
2012
import org.matsim.core.config.ConfigUtils;
2113
import org.matsim.core.config.groups.PlanCalcScoreConfigGroup;
2214
import org.matsim.core.controler.Controler;
15+
import org.matsim.core.controler.OutputDirectoryHierarchy;
2316
import org.matsim.core.utils.io.IOUtils;
2417
import org.matsim.testcases.MatsimTestUtils;
25-
2618
import picocli.CommandLine;
2719

20+
import java.net.MalformedURLException;
21+
import java.nio.file.Files;
22+
import java.nio.file.Path;
23+
import java.util.List;
24+
25+
import static org.assertj.core.api.Assertions.assertThat;
26+
import static org.junit.Assert.assertEquals;
27+
2828
public class MATSimApplicationTest {
2929

3030
@Rule
@@ -69,8 +69,8 @@ public void yaml() {
6969
assertThat(params.getOrCreateModeParams("car").getConstant())
7070
.isEqualTo(-1);
7171

72-
assertThat(params.getOrCreateModeParams("bike").getConstant())
73-
.isEqualTo(-2);
72+
assertThat(params.getOrCreateModeParams("bike").getConstant())
73+
.isEqualTo(-2);
7474

7575
}
7676

@@ -158,9 +158,26 @@ public void freight() {
158158

159159
}
160160

161+
@Test
162+
public void run() {
163+
164+
Config config = ConfigUtils.createConfig();
165+
Path out = Path.of(utils.getOutputDirectory()).resolve("out");
166+
167+
config.controler().setOutputDirectory(out.toString());
168+
config.controler().setOverwriteFileSetting(OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists);
169+
config.controler().setLastIteration(1);
170+
171+
int ret = MATSimApplication.execute(TestScenario.class, config);
172+
173+
// Content defined in the post process section
174+
assertThat(out.resolve("test.txt"))
175+
.hasContent("Inhalt");
176+
177+
}
178+
161179
@MATSimApplication.Prepare({
162-
TrajectoryToPlans.class, GenerateShortDistanceTrips.class,
163-
GenerateGermanWideFreightTrips.class, ExtractRelevantFreightTrips.class, MergePopulations.class
180+
TrajectoryToPlans.class, GenerateShortDistanceTrips.class, ExtractRelevantFreightTrips.class, MergePopulations.class
164181
})
165182
private static final class TestScenario extends MATSimApplication {
166183

@@ -179,9 +196,14 @@ public TestScenario() {
179196
protected Config prepareConfig(Config config) {
180197

181198
config.controler().setRunId(sample.adjustName("run-25pct"));
182-
183199
return config;
184200
}
201+
202+
203+
@Override
204+
protected List<MATSimAppCommand> preparePostProcessing(Path outputFolder, String runId) {
205+
return List.of(new TestCommand(outputFolder.resolve("test.txt"), "Inhalt"));
206+
}
185207
}
186208

187209
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package org.matsim.application;
2+
3+
import java.nio.file.Files;
4+
import java.nio.file.Path;
5+
6+
/**
7+
* Test command that writes content to file.
8+
*/
9+
public class TestCommand implements MATSimAppCommand {
10+
11+
private final Path out;
12+
private final String content;
13+
14+
public TestCommand(Path out, String content) {
15+
this.out = out;
16+
this.content = content;
17+
}
18+
19+
20+
@Override
21+
public Integer call() throws Exception {
22+
23+
Files.writeString(out, content);
24+
25+
return 0;
26+
}
27+
}

0 commit comments

Comments
 (0)