/**
   * Test that the scoring function works even when we don't spend the night at home, but don't end
   * the day with an ongoing activity at all. This is half of the case when the first and last
   * activity aren't the same.
   */
  @Test
  public void testNoNightActivity() {

    double zeroUtilDurW = getZeroUtilDuration_hrs(3.0, 1.0);
    double zeroUtilDurH = getZeroUtilDuration_hrs(7.0, 1.0);
    double perf = +3.0;

    Fixture f = new Fixture();
    // Need to change the typical duration of the home activity
    // for this test, since with the setting of 15 hours for "home",
    // this would amount to a smaller-than-zero expected contribution of
    // the home activity at 7 hours, and smaller-than-zero contributions
    // are truncated, so we wouldn't test anything. :-/
    f.config.planCalcScore().getActivityParams("h").setTypicalDuration(7.0 * 3600);
    f.config.planCalcScore().setPerforming_utils_hr(perf);

    ScoringFunction testee = getScoringFunctionInstance(f, f.person);
    testee.handleActivity((Activity) f.plan.getPlanElements().get(0));
    testee.handleLeg((Leg) f.plan.getPlanElements().get(1));
    testee.handleActivity((Activity) f.plan.getPlanElements().get(2));
    testee.finish();

    assertEquals(
        perf * 3.0 * Math.log(2.5 / zeroUtilDurW) + perf * 7.0 * Math.log(7.0 / zeroUtilDurH),
        testee.getScore(),
        EPSILON);
  }
 private double calcScore(final Fixture f) {
   CharyparNagelScoringFunctionFactory charyparNagelScoringFunctionFactory =
       new CharyparNagelScoringFunctionFactory(f.config.planCalcScore(), f.scenario.getNetwork());
   ScoringFunction testee =
       charyparNagelScoringFunctionFactory.createNewScoringFunction(
           new PersonImpl(Id.create("1", Person.class)));
   for (PlanElement planElement : f.plan.getPlanElements()) {
     if (planElement instanceof Activity) {
       testee.handleActivity((Activity) planElement);
     } else if (planElement instanceof Leg) {
       testee.handleLeg((Leg) planElement);
     }
   }
   testee.finish();
   double score = testee.getScore();
   EventsToScore eventsToScore =
       new EventsToScore(f.scenario, charyparNagelScoringFunctionFactory);
   double scoreFromEvents = calcScoreFromEvents(eventsToScore, f);
   assertEquals(
       "Score computed from the plan elements should be the same as score computed from stream of events constructed from plan elements.",
       score,
       scoreFromEvents,
       EPSILON);
   return score;
 }
  /**
   * Tests if the scoring function correctly handles {@link PersonMoneyEvent}. It generates one
   * person with one plan having two activities (home, work) and a car-leg in between. It then tests
   * the scoring function by calling several methods on an instance of the scoring function with the
   * aforementioned plan.
   */
  @Test
  public void testAddMoney() {
    Fixture f = new Fixture();

    // score the same plan twice
    PersonImpl person1 = new PersonImpl(Id.create(1, Person.class));
    PlanImpl plan1 = person1.createAndAddPlan(true);
    Activity act1a =
        plan1.createAndAddActivity("home", (Id<Link>) null); // , 0, 7.0*3600, 7*3600, false);
    act1a.setEndTime(f.secondLegStartTime);
    Leg leg1 = plan1.createAndAddLeg(TransportMode.car); // , 7*3600, 100, 7*3600+100);
    leg1.setDepartureTime(f.secondLegStartTime);
    leg1.setTravelTime(f.secondLegTravelTime);
    Route route2 = new GenericRouteImpl(null, null);
    leg1.setRoute(route2);
    route2.setDistance(20000.0);
    Activity act1b =
        plan1.createAndAddActivity(
            "work",
            (Id<Link>) null); // , 7.0*3600+100, Time.UNDEFINED_TIME, Time.UNDEFINED_TIME, false);
    act1b.setStartTime(f.secondLegStartTime + f.secondLegTravelTime);
    ScoringFunction sf1 = getScoringFunctionInstance(f, person1);
    sf1.handleActivity(act1a);
    sf1.handleLeg(leg1);
    sf1.handleActivity(act1b);

    sf1.finish();
    double score1 = sf1.getScore();

    ScoringFunction sf2 = getScoringFunctionInstance(f, person1);
    sf2.handleActivity(act1a);
    sf2.addMoney(1.23);
    sf2.handleLeg(leg1);
    sf2.addMoney(-2.46);
    sf2.handleActivity(act1b);
    sf2.addMoney(4.86);
    sf2.addMoney(-0.28);
    sf2.finish();
    double score2 = sf2.getScore();

    assertEquals(1.23 - 2.46 + 4.86 - 0.28, score2 - score1, EPSILON);
  }
  /**
   * Test that the stuck penalty is correctly computed. It should be the worst (dis)utility the
   * agent could gain.
   */
  @Test
  public void testStuckPenalty() {
    Fixture f = new Fixture();
    // test 1 where late arrival has the biggest impact
    f.config.planCalcScore().setLateArrival_utils_hr(-18.0);
    f.config.planCalcScore().setTraveling_utils_hr(-6.0);

    ScoringFunction testee = getScoringFunctionInstance(f, f.person);
    testee.handleActivity((Activity) f.plan.getPlanElements().get(0));
    testee.handleLeg((Leg) f.plan.getPlanElements().get(1));
    testee.handleActivity((Activity) f.plan.getPlanElements().get(2));
    testee.handleLeg((Leg) f.plan.getPlanElements().get(3));

    testee.agentStuck(16 * 3600 + 7.5 * 60);
    testee.finish();
    testee.getScore();

    assertEquals(
        24 * -18.0 - 6.0 * 0.50, testee.getScore(), EPSILON); // stuck penalty + 30min traveling

    // test 2 where traveling has the biggest impact
    f.config.planCalcScore().setLateArrival_utils_hr(-3.0);
    f.config.planCalcScore().setTraveling_utils_hr(-6.0);

    testee = getScoringFunctionInstance(f, f.person);
    testee.handleActivity((Activity) f.plan.getPlanElements().get(0));
    testee.handleLeg((Leg) f.plan.getPlanElements().get(1));
    testee.handleActivity((Activity) f.plan.getPlanElements().get(2));
    testee.handleLeg((Leg) f.plan.getPlanElements().get(3));
    testee.agentStuck(16 * 3600 + 7.5 * 60);
    testee.finish();
    testee.getScore();

    assertEquals(
        24 * -6.0 - 6.0 * 0.50, testee.getScore(), EPSILON); // stuck penalty + 30min traveling
  }