Skip to content

Commit de5b804

Browse files
allow the Evaluator to load a scenario directly
1 parent 1994359 commit de5b804

File tree

3 files changed

+169
-83
lines changed

3 files changed

+169
-83
lines changed

POSEIDON/src/main/java/uk/ac/ox/oxfish/experiments/tuna/Runner.java

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
/*
2-
* POSEIDON, an agent-based model of fisheries
3-
* Copyright (C) 2020 CoHESyS Lab [email protected]
2+
* POSEIDON, an agent-based model of fisheries
3+
* Copyright (C) 2024 CoHESyS Lab [email protected]
44
*
5-
* This program is free software: you can redistribute it and/or modify
6-
* it under the terms of the GNU General Public License as published by
7-
* the Free Software Foundation, either version 3 of the License, or
8-
* (at your option) any later version.
5+
* This program is free software: you can redistribute it and/or modify it under the terms of the
6+
* GNU General Public License as published by the Free Software Foundation, either version 3
7+
* of the License, or (at your option) any later version.
98
*
10-
* This program is distributed in the hope that it will be useful,
11-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13-
* GNU General Public License for more details.
14-
*
15-
* You should have received a copy of the GNU General Public License
16-
* along with this program. If not, see <http://www.gnu.org/licenses/>.
9+
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
10+
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11+
* See the GNU General Public License for more details.
1712
*
13+
* You should have received a copy of the GNU General Public License along with this program.
14+
* If not, see <http://www.gnu.org/licenses/>.
1815
*/
1916

2017
package uk.ac.ox.oxfish.experiments.tuna;
@@ -283,16 +280,6 @@ private void writeOutputs(
283280
});
284281
}
285282

286-
public Runner<S> writeScenarioToFile(final String outputFileName) {
287-
final File outputFile = outputPath.resolve(outputFileName).toFile();
288-
try (final Writer writer = new FileWriter(outputFile)) {
289-
new FishYAML().dump(scenarioSupplier.get(), writer);
290-
} catch (final IOException e) {
291-
throw new IllegalStateException("Error while writing file: " + outputFile, e);
292-
}
293-
return this;
294-
}
295-
296283
public Runner<S> requestFisherYearlyData() {
297284
return requestFisherYearlyData(__ -> true);
298285
}

epo/src/main/java/uk/ac/ox/poseidon/epo/calibration/Evaluator.java

Lines changed: 39 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -2,50 +2,43 @@
22
* POSEIDON, an agent-based model of fisheries
33
* Copyright (C) 2024 CoHESyS Lab [email protected]
44
*
5-
* This program is free software: you can redistribute it and/or modify
6-
* it under the terms of the GNU General Public License as published by
7-
* the Free Software Foundation, either version 3 of the License, or
8-
* (at your option) any later version.
5+
* This program is free software: you can redistribute it and/or modify it under the terms of the
6+
* GNU General Public License as published by the Free Software Foundation, either version 3
7+
* of the License, or (at your option) any later version.
98
*
10-
* This program is distributed in the hope that it will be useful,
11-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13-
* GNU General Public License for more details.
9+
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
10+
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11+
* See the GNU General Public License for more details.
1412
*
15-
* You should have received a copy of the GNU General Public License
16-
* along with this program. If not, see <http://www.gnu.org/licenses/>.
13+
* You should have received a copy of the GNU General Public License along with this program.
14+
* If not, see <http://www.gnu.org/licenses/>.
1715
*/
1816

1917
package uk.ac.ox.poseidon.epo.calibration;
2018

2119
import com.beust.jcommander.JCommander;
2220
import com.beust.jcommander.Parameter;
2321
import com.beust.jcommander.converters.PathConverter;
24-
import com.google.common.collect.ImmutableList;
2522
import com.google.common.collect.ImmutableMap;
2623
import com.google.common.collect.ImmutableSet;
2724
import uk.ac.ox.oxfish.experiments.tuna.Runner;
2825
import uk.ac.ox.oxfish.fisher.purseseiner.fads.AbundanceFadAttractionEvent;
2926
import uk.ac.ox.oxfish.fisher.purseseiner.fads.FadManager;
30-
import uk.ac.ox.oxfish.maximization.GenericOptimization;
31-
import uk.ac.ox.oxfish.maximization.SolutionExtractor;
3227
import uk.ac.ox.oxfish.maximization.YearlyResultsRowProvider;
3328
import uk.ac.ox.oxfish.model.FishState;
3429
import uk.ac.ox.oxfish.model.data.monitors.loggers.AbundanceFadAttractionEventObserver;
3530
import uk.ac.ox.oxfish.model.scenario.Scenario;
31+
import uk.ac.ox.oxfish.utility.yaml.FishYAML;
3632

33+
import java.io.File;
3734
import java.io.FileNotFoundException;
35+
import java.io.FileReader;
3836
import java.io.IOException;
39-
import java.nio.file.Files;
4037
import java.nio.file.Path;
41-
import java.nio.file.Paths;
4238
import java.util.Set;
4339
import java.util.concurrent.atomic.AtomicInteger;
44-
import java.util.stream.Stream;
4540

