1 package org.opentrafficsim.draw.graphs;
2
3 import static org.junit.Assert.assertEquals;
4 import static org.junit.Assert.assertNull;
5 import static org.junit.Assert.assertTrue;
6 import static org.junit.Assert.fail;
7
8 import java.awt.event.ActionEvent;
9 import java.util.ArrayList;
10 import java.util.HashSet;
11 import java.util.LinkedHashSet;
12 import java.util.List;
13 import java.util.Set;
14
15 import javax.naming.NamingException;
16 import javax.swing.JOptionPane;
17
18 import org.djunits.unit.AccelerationUnit;
19 import org.djunits.unit.TimeUnit;
20 import org.djunits.unit.util.UNITS;
21 import org.djunits.value.vdouble.scalar.Acceleration;
22 import org.djunits.value.vdouble.scalar.Direction;
23 import org.djunits.value.vdouble.scalar.Duration;
24 import org.djunits.value.vdouble.scalar.Length;
25 import org.djunits.value.vdouble.scalar.Speed;
26 import org.djunits.value.vdouble.scalar.Time;
27 import org.djutils.immutablecollections.ImmutableArrayList;
28 import org.jfree.data.DomainOrder;
29 import org.junit.Test;
30 import org.mockito.ArgumentMatchers;
31 import org.mockito.Mockito;
32 import org.mockito.invocation.InvocationOnMock;
33 import org.mockito.stubbing.Answer;
34 import org.opentrafficsim.core.definitions.DefaultsNl;
35 import org.opentrafficsim.core.dsol.OtsModelInterface;
36 import org.opentrafficsim.core.dsol.OtsReplication;
37 import org.opentrafficsim.core.dsol.OtsSimulatorInterface;
38 import org.opentrafficsim.core.geometry.OtsGeometryException;
39 import org.opentrafficsim.core.geometry.OtsPoint3d;
40 import org.opentrafficsim.core.gtu.GtuException;
41 import org.opentrafficsim.core.gtu.GtuType;
42 import org.opentrafficsim.core.network.NetworkException;
43 import org.opentrafficsim.core.network.Node;
44 import org.opentrafficsim.draw.graphs.GraphPath.Section;
45 import org.opentrafficsim.draw.graphs.road.GraphLaneUtil;
46 import org.opentrafficsim.kpi.interfaces.LaneData;
47 import org.opentrafficsim.kpi.sampling.SamplerData;
48 import org.opentrafficsim.road.definitions.DefaultsRoadNl;
49 import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
50 import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedCfLcTacticalPlanner;
51 import org.opentrafficsim.road.gtu.lane.tactical.following.FixedAccelerationModel;
52 import org.opentrafficsim.road.gtu.lane.tactical.following.GtuFollowingModelOld;
53 import org.opentrafficsim.road.gtu.lane.tactical.following.SequentialFixedAccelerationModel;
54 import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.Egoistic;
55 import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.LaneChangeModel;
56 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
57 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalRoutePlanner;
58 import org.opentrafficsim.road.network.RoadNetwork;
59 import org.opentrafficsim.road.network.factory.LaneFactory;
60 import org.opentrafficsim.road.network.lane.Lane;
61 import org.opentrafficsim.road.network.lane.LanePosition;
62 import org.opentrafficsim.road.network.lane.LaneType;
63 import org.opentrafficsim.road.network.sampling.LaneDataRoad;
64 import org.opentrafficsim.road.network.sampling.RoadSampler;
65
66 import nl.tudelft.simulation.dsol.SimRuntimeException;
67 import nl.tudelft.simulation.dsol.formalisms.eventscheduling.SimEvent;
68 import nl.tudelft.simulation.dsol.formalisms.eventscheduling.SimEventInterface;
69
70
71
72
73
74
75
76
77
78 public class ContourPlotTest implements UNITS
79 {
80
81
82 @SuppressWarnings("unchecked")
83 GraphPath<LaneData> mockedPath = Mockito.mock(GraphPath.class);
84
85 Section<LaneData> section0 = Mockito.mock(Section.class);
86
87 Section<LaneData> section1 = Mockito.mock(Section.class);
88
89 LaneData mockedLane0 = Mockito.mock(LaneData.class);
90
91 LaneData mockedLane1 = Mockito.mock(LaneData.class);
92
93 SamplerData mockedSamplerData = Mockito.mock(SamplerData.class);
94
95 OtsSimulatorInterface mockedSimulator = Mockito.mock(OtsSimulatorInterface.class);
96
97 SimEventInterface<Duration> lastScheduledEvent = null;
98
99
100
101
102
103
104
105
106 private GraphPath<LaneDataRoad> dummyPath(final OtsSimulatorInterface simulator, final RoadNetwork network)
107 throws Exception
108 {
109 LaneType laneType = DefaultsRoadNl.TWO_WAY_LANE;
110 Node b = new Node(network, "B", new OtsPoint3d(12345, 0, 0), Direction.ZERO);
111 ArrayList<Lane> result = new ArrayList<Lane>();
112 Lane[] lanes =
113 LaneFactory.makeMultiLane(network, "AtoB", new Node(network, "A", new OtsPoint3d(1234, 0, 0), Direction.ZERO),
114 b, null, 1, laneType, new Speed(100, KM_PER_HOUR), simulator, DefaultsNl.VEHICLE);
115 result.add(lanes[0]);
116
117 lanes = LaneFactory.makeMultiLane(network, "BtoC", b,
118 new Node(network, "C", new OtsPoint3d(99999, 0, 0), Direction.ZERO), null, 1, laneType,
119 new Speed(100, KM_PER_HOUR), null, DefaultsNl.VEHICLE);
120 return GraphLaneUtil.createPath("AtoB", lanes[0]);
121 }
122
123
124
125
126
127
128 public final void setUp() throws SimRuntimeException, NamingException
129 {
130 Mockito.when(this.mockedPath.getTotalLength()).thenReturn(Length.valueOf("2000m"));
131 Mockito.when(this.mockedPath.getNumberOfSeries()).thenReturn(2);
132 Mockito.when(this.mockedPath.get(0)).thenReturn(this.section0);
133 Mockito.when(this.mockedPath.get(1)).thenReturn(this.section1);
134 Mockito.when(this.mockedPath.getStartDistance(this.section0)).thenReturn(Length.ZERO);
135 Mockito.when(this.mockedPath.getStartDistance(this.section1)).thenReturn(Length.valueOf("1234m"));
136 Mockito.when(this.mockedPath.getSpeedLimit()).thenReturn(Speed.valueOf("100 km/h"));
137 List<Section<LaneData>> sectionList = new ArrayList<>();
138 sectionList.add(this.section0);
139 sectionList.add(this.section1);
140 Mockito.when(this.mockedLane0.getLength()).thenReturn(Length.valueOf("1234m"));
141 Mockito.when(this.mockedLane1.getLength()).thenReturn(Length.valueOf("766m"));
142 Set<LaneData> set0 = new HashSet<>();
143 set0.add(this.mockedLane0);
144 Mockito.when(this.section0.iterator()).thenReturn(set0.iterator());
145 Set<LaneData> set1 = new HashSet<>();
146 set1.add(this.mockedLane1);
147 Mockito.when(this.section0.iterator()).thenReturn(set0.iterator());
148 Mockito.when(this.section1.iterator()).thenReturn(set1.iterator());
149 Mockito.when(this.mockedPath.getSections()).thenReturn(new ImmutableArrayList<>(sectionList));
150 Mockito.when(this.section0.getLength()).thenReturn(Length.valueOf("2000m"));
151 Mockito.when(this.section1.getLength()).thenReturn(Length.valueOf("766m"));
152 Mockito.when(this.mockedSimulator.scheduleEventAbsTime(ArgumentMatchers.any(Time.class), ArgumentMatchers.any(),
153 ArgumentMatchers.anyString(), ArgumentMatchers.isNull())).thenAnswer(new Answer<SimEventInterface<Duration>>()
154 {
155 @Override
156 public SimEventInterface<Duration> answer(final InvocationOnMock invocation) throws Throwable
157 {
158 ContourPlotTest.this.lastScheduledEvent =
159 new SimEvent<Duration>(((Time) invocation.getArgument(0)).minus(Time.ZERO),
160 invocation.getArgument(2), "update", null);
161 return ContourPlotTest.this.lastScheduledEvent;
162 }
163 });
164 Mockito.when(this.mockedSimulator.getSimulatorAbsTime()).thenReturn(Time.ZERO);
165 Mockito.when(this.mockedSimulator.getSimulatorTime()).thenReturn(Duration.ZERO);
166 OtsModelInterface model = Mockito.mock(OtsModelInterface.class);
167 OtsReplication replication = new OtsReplication("test", Time.ZERO, Duration.ZERO, Duration.instantiateSI(3600.0));
168 Mockito.when(this.mockedSimulator.getReplication()).thenReturn(replication);
169 }
170
171
172
173
174
175 @Test
176 public final void accelerationContourTest() throws Exception
177 {
178 setUp();
179 ContourDataSource dataPool = new ContourDataSource(this.mockedSamplerData, this.mockedPath);
180 ContourPlotAcceleration acp = new ContourPlotAcceleration("acceleration", this.mockedSimulator, dataPool);
181 assertEquals("SeriesKey should be \"acceleration\"", "acceleration", acp.getSeriesKey(0));
182 standardContourTests(this.mockedSimulator, acp, this.mockedPath, Double.NaN, 0);
183 }
184
185
186
187
188
189 @Test
190 public final void densityContourTest() throws Exception
191 {
192 setUp();
193 OtsSimulatorInterface simulator = this.mockedSimulator;
194 RoadNetwork network = new RoadNetwork("density contour test network", simulator);
195 GraphPath<LaneDataRoad> path = dummyPath(simulator, network);
196 RoadSampler sampler = new RoadSampler(network);
197 ContourDataSource dataPool = new ContourDataSource(sampler.getSamplerData(), path);
198 ContourPlotDensity dcp = new ContourPlotDensity("density", simulator, dataPool);
199 assertTrue("newly created DensityContourPlot should not be null", null != dcp);
200 assertEquals("SeriesKey should be \"density\"", "density", dcp.getSeriesKey(0));
201 standardContourTests(simulator, dcp, path, Double.NaN, Double.NaN);
202 }
203
204
205
206
207
208 @Test
209 public final void flowContourTest() throws Exception
210 {
211 setUp();
212 OtsSimulatorInterface simulator = this.mockedSimulator;
213 RoadNetwork network = new RoadNetwork("flow contour test network", simulator);
214 GraphPath<LaneDataRoad> path = dummyPath(simulator, network);
215 RoadSampler sampler = new RoadSampler(network);
216 ContourDataSource dataPool = new ContourDataSource(sampler.getSamplerData(), path);
217 ContourPlotFlow fcp = new ContourPlotFlow("flow", simulator, dataPool);
218 assertTrue("newly created DensityContourPlot should not be null", null != fcp);
219 assertEquals("SeriesKey should be \"flow\"", "flow", fcp.getSeriesKey(0));
220 standardContourTests(simulator, fcp, path, Double.NaN, Double.NaN);
221 }
222
223
224
225
226
227 @Test
228 public final void speedContourTest() throws Exception
229 {
230 setUp();
231 OtsSimulatorInterface simulator = this.mockedSimulator;
232 RoadNetwork network = new RoadNetwork("flow contour test network", simulator);
233 GraphPath<LaneDataRoad> path = dummyPath(simulator, network);
234 RoadSampler sampler = new RoadSampler(network);
235 ContourDataSource dataPool = new ContourDataSource(sampler.getSamplerData(), path);
236 ContourPlotSpeed scp = new ContourPlotSpeed("speed", simulator, dataPool);
237 assertTrue("newly created DensityContourPlot should not be null", null != scp);
238 assertEquals("SeriesKey should be \"speed\"", "speed", scp.getSeriesKey(0));
239 standardContourTests(simulator, scp, path, Double.NaN, 50);
240 }
241
242
243
244
245
246
247
248
249
250 static void printMatrix(final AbstractContourPlot<?> cp, final int fromX, final int toX, final int fromY, final int toY)
251 {
252 System.out.println("Contour plot data:");
253 int maxItem = cp.getItemCount(0);
254 for (int y = fromY; y <= toY; y++)
255 {
256 System.out.print(String.format("y=%3d ", y));
257 for (int x = fromX; x <= toX; x++)
258 {
259
260 int item;
261 for (item = 0; item < maxItem; item++)
262 {
263 if (cp.getXValue(0, item) == x && cp.getYValue(0, item) == y)
264 {
265 break;
266 }
267 }
268 if (item < maxItem)
269 {
270 System.out.print(String.format("%10.6f", cp.getZValue(0, item)));
271 }
272 else
273 {
274 System.out.print(" -------- ");
275 }
276 }
277 System.out.println("");
278 }
279 System.out.print("");
280 }
281
282
283
284
285
286
287
288
289
290
291
292
293 public static void standardContourTests(final OtsSimulatorInterface simulator, final AbstractContourPlot<?> cp,
294 final GraphPath<?> path, final double expectedZValue, final double expectedZValueWithTraffic) throws Exception
295 {
296 assertEquals("seriesCount should be 1", 1, cp.getSeriesCount());
297 assertEquals("domainOrder should be ASCENDING", DomainOrder.ASCENDING, cp.getDomainOrder());
298 assertEquals("indexOf always returns 0", 0, cp.indexOf(0));
299 assertEquals("indexOf always returns 0", 0, cp.indexOf("abc"));
300 assertNull("getGroup always returns null", cp.getGroup());
301 int xBins = cp.getDataPool().timeAxis.getBinCount();
302 int yBins = cp.getDataPool().spaceAxis.getBinCount();
303 int expectedXBins = (int) Math.ceil(((AbstractPlot.DEFAULT_INITIAL_UPPER_TIME_BOUND).getSI())
304 / ContourDataSource.DEFAULT_TIME_GRANULARITIES[ContourDataSource.DEFAULT_TIME_GRANULARITY_INDEX]
305 + (cp.getDataPool().timeAxis.isInterpolate() ? 1 : 0));
306 assertEquals("Initial xBins should be " + expectedXBins, expectedXBins, xBins);
307 int expectedYBins = (int) Math.ceil(path.getTotalLength().getSI()
308 / ContourDataSource.DEFAULT_SPACE_GRANULARITIES[ContourDataSource.DEFAULT_SPACE_GRANULARITY_INDEX]
309 + (cp.getDataPool().timeAxis.isInterpolate() ? 1 : 0));
310 assertEquals("yBins should be " + expectedYBins, expectedYBins, yBins);
311 int bins = cp.getItemCount(0);
312 assertEquals("Total bin count is product of xBins * yBins", xBins * yBins, bins);
313 String initialUpperTimeBoundString = AbstractPlot.DEFAULT_INITIAL_UPPER_TIME_BOUND.toString();
314
315 for (double timeGranularity : ContourDataSource.DEFAULT_TIME_GRANULARITIES)
316 {
317 cp.actionPerformed(new ActionEvent(timeGranularity, 0, "setTimeGranularity"));
318
319 for (double distanceGranularity : ContourDataSource.DEFAULT_SPACE_GRANULARITIES)
320 {
321 cp.actionPerformed(new ActionEvent(distanceGranularity, 0, "setSpaceGranularity"));
322 cp.notifyPlotChange();
323 expectedXBins = (int) Math.ceil((AbstractPlot.DEFAULT_INITIAL_UPPER_TIME_BOUND.getSI()) / timeGranularity)
324 + (cp.getDataPool().timeAxis.isInterpolate() ? 1 : 0);
325 xBins = cp.getDataPool().timeAxis.getBinCount();
326 assertEquals("Modified xBins should be " + expectedXBins, expectedXBins, xBins);
327 expectedYBins = (int) Math.ceil(path.get(0).getLength().getSI() / distanceGranularity)
328 + (cp.getDataPool().spaceAxis.isInterpolate() ? 1 : 0);
329 yBins = cp.getDataPool().spaceAxis.getBinCount();
330
331
332
333 assertEquals("Modified yBins should be " + expectedYBins, expectedYBins, yBins);
334 bins = cp.getItemCount(0);
335 assertEquals("Total bin count is product of xBins * yBins", xBins * yBins, bins);
336 for (int item = 0; item < bins; item++)
337 {
338 double x = cp.getXValue(0, item);
339
340 assertTrue("X should be >= -granularity / 2", x >= -timeGranularity / 2);
341 assertTrue("X should be <= " + initialUpperTimeBoundString,
342 x <= AbstractPlot.DEFAULT_INITIAL_UPPER_TIME_BOUND.getSI());
343 Number alternateX = cp.getX(0, item);
344 assertEquals("getXValue and getX should return things that have the same value", x,
345 alternateX.doubleValue(), 0.000001);
346 double y = cp.getYValue(0, item);
347 Number alternateY = cp.getY(0, item);
348 assertEquals("getYValue and getY should return things that have the same value", y,
349 alternateY.doubleValue(), 0.000001);
350 double z = cp.getZValue(0, item);
351 if (Double.isNaN(expectedZValue))
352 {
353 assertTrue("Z value should be NaN", Double.isNaN(z));
354 }
355 else
356 {
357 assertEquals("Z value should be " + expectedZValue, expectedZValue, z, 0.0001);
358 }
359 Number alternateZ = cp.getZ(0, item);
360 if (Double.isNaN(expectedZValue))
361 {
362 assertTrue("Alternate Z value should be NaN", Double.isNaN(alternateZ.doubleValue()));
363 }
364 else
365 {
366 assertEquals("Alternate Z value should be " + expectedZValue, expectedZValue, alternateZ.doubleValue(),
367 0.0000);
368 }
369 }
370 try
371 {
372 cp.getXValue(0, -1);
373 fail("Should have thrown an Exception");
374 }
375 catch (RuntimeException e)
376 {
377
378 }
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406 }
407 }
408
409 try
410 {
411 cp.actionPerformed(new ActionEvent(cp, 0, "blabla"));
412 fail("Should have thrown an Exception");
413 }
414 catch (RuntimeException e)
415 {
416
417 }
418 try
419 {
420 cp.actionPerformed(new ActionEvent(cp, 0, "setDistanceGranularity -1"));
421 fail("Should have thrown an Exception");
422 }
423 catch (RuntimeException e)
424 {
425
426 }
427 try
428 {
429 cp.actionPerformed(new ActionEvent(cp, 0, "setDistanceGranularity abc"));
430 fail("Should have thrown an Exception");
431 }
432 catch (RuntimeException e)
433 {
434
435 }
436 try
437 {
438 cp.actionPerformed(new ActionEvent(cp, 0, "setDistanceGranularitIE 10"));
439 fail("Should have thrown an Exception");
440 }
441 catch (RuntimeException e)
442 {
443
444 }
445
446 final double useTimeGranularity = 30;
447 cp.actionPerformed(new ActionEvent(useTimeGranularity, 0, "setTimeGranularity"));
448 final double useDistanceGranularity =
449 ContourDataSource.DEFAULT_SPACE_GRANULARITIES[ContourDataSource.DEFAULT_SPACE_GRANULARITIES.length - 1];
450 cp.actionPerformed(new ActionEvent(useDistanceGranularity, 0, "setSpaceGranularity"));
451 cp.notifyPlotChange();
452 bins = cp.getItemCount(0);
453 Time initialTime = new Time(0, TimeUnit.BASE_SECOND);
454 Length initialPosition = new Length(100, METER);
455 Speed initialSpeed = new Speed(50, KM_PER_HOUR);
456
457 SequentialFixedAccelerationModel gtuFollowingModel =
458 new SequentialFixedAccelerationModel(simulator, new Acceleration(2.0, AccelerationUnit.METER_PER_SECOND_2));
459
460 gtuFollowingModel
461 .addStep(new FixedAccelerationModel(new Acceleration(0, METER_PER_SECOND_2), new Duration(60, SECOND)));
462
463 gtuFollowingModel
464 .addStep(new FixedAccelerationModel(new Acceleration(0, METER_PER_SECOND_2), new Duration(600, SECOND)));
465
466 gtuFollowingModel
467 .addStep(new FixedAccelerationModel(new Acceleration(0, METER_PER_SECOND_2), new Duration(300, SECOND)));
468 LaneChangeModel laneChangeModel = new Egoistic();
469
470
471 for (int item = 0; item < bins; item++)
472 {
473 double x = cp.getXValue(0, item);
474
475
476 assertTrue("X should be >= -timeGranularity / 2", x >= -cp.getTimeGranularity() / 2);
477 assertTrue("X should be <= " + initialUpperTimeBoundString, x <= AbstractPlot.DEFAULT_INITIAL_UPPER_TIME_BOUND.si);
478 Number alternateX = cp.getX(0, item);
479 assertEquals("getXValue and getX should return things that have the same value", x, alternateX.doubleValue(),
480 0.000001);
481 double y = cp.getYValue(0, item);
482 Number alternateY = cp.getY(0, item);
483 assertEquals("getYValue and getY should return things that have the same value", y, alternateY.doubleValue(),
484 0.000001);
485 double z = cp.getZValue(0, item);
486 if (Double.isNaN(expectedZValue))
487 {
488 assertTrue("Z value should be NaN (got " + z + ")", Double.isNaN(z));
489 }
490 else
491 {
492 assertEquals("Z value should be " + expectedZValue, expectedZValue, z, 0.0001);
493 }
494 Number alternateZ = cp.getZ(0, item);
495 if (Double.isNaN(expectedZValue))
496 {
497 assertTrue("Alternate Z value should be NaN", Double.isNaN(alternateZ.doubleValue()));
498 }
499 else
500 {
501 assertEquals("Alternate Z value should be " + expectedZValue, expectedZValue, alternateZ.doubleValue(), 0.0000);
502 }
503 }
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743 }
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764 private static LaneBasedGtu makeReferenceCar(final String id, final GtuType gtuType, final Lane lane,
765 final Length initialPosition, final Speed initialSpeed, final OtsSimulatorInterface simulator,
766 final GtuFollowingModelOld gtuFollowingModel, final LaneChangeModel laneChangeModel, final RoadNetwork network)
767 throws NamingException, NetworkException, SimRuntimeException, GtuException, OtsGeometryException
768 {
769
770 Length length = new Length(5.0, METER);
771 Length width = new Length(2.0, METER);
772 Set<LanePosition> initialLongitudinalPositions = new LinkedHashSet<>(1);
773 initialLongitudinalPositions.add(new LanePosition(lane, initialPosition));
774 Speed maxSpeed = new Speed(120, KM_PER_HOUR);
775 LaneBasedGtu gtu = new LaneBasedGtu(id, gtuType, length, width, maxSpeed, length.times(0.5), network);
776 LaneBasedStrategicalPlanner strategicalPlanner = new LaneBasedStrategicalRoutePlanner(
777 new LaneBasedCfLcTacticalPlanner(gtuFollowingModel, laneChangeModel, gtu), gtu);
778 gtu.init(strategicalPlanner, initialLongitudinalPositions, initialSpeed);
779
780 return gtu;
781 }
782
783
784
785
786
787
788 public static void main(final String[] args) throws Exception
789 {
790 ContourPlotTest cpt = new ContourPlotTest();
791 System.out.println("Click the OK button");
792 JOptionPane.showMessageDialog(null, "ContourPlot", "Start experiment", JOptionPane.INFORMATION_MESSAGE);
793 System.out.println("Running ...");
794 cpt.densityContourTest();
795 System.out.println("Finished");
796 }
797
798 }