protected void validate() {

    if (myController == null)
      BeatsErrorLog.addError("Invalid controller for pretimed signal plan id=" + getId() + ".");

    // positive cycle
    if (_cyclelength <= 0)
      BeatsErrorLog.addError(
          "Non-positive cycle length in pretimed signal controller id=" + getId() + ".");

    // cycle length should be a multiple of controller dt
    if (myController != null)
      if (!BeatsMath.isintegermultipleof(_cyclelength, myController.getDtinseconds()))
        BeatsErrorLog.addError(
            "Cycle length is not an integer multiple of controller rate in pretimed signal controller id="
                + getId()
                + ".");

    // plan includes all targets
    boolean foundit;
    if (myController != null)
      for (ScenarioElement se : myController.getTargets()) {
        foundit = false;
        for (int i = 0; i < intersplan.length; i++) {
          if (se.getId().equals(intersplan[i].mySignal.getId())) {
            foundit = true;
            break;
          }
        }
        if (!foundit)
          BeatsErrorLog.addError(
              "Controller target (id="
                  + se.getId()
                  + ") not found in pretimed signal plan id="
                  + getId());
      }

    // intersection plans
    for (int i = 0; i < intersplan.length; i++)
      intersplan[i].validate(myController.getDtinseconds());
  }
    public void update(Clock clock) {

      int i, j;
      int e = 0;

      if (measured_flow_profile_veh.sample(false, clock))
        current_flow_veh = measured_flow_profile_veh.getCurrentSample() * knob;

      if (BeatsMath.equals(current_flow_veh, 0d)) {
        beta = 0d;
        return;
      }

      // Sf: total demand from "feeds"
      Double Sf = 0d;
      for (Link link : feeds) Sf += BeatsMath.sum(link.get_out_demand_in_veh(e));

      // compute demand to non-measured, total $+phi, and from feed links phi
      ArrayList<Double> beta_array = new ArrayList<Double>();

      // compute sr normalization factor for feeding links
      //            for(i=0;i<myNode.getInput_link().length;i++) {
      //                if (!feeds.contains( myNode.input_link[i]))
      //                    continue;
      //                alpha_tilde[i] = 0d;
      //                for (j = 0; j < myNode.nOut; j++)
      //                    if(not_meas.contains( myNode.output_link[j]))
      //                        alpha_tilde[i] += myNode.getSplitRatio(i, j);
      //            }

      // freeflow case
      beta_array.add(0d);
      beta_array.add(current_flow_veh / Sf);

      // rest
      for (j = 0; j < myNode.nOut; j++) {
        Link outlink = myNode.output_link[j];

        // case for the measured
        if (not_meas.contains(outlink)) {

          double dem_non_feed = 0d; // demand on j from non-feeding links
          double dem_feed = 0d; // demand on j from feeding links

          for (i = 0; i < myNode.nIn; i++) {
            Link inlink = myNode.input_link[i];
            //                        Double alpha_ij = myNode.getSplitRatio(i,j);
            Double Si = BeatsMath.sum(inlink.get_out_demand_in_veh(e));
            if (feeds.contains(inlink)) dem_feed += Si; // alpha_ij * Si / alpha_tilde[i];
            else // otherwise add to total
            dem_non_feed += 0d; // alpha_ij * Si;
          }

          Double R = outlink.get_available_space_supply_in_veh(e);

          double num = current_flow_veh * (dem_non_feed + dem_feed);
          double den = Sf * R + dem_feed * current_flow_veh;

          beta_array.add(den > 0 ? num / den : Double.POSITIVE_INFINITY);
        }
      }

      beta = Math.min(BeatsMath.max(beta_array), 1d);
    }