Skip to content

Commit 9943c9d

Browse files
committed
feat: add max attempts option to command line parsers and update related generators
1 parent 8ecd1d1 commit 9943c9d

File tree

13 files changed

+132
-75
lines changed

13 files changed

+132
-75
lines changed

docs/technical-details/api-benchmarks/coordinate-generators.md

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ The tool generates random coordinates within a specified bounding box and then u
4444
| `-m, --max-distances` | Maximum distances in meters **per profile** between the start and endpoint. | (none) |
4545
| `-t, --threads` | Number of threads to use. | Available processors |
4646
| `-sr, --snap-radius` | Search radius in meters for coordinate snapping. | 1000 |
47+
| `-ma, --max-attempts` | Maximum number of attempts for coordinate generation. | 1000 |
4748

4849
### Route Generator Examples
4950

@@ -78,6 +79,7 @@ Generate 50 routes for both driving-car and cycling-regular profiles with differ
7879
--max-distances 5000,3000 \
7980
--threads 4 \
8081
--snap-radius 1500 \
82+
--max-attempts 1500 \
8183
--url http://localhost:8080/ors \
8284
--output routes.csv"
8385
```
@@ -94,14 +96,15 @@ The tool generates random coordinates within a specified bounding box and then u
9496

9597
### Snapping Generator Options
9698

97-
| Option | Description | Default |
98-
|--------|-------------|---------|
99-
| `-n, --num-points` | Number of points to generate per profile. | (required) |
100-
| `-e, --extent` | Bounding box (minLon,minLat,maxLon,maxLat). | (required) |
101-
| `-p, --profiles` | Comma-separated list of routing profiles. | (required) |
102-
| `-r, --radius` | Search radius in meters. | 350 |
103-
| `-u, --url` | ORS API base URL. | <http://localhost:8080/ors> |
104-
| `-o, --output` | Output CSV file path. | snapped_coordinates.csv |
99+
| Option | Description | Default |
100+
|-----------------------|-------------------------------------------------------|-----------------------------|
101+
| `-n, --num-points` | Number of points to generate per profile. | (required) |
102+
| `-e, --extent` | Bounding box (minLon,minLat,maxLon,maxLat). | (required) |
103+
| `-p, --profiles` | Comma-separated list of routing profiles. | (required) |
104+
| `-r, --radius` | Search radius in meters. | 350 |
105+
| `-u, --url` | ORS API base URL. | <http://localhost:8080/ors> |
106+
| `-o, --output` | Output CSV file path. | snapped_coordinates.csv |
107+
| `-ma, --max-attempts` | Maximum number of attempts for coordinate generation. | 1000 |
105108

106109
### Snapping Generator Examples
107110

@@ -133,6 +136,7 @@ Generate 50 snapped points for both driving-car and cycling-regular profiles:
133136
--extent 8.681495,49.411721,8.695485,49.419365 \
134137
--profiles driving-car,cycling-regular \
135138
--radius 250 \
139+
--max-attempts 1500 \
136140
--url http://localhost:8080/ors \
137141
--output snapped.csv"
138142
```

ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/RouteGeneratorApp.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public static void main(String[] args) {
2525
CoordinateGeneratorRoute generator = cli.createGenerator();
2626

2727
LOGGER.info("Generating {} routes...", generator.getNumRoutes());
28-
generator.generateRoutes();
28+
generator.generate();
2929
LOGGER.info("\n");
3030

3131
List<Route> result = generator.getResult();

ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/cli/RouteCommandLineParser.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public class RouteCommandLineParser extends CommandLineParser {
1414

1515
private static final String OPT_THREADS = "threads";
1616
private static final String OPT_SNAP_RADIUS = "snap-radius";
17+
private static final String OPT_MAX_ATTEMPTS = "max-attempts";
1718
private static final int DEFAULT_THREAD_COUNT = Runtime.getRuntime().availableProcessors();
1819

1920
public RouteCommandLineParser(String[] args) {
@@ -73,7 +74,6 @@ protected void setupOptions() {
7374
.hasArg()
7475
.desc("Maximum distances between coordinates in meters, comma-separated in profile order (e.g., 5000,3000)")
7576
.build());
76-
7777
options.addOption(Option.builder("t")
7878
.longOpt(OPT_THREADS)
7979
.hasArg()
@@ -86,6 +86,13 @@ protected void setupOptions() {
8686
.type(Number.class)
8787
.desc("Search radius in meters for coordinate snapping (default: 1000)")
8888
.build());
89+
90+
options.addOption(Option.builder("ma")
91+
.longOpt(OPT_MAX_ATTEMPTS)
92+
.hasArg()
93+
.type(Number.class)
94+
.desc("Maximum number of attempts for coordinate generation (default: 1000)")
95+
.build());
8996
}
9097

9198
@Override
@@ -124,6 +131,7 @@ public CoordinateGeneratorRoute createGenerator() {
124131
String baseUrl = cmd.getOptionValue("u", "http://localhost:8080/ors");
125132
double minDistance = Double.parseDouble(cmd.getOptionValue("d", "1"));
126133
double snapRadius = Double.parseDouble(cmd.getOptionValue(OPT_SNAP_RADIUS, "1000"));
134+
int maxAttempts = Integer.parseInt(cmd.getOptionValue(OPT_MAX_ATTEMPTS, String.valueOf(100)));
127135

128136
// Parse the max distances if provided
129137
Map<String, Double> maxDistanceByProfile = parseMaxDistances(cmd.getOptionValue("m"), profiles);
@@ -132,13 +140,15 @@ public CoordinateGeneratorRoute createGenerator() {
132140

133141
if (LOGGER.isInfoEnabled()) {
134142
LOGGER.info(
135-
"Creating CoordinateGeneratorRoute with numRoutes={}, extent={}, profiles={}, baseUrl={}, minDistance={}, maxDistances={}, numThreads={}, snapRadius={}",
143+
"Creating CoordinateGeneratorRoute with numRoutes={}, extent={}, profiles={}, baseUrl={}, minDistance={}, maxDistances={}, numThreads={}, snapRadius={}, maxAttempts={}",
136144
numRoutes, extent, java.util.Arrays.toString(profiles), baseUrl, minDistance, maxDistanceByProfile,
137-
numThreads, snapRadius);
145+
numThreads, snapRadius, maxAttempts);
138146
}
139147

140-
return new CoordinateGeneratorRoute(numRoutes, extent, profiles, baseUrl, minDistance, maxDistanceByProfile,
141-
numThreads, snapRadius);
148+
CoordinateGeneratorRoute generator = new CoordinateGeneratorRoute(numRoutes, extent, profiles, baseUrl,
149+
minDistance, maxDistanceByProfile, numThreads, snapRadius, maxAttempts);
150+
generator.generate();
151+
return generator;
142152
}
143153

144154
/**

ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/cli/SnappingCommandLineParser.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
public class SnappingCommandLineParser extends CommandLineParser {
1010
private static final Logger LOGGER = LoggerFactory.getLogger(SnappingCommandLineParser.class);
11+
private static final String OPT_MAX_ATTEMPTS = "max-attempts";
1112

1213
public SnappingCommandLineParser(String[] args) {
1314
super(args);
@@ -60,6 +61,13 @@ protected void setupOptions() {
6061
.hasArg()
6162
.desc("Output CSV file path")
6263
.build());
64+
65+
options.addOption(Option.builder("ma")
66+
.longOpt(OPT_MAX_ATTEMPTS)
67+
.hasArg()
68+
.type(Number.class)
69+
.desc("Maximum number of attempts for coordinate generation (default: 1000)")
70+
.build());
6371
}
6472

6573
@Override
@@ -88,12 +96,17 @@ public CoordinateGeneratorSnapping createGenerator() {
8896
String[] profiles = parseProfiles(cmd.getOptionValue("p"));
8997
double radius = Double.parseDouble(cmd.getOptionValue("r", "350"));
9098
String baseUrl = cmd.getOptionValue("u", "http://localhost:8080/ors");
99+
int maxAttempts = Integer.parseInt(
100+
cmd.getOptionValue(OPT_MAX_ATTEMPTS, "100"));
91101

92102
LOGGER.info(
93-
"Creating CoordinateGeneratorSnapping with numPoints={}, extent={}, radius={}, profiles={}, baseUrl={}",
94-
numPoints, extent, radius, profiles, baseUrl);
103+
"Creating CoordinateGeneratorSnapping with numPoints={}, extent={}, radius={}, profiles={}, baseUrl={}, maxAttempts={}",
104+
numPoints, extent, radius, profiles, baseUrl, maxAttempts);
95105

96-
return new CoordinateGeneratorSnapping(numPoints, extent, radius, profiles, baseUrl);
106+
CoordinateGeneratorSnapping generator = new CoordinateGeneratorSnapping(numPoints, extent, radius, profiles,
107+
baseUrl, maxAttempts);
108+
generator.generate();
109+
return generator;
97110
}
98111

99112
/**

ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/generators/AbstractCoordinateGenerator.java

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
*/
2525
public abstract class AbstractCoordinateGenerator {
2626
protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractCoordinateGenerator.class);
27-
protected static final int DEFAULT_MAX_ATTEMPTS = 10000;
2827
protected static final double COORDINATE_PRECISION = 1e-6;
2928
protected static final String DEFAULT_BASE_URL = "http://localhost:8082/ors";
3029

@@ -35,6 +34,7 @@ public abstract class AbstractCoordinateGenerator {
3534
protected final Random random;
3635
protected final ObjectMapper mapper;
3736
protected final String apiKey;
37+
protected final int maxAttempts;
3838

3939
/**
4040
* Creates a new coordinate generator
@@ -44,14 +44,16 @@ public abstract class AbstractCoordinateGenerator {
4444
* @param baseUrl API base URL
4545
* @param endpoint API endpoint name (for logging)
4646
*/
47-
protected AbstractCoordinateGenerator(double[] extent, String[] profiles, String baseUrl, String endpoint) {
47+
protected AbstractCoordinateGenerator(double[] extent, String[] profiles, String baseUrl, String endpoint,
48+
int maxAttempts) {
4849
this.baseUrl = baseUrl != null ? baseUrl : DEFAULT_BASE_URL;
4950
validateBaseInputParameters(extent, profiles, endpoint);
5051
this.extent = extent;
5152
this.profiles = profiles.clone();
5253
this.random = new SecureRandom();
5354
this.mapper = new ObjectMapper();
5455
this.apiKey = getApiKey();
56+
this.maxAttempts = maxAttempts;
5557
}
5658

5759
private void validateBaseInputParameters(double[] extent, String[] profiles, String endpoint) {
@@ -130,11 +132,6 @@ protected String processResponse(ClassicHttpResponse response) throws IOExceptio
130132
*/
131133
public abstract void writeToCSV(String filePath) throws IOException;
132134

133-
/**
134-
* Main generation method with specified maximum attempts
135-
*/
136-
protected abstract void generate(int maxAttempts);
137-
138135
/**
139136
* Gets the generated results
140137
*/
@@ -146,9 +143,8 @@ protected String processResponse(ClassicHttpResponse response) throws IOExceptio
146143
protected abstract void initializeCollections();
147144

148145
/**
149-
* Main generation method with default maximum attempts
146+
* Main generation method
150147
*/
151-
public void generate() {
152-
generate(DEFAULT_MAX_ATTEMPTS);
153-
}
148+
protected abstract void generate();
149+
154150
}

ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/generators/CoordinateGeneratorMatrix.java

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ public record MatrixDimensions(int numRows, int numCols) {
4848

4949
public CoordinateGeneratorMatrix(int numMatrices, double[] extent, String[] profiles, String baseUrl,
5050
Map<String, Double> maxDistanceByProfile,
51-
MatrixDimensions matrixDimensions, int numThreads, double snapRadius) {
52-
super(extent, profiles, baseUrl, "matrix");
51+
MatrixDimensions matrixDimensions, int numThreads, double snapRadius, int maxAttempts) {
52+
super(extent, profiles, baseUrl, "matrix", maxAttempts);
5353
validateInputs(numMatrices, numThreads);
5454

5555
this.numMatrices = numMatrices;
@@ -111,12 +111,12 @@ private Map<String, Double> normalizeMaxDistances(String[] profiles, Map<String,
111111
}
112112

113113
public void generateMatrices() {
114-
generate(DEFAULT_MAX_ATTEMPTS);
114+
generate();
115115
}
116116

117117
@Override
118-
public void generate(int maxAttempts) {
119-
LOGGER.info("Starting route generation with {} threads and max attempts: {}", numThreads, maxAttempts);
118+
public void generate() {
119+
LOGGER.info("Starting route generation with {} threads and max attempts: {}", numThreads, this.maxAttempts);
120120
initializeCollections();
121121

122122
ExecutorService executor = null;
@@ -125,19 +125,19 @@ public void generate(int maxAttempts) {
125125

126126
try {
127127
executor = Executors.newFixedThreadPool(numThreads);
128-
executeMatrixGeneration(executor, maxAttempts, shouldContinue, consecutiveFailedAttempts);
128+
executeMatrixGeneration(executor, shouldContinue, consecutiveFailedAttempts);
129129
} catch (Exception e) {
130130
LOGGER.error("Error generating routes: ", e);
131131
} finally {
132132
shutdownExecutor(executor);
133133
}
134134
}
135135

136-
private void executeMatrixGeneration(ExecutorService executor, int maxAttempts,
136+
private void executeMatrixGeneration(ExecutorService executor,
137137
AtomicBoolean shouldContinue, AtomicInteger consecutiveFailedAttempts) {
138138
try (ProgressBar pb = createProgressBar()) {
139139
while (!matrixRepository.areAllProfilesComplete(numMatrices) &&
140-
consecutiveFailedAttempts.get() < maxAttempts &&
140+
consecutiveFailedAttempts.get() < this.maxAttempts &&
141141
shouldContinue.get()) {
142142

143143
int initialTotalMatrices = matrixRepository.getTotalMatrixCount();
@@ -161,13 +161,13 @@ private void executeMatrixGeneration(ExecutorService executor, int maxAttempts,
161161
// Check if we made progress in this iteration
162162
if (matrixRepository.getTotalMatrixCount() == initialTotalMatrices) {
163163
int attempts = consecutiveFailedAttempts.incrementAndGet();
164-
pb.setExtraMessage(String.format("Attempt %d/%d - No new routes", attempts, maxAttempts));
164+
pb.setExtraMessage(String.format("Attempt %d/%d - No new routes", attempts, this.maxAttempts));
165165
} else {
166166
consecutiveFailedAttempts.set(0);
167167
}
168168
}
169169

170-
finalizeProgress(pb, maxAttempts, consecutiveFailedAttempts.get());
170+
finalizeProgress(pb, consecutiveFailedAttempts.get());
171171
}
172172
}
173173

@@ -202,11 +202,11 @@ private void updateProgressBar(ProgressBar pb) {
202202
pb.setExtraMessage(matrixRepository.getProgressMessage());
203203
}
204204

205-
private void finalizeProgress(ProgressBar pb, int maxAttempts, int attempts) {
205+
private void finalizeProgress(ProgressBar pb, int attempts) {
206206
pb.stepTo(matrixRepository.getTotalMatrixCount());
207-
if (attempts >= maxAttempts) {
207+
if (attempts >= this.maxAttempts) {
208208
LOGGER.warn("Stopped route generation after {} attempts. Routes per profile: {}",
209-
maxAttempts, matrixRepository.getProgressMessage());
209+
this.maxAttempts, matrixRepository.getProgressMessage());
210210
}
211211
}
212212

ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/generators/CoordinateGeneratorRoute.java

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ public class CoordinateGeneratorRoute extends AbstractCoordinateGenerator {
4040

4141
public CoordinateGeneratorRoute(int numRoutes, double[] extent, String[] profiles, String baseUrl,
4242
double minDistance, Map<String, Double> maxDistanceByProfile, int numThreads,
43-
double snapRadius) {
44-
super(extent, profiles, baseUrl, "matrix");
43+
double snapRadius, int maxAttempts) {
44+
super(extent, profiles, baseUrl, "matrix", maxAttempts);
4545
validateInputs(numRoutes, minDistance, numThreads);
4646

4747
this.numRoutes = numRoutes;
@@ -84,13 +84,9 @@ private Map<String, Double> normalizeMaxDistances(String[] profiles, Map<String,
8484
return normalized;
8585
}
8686

87-
public void generateRoutes() {
88-
generate(DEFAULT_MAX_ATTEMPTS);
89-
}
90-
9187
@Override
92-
public void generate(int maxAttempts) {
93-
LOGGER.info("Starting route generation with {} threads and max attempts: {}", numThreads, maxAttempts);
88+
public void generate() {
89+
LOGGER.info("Starting route generation with {} threads and max attempts: {}", numThreads, this.maxAttempts);
9490
initializeCollections();
9591
LOGGER.debug("Collections initialized.");
9692

@@ -100,21 +96,21 @@ public void generate(int maxAttempts) {
10096

10197
try {
10298
executor = Executors.newFixedThreadPool(numThreads);
103-
executeRouteGeneration(executor, maxAttempts, shouldContinue, consecutiveFailedAttempts);
99+
executeRouteGeneration(executor, shouldContinue, consecutiveFailedAttempts);
104100
} catch (Exception e) {
105101
LOGGER.error("Error generating routes: ", e);
106102
} finally {
107103
shutdownExecutor(executor);
108104
}
109105
}
110106

111-
private void executeRouteGeneration(ExecutorService executor, int maxAttempts,
112-
AtomicBoolean shouldContinue, AtomicInteger consecutiveFailedAttempts) {
107+
private void executeRouteGeneration(ExecutorService executor, AtomicBoolean shouldContinue,
108+
AtomicInteger consecutiveFailedAttempts) {
113109
LOGGER.debug("executeRouteGeneration: Starting. Max attempts: {}, Should continue: {}, Consecutive Fails: {}",
114-
maxAttempts, shouldContinue.get(), consecutiveFailedAttempts.get());
110+
this.maxAttempts, shouldContinue.get(), consecutiveFailedAttempts.get());
115111
try (ProgressBar pb = createProgressBar()) {
116112
while (!routeRepository.areAllProfilesComplete(numRoutes) &&
117-
consecutiveFailedAttempts.get() < maxAttempts &&
113+
consecutiveFailedAttempts.get() < this.maxAttempts &&
118114
shouldContinue.get()) {
119115
LOGGER.debug(
120116
"executeRouteGeneration: Loop iteration. Profiles complete: {}, Consecutive Fails: {}, Should continue: {}",
@@ -154,7 +150,7 @@ private void executeRouteGeneration(ExecutorService executor, int maxAttempts,
154150
}
155151
}
156152

157-
finalizeProgress(pb, maxAttempts, consecutiveFailedAttempts.get());
153+
finalizeProgress(pb, consecutiveFailedAttempts.get());
158154
LOGGER.debug("executeRouteGeneration: Finalized progress.");
159155
}
160156
}
@@ -194,11 +190,11 @@ private void updateProgressBar(ProgressBar pb) {
194190
pb.setExtraMessage(routeRepository.getProgressMessage());
195191
}
196192

197-
private void finalizeProgress(ProgressBar pb, int maxAttempts, int attempts) {
193+
private void finalizeProgress(ProgressBar pb, int attempts) {
198194
pb.stepTo(routeRepository.getTotalRouteCount());
199-
if (attempts >= maxAttempts) {
195+
if (attempts >= this.maxAttempts) {
200196
LOGGER.warn("Stopped route generation after {} attempts. Routes per profile: {}",
201-
maxAttempts, routeRepository.getProgressMessage());
197+
this.maxAttempts, routeRepository.getProgressMessage());
202198
}
203199
}
204200

0 commit comments

Comments
 (0)