46-
import static com.google.common.base.Preconditions.checkState;
47-
import static com.google.common.collect.ImmutableList.toImmutableList;
48-
import static com.google.common.io.Files.getFileExtension;
41+
import static com.google.common.base.Preconditions.checkNotNull;
4942
import static java.lang.Runtime.getRuntime;
5043

5144
public class Evaluator implements Runnable {
@@ -67,20 +60,10 @@ public class Evaluator implements Runnable {
6760
@Parameter(converter = PathConverter.class)
6861
private Path calibrationFolder;
6962

70-
private static Scenario makeScenario(
71-
final GenericOptimization optimization,
72-
final double[] optimalParameters
73-
) {
74-
try {
75-
return GenericOptimization.buildScenario(
76-
optimalParameters,
77-
Paths.get(optimization.getScenarioFile()).toFile(),
78-
optimization.getParameters()
79-
);
80-
} catch (final FileNotFoundException e) {
81-
throw new IllegalStateException(e);
82-
}
83-
}
63+
// If `scenarioFile` is not provided, the Evaluator will extract a scenario from
64+
// the calibration log and write it back to `calibrated_scenario.yaml`.
65+
@Parameter(names = {"-s", "--scenario"}, converter = PathConverter.class)
66+
private Path scenarioFile;
8467

8568
public static void main(final String[] args) {
8669

@@ -93,29 +76,12 @@ public static void main(final String[] args) {
9376
evaluator.run();
9477
}
9578

96-
private static Path findCalibrationFile(final Path folder) {
97-
try (final Stream<Path> paths = Files.list(folder)) {
98-
final ImmutableList<Path> calibrationFiles = paths
99-
.filter(path -> getFileExtension(path.toString()).equals("yaml"))
100-
.filter(Evaluator::isCalibrationFile)
101-
.collect(toImmutableList());
102-
checkState(!calibrationFiles.isEmpty(), "No calibration files found in %s", folder);
103-
checkState(calibrationFiles.size() == 1, "More than one calibration files found in %s", folder);
104-
return calibrationFiles.get(0);
105-
} catch (final IOException e) {
106-
throw new IllegalStateException(e);
107-
}
79+
public Path getScenarioFile() {
80+
return scenarioFile;
10881
}
10982

110-
private static boolean isCalibrationFile(final Path path) {
111-
try (final Stream<String> lines = Files.lines(path)) {
112-
return lines
113-
.findFirst()
114-
.filter(line -> line.equals("!!uk.ac.ox.oxfish.maximization.GenericOptimization"))
115-
.isPresent();
116-
} catch (final IOException e) {
117-
throw new IllegalStateException(e);
118-
}
83+
public void setScenarioFile(final Path scenarioFile) {
84+
this.scenarioFile = scenarioFile;
11985
}
12086

12187
@SuppressWarnings("unused")
@@ -141,14 +107,13 @@ public void setCalibrationFolder(final Path calibrationFolder) {
141107
@Override
142108
public void run() {
143109

144-
final Path calibrationFilePath = findCalibrationFile(calibrationFolder);
145-
final Path logFilePath = calibrationFolder.resolve("calibration_log.md");
146-
final double[] solution = new SolutionExtractor(logFilePath).bestSolution().getKey();
147-
final GenericOptimization optimization = GenericOptimization.fromFile(calibrationFilePath);
110+
final Scenario scenario =
111+
scenarioFile == null
112+
? new ScenarioExtractor(calibrationFolder).getAndWriteToFile("calibrated_scenario.yaml")
113+
: loadScenario();
148114

149115
final Runner<Scenario> runner =
150-
new Runner<>(() -> makeScenario(optimization, solution), calibrationFilePath.getParent())
151-
.writeScenarioToFile("calibrated_scenario.yaml")
116+
new Runner<>(() -> scenario, calibrationFolder)
152117
.setParallel(parallel)
153118
.registerRowProvider("yearly_results.csv", YearlyResultsRowProvider::new)
154119
.requestFisherYearlyData();
@@ -169,6 +134,20 @@ public void run() {
169134
.run(numYearsToRuns, 1, runCounter);
170135
}
171136

137+
private Scenario loadScenario() {
138+
checkNotNull(this.calibrationFolder);
139+
checkNotNull(this.scenarioFile);
140+
final File scenarioFile = calibrationFolder.resolve(this.scenarioFile).toFile();
141+
try (final FileReader fileReader = new FileReader(scenarioFile)) {
142+
final FishYAML fishYAML = new FishYAML();
143+
return fishYAML.loadAs(fileReader, Scenario.class);
144+
} catch (final FileNotFoundException e) {
145+
throw new IllegalArgumentException("Can't find scenario file: " + scenarioFile, e);
146+
} catch (final IOException e) {
147+
throw new IllegalStateException("Error while reading file: " + scenarioFile, e);
148+
}
149+
}
150+
172151
private void registerFadAttractionEventProviders(final Runner<Scenario> runner) {
173152
runner.setAfterStartConsumer(state -> {
174153
final FishState fishState = state.getModel();
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
* POSEIDON, an agent-based model of fisheries
3+
* Copyright (C) 2024 CoHESyS Lab [email protected]
4+
*
5+
* This program is free software: you can redistribute it and/or modify it under the terms of the
6+
* GNU General Public License as published by the Free Software Foundation, either version 3
7+
* of the License, or (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
10+
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11+
* See the GNU General Public License for more details.
12+
*
13+
* You should have received a copy of the GNU General Public License along with this program.
14+
* If not, see <http://www.gnu.org/licenses/>.
15+
*/
16+
package uk.ac.ox.poseidon.epo.calibration;
17+
18+
import com.google.common.base.Supplier;
19+
import com.google.common.collect.ImmutableList;
20+
import uk.ac.ox.oxfish.maximization.GenericOptimization;
21+
import uk.ac.ox.oxfish.maximization.SolutionExtractor;
22+
import uk.ac.ox.oxfish.model.scenario.Scenario;
23+
import uk.ac.ox.oxfish.utility.yaml.FishYAML;
24+
25+
import java.io.*;
26+
import java.nio.file.Files;
27+
import java.nio.file.Path;
28+
import java.nio.file.Paths;
29+
import java.util.stream.Stream;
30+
31+
import static com.google.common.base.Preconditions.checkState;
32+
import static com.google.common.collect.ImmutableList.toImmutableList;
33+
import static com.google.common.io.Files.getFileExtension;
34+
35+
public class ScenarioExtractor implements Supplier<Scenario> {
36+
37+
private final Path calibrationLogFile;
38+
private final Path calibrationFolder;
39+
40+
public ScenarioExtractor(
41+
final Path calibrationFolder
42+
) {
43+
this(calibrationFolder, Paths.get("calibration_log.md"));
44+
}
45+
46+
public ScenarioExtractor(
47+
final Path calibrationFolder,
48+
final Path calibrationLogFile
49+
) {
50+
this.calibrationLogFile = calibrationLogFile;
51+
this.calibrationFolder = calibrationFolder;
52+
}
53+
54+
public Scenario getAndWriteToFile(final String outputFileName) {
55+
final Scenario scenario = get();
56+
writeScenarioToFile(scenario, outputFileName);
57+
return scenario;
58+
}
59+
60+
@Override
61+
public Scenario get() {
62+
final Path calibrationFilePath = findCalibrationFile(calibrationFolder);
63+
final Path logFilePath = calibrationFolder.resolve(calibrationLogFile);
64+
final double[] solution = new SolutionExtractor(logFilePath).bestSolution().getKey();
65+
final GenericOptimization optimization = GenericOptimization.fromFile(calibrationFilePath);
66+
return makeScenario(optimization, solution);
67+
}
68+
69+
private void writeScenarioToFile(
70+
final Scenario scenario,
71+
final String outputFileName
72+
) {
73+
final File outputFile = calibrationFolder.resolve(outputFileName).toFile();
74+
try (final Writer writer = new FileWriter(outputFile)) {
75+
new FishYAML().dump(scenario, writer);
76+
} catch (final IOException e) {
77+
throw new IllegalStateException("Error while writing file: " + outputFile, e);
78+
}
79+
}
80+
81+
private static Path findCalibrationFile(final Path folder) {
82+
try (final Stream<Path> paths = Files.list(folder)) {
83+
final ImmutableList<Path> calibrationFiles = paths
84+
.filter(path -> getFileExtension(path.toString()).equals("yaml"))
85+
.filter(ScenarioExtractor::isCalibrationFile)
86+
.collect(toImmutableList());
87+
checkState(!calibrationFiles.isEmpty(), "No calibration files found in %s", folder);
88+
checkState(calibrationFiles.size() == 1, "More than one calibration files found in %s", folder);
89+
return calibrationFiles.get(0);
90+
} catch (final IOException e) {
91+
throw new IllegalStateException(e);
92+
}
93+
}
94+
95+
private static Scenario makeScenario(
96+
final GenericOptimization optimization,
97+
final double[] optimalParameters
98+
) {
99+
try {
100+
return GenericOptimization.buildScenario(
101+
optimalParameters,
102+
Paths.get(optimization.getScenarioFile()).toFile(),
103+
optimization.getParameters()
104+
);
105+
} catch (final FileNotFoundException e) {
106+
throw new IllegalStateException(e);
107+
}
108+
}
109+
110+
private static boolean isCalibrationFile(final Path path) {
111+
try (final Stream<String> lines = Files.lines(path)) {
112+
return lines
113+
.findFirst()
114+
.filter(line -> line.equals("!!uk.ac.ox.oxfish.maximization.GenericOptimization"))
115+
.isPresent();
116+
} catch (final IOException e) {
117+
throw new IllegalStateException(e);
118+
}
119+
}
120+
}

0 commit comments

Comments
 (0)