0001: /*
0002: * <copyright>
0003: *
0004: * Copyright 1997-2004 BBNT Solutions, LLC
0005: * under sponsorship of the Defense Advanced Research Projects
0006: * Agency (DARPA).
0007: *
0008: * You can redistribute this software and/or modify it under the
0009: * terms of the Cougaar Open Source License as published on the
0010: * Cougaar Open Source Website (www.cougaar.org).
0011: *
0012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
0015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
0016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0023: *
0024: * </copyright>
0025: */
0026:
0027: package org.cougaar.logistics.plugin.inventory;
0028:
0029: import org.cougaar.core.mts.MessageAddress;
0030: import org.cougaar.glm.ldm.asset.Inventory;
0031: import org.cougaar.glm.ldm.asset.SupplyClassPG;
0032: import org.cougaar.glm.ldm.plan.AlpineAspectType;
0033: import org.cougaar.glm.ldm.plan.ObjectScheduleElement;
0034: import org.cougaar.glm.ldm.plan.PlanScheduleElementType;
0035: import org.cougaar.glm.ldm.plan.QuantityScheduleElement;
0036: import org.cougaar.glm.ldm.plan.QuantityScheduleElementImpl;
0037: import org.cougaar.logistics.ldm.Constants;
0038: import org.cougaar.logistics.plugin.packer.GenericPlugin;
0039: import org.cougaar.planning.ldm.PlanningFactory;
0040: import org.cougaar.planning.ldm.asset.AggregateAsset;
0041: import org.cougaar.planning.ldm.asset.Asset;
0042: import org.cougaar.planning.ldm.measure.*;
0043: import org.cougaar.planning.ldm.plan.*;
0044: import org.cougaar.planning.plugin.util.PluginHelper;
0045: import org.cougaar.util.MoreMath;
0046: import org.cougaar.util.TimeSpan;
0047: import org.cougaar.util.log.Logger;
0048:
0049: import java.io.Serializable;
0050: import java.util.*;
0051:
0052: /** Provides convenience methods. */
0053: public class TaskUtils extends PluginHelper implements Serializable { // revisit making Serializable later...
0054:
0055: private transient Logger logger;
0056: private transient UtilsProvider utilProvider;
0057: private transient AssetUtils assetUtils;
0058:
0059: public TaskUtils(UtilsProvider provider) {
0060: super ();
0061: utilProvider = provider;
0062: logger = (Logger) utilProvider.getLoggingService(this );
0063: assetUtils = utilProvider.getAssetUtils();
0064: }
0065:
0066: public TaskUtils(Logger aLogger) {
0067: super ();
0068: utilProvider = null;
0069: logger = aLogger;
0070: assetUtils = new AssetUtils(aLogger);
0071: }
0072:
0073: /** @param task the task
0074: * @return true if the task has an packer INTERNAL prep phrase */
0075: public static boolean isInternal(Task task) {
0076: PrepositionalPhrase pp = task
0077: .getPrepositionalPhrase(GenericPlugin.INTERNAL);
0078: if (pp == null) {
0079: return false;
0080: }
0081: return true;
0082: }
0083:
0084: /** @param t the task
0085: * @param type type identification string
0086: * @return true if the task's OFTYPE preposition's indirect object is
0087: * an asset with nomeclature equal to 'type'.*/
0088: public static boolean isTaskOfType(Task t, String type) {
0089: PrepositionalPhrase pp = t
0090: .getPrepositionalPhrase(Constants.Preposition.OFTYPE);
0091: if (pp != null) {
0092: Object obj = pp.getIndirectObject();
0093: if (obj instanceof Asset) {
0094: Asset a = (Asset) obj;
0095: return a.getTypeIdentificationPG()
0096: .getTypeIdentification().equals(type);
0097: }
0098: }
0099: return false;
0100: }
0101:
0102: /** @param t the task
0103: * @param type type identification string
0104: * @return true if the task's OFTYPE preposition's indirect object is
0105: * an string with nomeclature equal to 'type'.*/
0106: public static boolean isTaskOfTypeString(Task t, String type) {
0107: PrepositionalPhrase pp = t
0108: .getPrepositionalPhrase(Constants.Preposition.OFTYPE);
0109: if (pp != null) {
0110: Object obj = pp.getIndirectObject();
0111: if (obj instanceof String) {
0112: return ((String) obj).equals(type);
0113: }
0114: }
0115: return false;
0116: }
0117:
0118: public boolean isDirectObjectOfType(Task t, String type) {
0119: boolean result = false;
0120: Asset asset = t.getDirectObject();
0121: // Check for aggregate assets and grab the prototype
0122: if (asset instanceof AggregateAsset) {
0123: asset = ((AggregateAsset) asset).getAsset();
0124: }
0125: try {
0126: SupplyClassPG pg = (SupplyClassPG) asset
0127: .searchForPropertyGroup(SupplyClassPG.class);
0128: if (pg != null) {
0129: result = type.equals(pg.getSupplyType());
0130: if ((result == true)
0131: && (type.equals("PackagedPOL"))
0132: && asset.getTypeIdentificationPG()
0133: .getTypeIdentification().endsWith(
0134: "Aggregate")) {
0135: logger
0136: .debug("\n direct object type... type for plugin is: "
0137: + type
0138: + "]"
0139: + " type for DO is: ["
0140: + pg.getSupplyType() + "]");
0141: }
0142:
0143: } else {
0144: logger.debug("No SupplyClassPG found on asset "
0145: + this .taskDesc(t));
0146: }
0147: } catch (Exception e) {
0148: logger.error("Tasks DO is null " + this .taskDesc(t) + "\n"
0149: + e);
0150: }
0151: return result;
0152: }
0153:
0154: // utility functions
0155: public String taskDesc(Task task) {
0156: if (isProjection(task)) {
0157: return task.getUID()
0158: + ": "
0159: + task.getVerb()
0160: + "("
0161: + getDailyQuantity(task, getStartTime(task))
0162: + " "
0163: + getTaskItemName(task)
0164: + ") "
0165: + getTimeUtils().dateString(
0166: new Date(getStartTime(task)))
0167: + " - "
0168: + getTimeUtils().dateString(
0169: new Date(getEndTime(task)));
0170: } else {
0171: return task.getUID()
0172: + ": "
0173: + task.getVerb()
0174: + "("
0175: + getQuantity(task)
0176: + " "
0177: + getTaskItemName(task)
0178: + ") "
0179: + getTimeUtils().dateString(
0180: new Date(getEndTime(task)));
0181: }
0182: }
0183:
0184: public String getTaskItemName(Task task) {
0185: Asset prototype = (Asset) task.getDirectObject();
0186: if (prototype == null)
0187: return "null";
0188: return assetUtils.assetDesc(prototype);
0189: }
0190:
0191: public static boolean isMyRefillTask(Task task, String myOrgName) {
0192: PrepositionalPhrase pp = task
0193: .getPrepositionalPhrase(Constants.Preposition.REFILL);
0194: if (pp == null) {
0195: return false;
0196: }
0197: pp = task.getPrepositionalPhrase(Constants.Preposition.FOR);
0198: if (pp == null) {
0199: return false;
0200: }
0201: Object io = pp.getIndirectObject();
0202: if (io instanceof String) {
0203: String orgName = (String) io;
0204: if (orgName.equals(myOrgName)) {
0205: return true;
0206: }
0207: }
0208: return false;
0209: }
0210:
0211: public static boolean isMyNonRefillTask(Task task, String myOrgName) {
0212: PrepositionalPhrase pp = task
0213: .getPrepositionalPhrase(Constants.Preposition.REFILL);
0214: if (pp != null) {
0215: return false;
0216: }
0217: pp = task.getPrepositionalPhrase(Constants.Preposition.FOR);
0218: if (pp == null) {
0219: return false;
0220: }
0221: Object io = pp.getIndirectObject();
0222: if (io instanceof String) {
0223: String orgName = (String) io;
0224: if (orgName.equals(myOrgName)) {
0225: return true;
0226: }
0227: }
0228: return false;
0229: }
0230:
0231: public static boolean isMyInventoryProjection(Task task,
0232: String myOrgName) {
0233: PrepositionalPhrase pp = task
0234: .getPrepositionalPhrase(Constants.Preposition.FOR);
0235: if (pp == null) {
0236: return false;
0237: }
0238: Object io = pp.getIndirectObject();
0239: if (io instanceof String) {
0240: String orgName = (String) io;
0241: if (orgName.equals(myOrgName)) {
0242: pp = task
0243: .getPrepositionalPhrase(Constants.Preposition.MAINTAINING);
0244: if (pp != null) {
0245: try {
0246: if (((MaintainedItem) pp.getIndirectObject())
0247: .getMaintainedItemType().equals(
0248: "Inventory")) {
0249: return true;
0250: }
0251: } catch (ClassCastException exc) {
0252: return false;
0253: }
0254: }
0255: }
0256: }
0257: return false;
0258: }
0259:
0260: public boolean isReadyForTransport(Task task) {
0261: PrepositionalPhrase pp = task
0262: .getPrepositionalPhrase(Constants.Preposition.READYFORTRANSPORT);
0263: return (pp != null);
0264: }
0265:
0266: public boolean isMyDemandForecastProjection(Task task,
0267: String orgName) {
0268: PrepositionalPhrase pp = task
0269: .getPrepositionalPhrase(Constants.Preposition.FOR);
0270: if (pp == null) {
0271: return false;
0272: }
0273: Object io = pp.getIndirectObject();
0274: if (io instanceof String) {
0275: String taskOrg = (String) io;
0276: if (taskOrg.equals(orgName)) {
0277: pp = task
0278: .getPrepositionalPhrase(Constants.Preposition.REFILL);
0279: return (pp == null);
0280: }
0281: }
0282: return false;
0283: }
0284:
0285: /** return the preference of the given aspect type. Returns null if
0286: * the task does not have the given aspect. */
0287: public static double getPreference(Task t, int aspect_type) {
0288: Preference p = t.getPreference(aspect_type);
0289: if (p == null)
0290: return Double.NaN;
0291:
0292: AspectScorePoint asp = p.getScoringFunction().getBest();
0293: return asp.getValue();
0294: }
0295:
0296: public static boolean isProjection(Task t) {
0297: return (t
0298: .getPrepositionalPhrase(Constants.Preposition.DEMANDRATE) != null || t
0299: .getPreference(AlpineAspectType.DEMANDRATE) != null);
0300: }
0301:
0302: public static boolean isSupply(Task t) {
0303: return !isProjection(t);
0304: }
0305:
0306: public boolean isLevel2(Task t) {
0307: return assetUtils.isLevel2Asset(t.getDirectObject());
0308: }
0309:
0310: // TASK PREFERENCE UTILS
0311:
0312: public static double getQuantity(Task task) {
0313: return getPreferenceBestValue(task, AspectType.QUANTITY);
0314: }
0315:
0316: public static Preference createDemandRatePreference(
0317: PlanningFactory rf, Rate rate) {
0318: ScoringFunction sf = ScoringFunction
0319: .createStrictlyAtValue(AspectValue.newAspectValue(
0320: AlpineAspectType.DEMANDRATE, rate));
0321: return rf.newPreference(AlpineAspectType.DEMANDRATE, sf);
0322: }
0323:
0324: /**
0325: * Compare the preferences of two tasks return true if the tasks
0326: * have preferences for the same aspect types and if all
0327: * corresponding AspectValues are nearly equal.
0328: * This needs to be fixed to be more efficient.
0329: **/
0330: private boolean comparePreferences(Task a, Task b) {
0331: return comparePreferencesInner(a, b)
0332: && comparePreferencesInner(b, a);
0333: }
0334:
0335: private boolean comparePreferencesInner(Task a, Task b) {
0336: Enumeration ae = a.getPreferences();
0337: while (ae.hasMoreElements()) {
0338: Preference p = (Preference) ae.nextElement();
0339: int at = p.getAspectType();
0340: double av = p.getScoringFunction().getBest().getValue();
0341: double bv = getPreferenceBestValue(b, at);
0342: if (at == AspectType.START_TIME
0343: || at == AspectType.END_TIME) {
0344: //for times say they are nearly equal if they are within the same hour
0345: // it could be longer if we only had daily buckets - but this should
0346: // work for both daily and hourly buckets
0347: long aHourLong = (long) av / 3600000;
0348: long bHourLong = (long) bv / 3600000;
0349: if (aHourLong != bHourLong)
0350: return false;
0351: } else {
0352: if (!MoreMath.nearlyEquals(av, bv, 0.0001))
0353: return false;
0354: }
0355: }
0356: return true;
0357: }
0358:
0359: /** @param task
0360: * @return Value of the FOR Preposition if available, else null
0361: */
0362: public static Object getCustomer(Task task) {
0363: PrepositionalPhrase pp_for = task
0364: .getPrepositionalPhrase(Constants.Preposition.FOR);
0365: Object org;
0366: if (pp_for != null) {
0367: org = pp_for.getIndirectObject();
0368: return org;
0369: }
0370: return null;
0371: }
0372:
0373: public boolean isFlowRate(Task task) {
0374: // select any rate in the rate_schedule, e.g. the first:
0375: Rate r = getRate(task);
0376: return (r instanceof FlowRate);
0377: }
0378:
0379: public Rate getRate(Task task) {
0380: return getRate(task, getStartTime(task));
0381: }
0382:
0383: public Rate getRate(Task task, long time) {
0384: return getRate(task, time, time);
0385: }
0386:
0387: public Rate getRate(Task task, long start, long end) {
0388: // look for time-phased rate schedule
0389: PrepositionalPhrase pp_rate = task
0390: .getPrepositionalPhrase(Constants.Preposition.DEMANDRATE);
0391: if (pp_rate != null) {
0392: Object indObj = pp_rate.getIndirectObject();
0393: if (indObj instanceof Schedule) {
0394: Schedule sched = (Schedule) indObj;
0395: Collection rate_elems = (start == end ? sched
0396: .getScheduleElementsWithTime(start) : sched
0397: .getOverlappingScheduleElements(start, end));
0398: int n = (rate_elems == null ? 0 : rate_elems.size());
0399: if (n > 0) {
0400: if (n == 1 || (start >= end)) {
0401: // return the single matching rate
0402: ObjectScheduleElement ose = (ObjectScheduleElement) rate_elems
0403: .iterator().next();
0404: return (Rate) ose.getObject();
0405: }
0406: // compute the average rate for this timespan
0407: Rate avgRate = null;
0408: long prevStart = start;
0409: Rate firstRate = null;
0410: double totalQty = 0.0;
0411: for (Iterator iter = rate_elems.iterator(); iter
0412: .hasNext();) {
0413: ObjectScheduleElement ose = (ObjectScheduleElement) iter
0414: .next();
0415: long st = Math.max(prevStart, ose
0416: .getStartTime());
0417: long et = Math.min(ose.getEndTime(), end);
0418: long time_spanned = (et - st);
0419: if (time_spanned <= 0) {
0420: continue;
0421: }
0422: prevStart = et;
0423: Rate r = (Rate) ose.getObject();
0424: if (firstRate == null) {
0425: firstRate = r;
0426: }
0427: double dailyRate = getDailyQuantity(r);
0428: if (Double.isNaN(dailyRate)) {
0429: continue;
0430: }
0431: double qty = (dailyRate * ((double) time_spanned / TimeUtils.MSEC_PER_DAY));
0432: totalQty += qty;
0433: }
0434: Duration dur = new Duration((end - start),
0435: Duration.MILLISECONDS);
0436: if (firstRate instanceof FlowRate) {
0437: Volume vol = new Volume(totalQty,
0438: Volume.GALLONS);
0439: avgRate = new FlowRate(vol, dur);
0440: } else if (firstRate instanceof CountRate) {
0441: Count cnt = new Count(totalQty, Count.EACHES);
0442: avgRate = new CountRate(cnt, dur);
0443: } else if (firstRate instanceof MassTransferRate) {
0444: Mass mass = new Mass(totalQty, Mass.SHORT_TONS);
0445: avgRate = new MassTransferRate(mass, dur);
0446: } else {
0447: avgRate = null;
0448: }
0449: return avgRate;
0450: }
0451: }
0452: }
0453: // look for preference
0454: AspectValue best = getPreferenceBest(task,
0455: AlpineAspectType.DEMANDRATE);
0456: if (best != null) {
0457: return ((AspectRate) best).getRateValue();
0458: }
0459: // not a projection?
0460: return null;
0461: }
0462:
0463: public double getDailyQuantity(Task task) {
0464: return getDailyQuantity(task, getEndTime(task));
0465: }
0466:
0467: public double getDailyQuantity(Task task, long time) {
0468: return getDailyQuantity(task, time, time);
0469: }
0470:
0471: public double getDailyQuantity(Task task, long start, long end) {
0472: if (isProjection(task)) {
0473: return getDailyQuantity(getRate(task, start, end));
0474: } else {
0475: return getQuantity(task);
0476: }
0477: }
0478:
0479: public static double getDailyQuantity(Rate r) {
0480: if (r instanceof FlowRate) {
0481: return ((FlowRate) r).getGallonsPerDay();
0482: } else if (r instanceof CountRate) {
0483: return ((CountRate) r).getEachesPerDay();
0484: } else if (r instanceof MassTransferRate) {
0485: return ((MassTransferRate) r).getShortTonsPerDay();
0486: } else {
0487: return Double.NaN;
0488: }
0489: }
0490:
0491: /**
0492: * Given a Scalar, return a double value representing
0493: * Gallons for Volume,
0494: * Eaches for Count and
0495: * Short Tons for Mass.
0496: **/
0497: public double getDouble(Scalar measure) {
0498: double result = Double.NaN;
0499: if (measure instanceof Volume) {
0500: result = ((Volume) measure).getGallons();
0501: } else if (measure instanceof Count) {
0502: result = ((Count) measure).getEaches();
0503: } else if (measure instanceof Mass) {
0504: result = ((Mass) measure).getShortTons();
0505: } else {
0506: logger
0507: .error("InventoryBG.getDouble(), Inventory cannot determine type of measure");
0508: }
0509: return result;
0510: }
0511:
0512: public static double getQuantity(AllocationResult ar) {
0513: return getARAspectValue(ar, AspectType.QUANTITY);
0514: }
0515:
0516: // Hand in the demandRate from a phase of particular allocation result
0517: // and its parent task. This function basically handles the
0518: // contained demand rate result and returns the corresponding
0519: // daily rate. If its fuel (FlowRate) that's already gallons
0520: // per day, otherwise its eaches per millisecond and should be
0521: // multiplied correspondingly.
0522: public double convertResultsToDailyRate(Task task, double demandRate) {
0523: if (isProjection(task) && !isFlowRate(task)) {
0524: return demandRate * TimeUtils.SEC_PER_DAY;
0525: }
0526: return demandRate;
0527: }
0528:
0529: public double getQuantity(Task task, AllocationResult ar) {
0530: if (isProjection(task)) {
0531: // logger.warn("TaskUtils::getting qty from projection!");
0532: return convertResultsToDailyRate(task, getARAspectValue(ar,
0533: AlpineAspectType.DEMANDRATE));
0534: } else {
0535: return getQuantity(ar);
0536: }
0537: }
0538:
0539: public double getQuantity(Task task, AllocationResult ar,
0540: long time_spanned) {
0541: if (isProjection(task)) {
0542: Rate rate = getARAspectRate(ar);
0543: Duration d = Duration
0544: .newMilliseconds((double) time_spanned);
0545: Scalar scalar = (Scalar) rate.computeNumerator(d);
0546: return getDouble(scalar);
0547: } else {
0548: return getQuantity(ar);
0549: }
0550: }
0551:
0552: public double getTotalQuantity(Task task) {
0553: return getTotalQuantity(task, getStartTime(task),
0554: getEndTime(task));
0555: }
0556:
0557: public double getTotalQuantity(Task task, long startTime,
0558: long endTime) {
0559: if (isProjection(task)) {
0560: double time_spanned = endTime - startTime;
0561: if (time_spanned > 0) {
0562: Rate rate = getRate(task, startTime, endTime);
0563: Duration d = Duration
0564: .newMilliseconds((double) time_spanned);
0565: Scalar scalar = (Scalar) rate.computeNumerator(d);
0566: return getDouble(scalar);
0567: } else {
0568: return 0.0d;
0569: }
0570: } else {
0571: return getQuantity(task);
0572: }
0573: }
0574:
0575: public double getTotalQuantity(Task task, double demandRate,
0576: long startTime, long endTime) {
0577: if (isProjection(task)) {
0578: double time_spanned = endTime - startTime;
0579: if (time_spanned > 0) {
0580: double dailyRate = convertResultsToDailyRate(task,
0581: demandRate);
0582: return (dailyRate * (time_spanned / TimeUtils.MSEC_PER_DAY));
0583: } else {
0584: return 0.0d;
0585: }
0586: } else {
0587: return getQuantity(task);
0588: }
0589: }
0590:
0591: public static Rate getARAspectRate(AllocationResult ar) {
0592: if (ar == null)
0593: return null;
0594: AspectValue[] avs = ar.getAspectValueResults();
0595: for (int ii = 0; ii < avs.length; ii++) {
0596: if (avs[ii].getAspectType() == AlpineAspectType.DEMANDRATE) {
0597: return ((AspectRate) avs[ii]).getRateValue();
0598: }
0599: }
0600: return null;
0601: }
0602:
0603: public TimeUtils getTimeUtils() {
0604: return utilProvider.getTimeUtils();
0605: }
0606:
0607: public static Collection getUnallocatedTasks(Collection tasks,
0608: Verb verb) {
0609: Iterator taskIt = tasks.iterator();
0610: ArrayList list = new ArrayList();
0611: Task task;
0612: while (taskIt.hasNext()) {
0613: task = (Task) taskIt.next();
0614: if ((task.getPlanElement() == null)
0615: && (task.getVerb().equals(verb))) {
0616: list.add(task);
0617: }
0618: }
0619: return list;
0620: }
0621:
0622: public Schedule newObjectSchedule(Collection tasks) {
0623: Vector os_elements = new Vector();
0624: ScheduleImpl s = new ScheduleImpl();
0625: s.setScheduleElementType(PlanScheduleElementType.OBJECT);
0626: s.setScheduleType(ScheduleType.OTHER);
0627:
0628: for (Iterator iterator = tasks.iterator(); iterator.hasNext();) {
0629: Task task = (Task) iterator.next();
0630: try {
0631: os_elements.add(new ObjectScheduleElement(
0632: getStartTime(task), getEndTime(task), task));
0633: } catch (IllegalArgumentException iae) {
0634: if (logger.isErrorEnabled()) {
0635: logger
0636: .error("newObjectSchedule failed, start and end time is "
0637: + new Date(getStartTime(task))
0638: + " for task "
0639: + task
0640: + "\n"
0641: + iae.getMessage());
0642: }
0643: }
0644: }
0645: s.setScheduleElements(os_elements.elements());
0646: return s;
0647: }
0648:
0649: /** Change the prev task's preferences to the new tasks preferences if they are different.
0650: * @param prev_task previously published task.
0651: * @param new_task already defined to have the same taskKey as task a.
0652: * @return null if the two tasks are the same,
0653: * or returns task a modified for a publishChange.
0654: */
0655: public Task changeTask(Task prev_task, Task new_task) {
0656: // Checks for changed preferences.
0657: if (prev_task == new_task) {
0658: //return new_task;
0659: return null;
0660: }
0661: if (!comparePreferences(new_task, prev_task)) {
0662: synchronized (new_task) {
0663: Enumeration ntPrefs = new_task.getPreferences();
0664: ((NewTask) prev_task).setPreferences(ntPrefs);
0665: } // synch
0666: return prev_task;
0667: }
0668: return null;
0669: }
0670:
0671: // Time Preference Utils
0672:
0673: /** Create a Time Preference for a Refill Task or a Demand Task
0674: * Use a Piecewise Linear Scoring Function.
0675: * For details see the IM SDD.
0676: * @param bestDay The time you want this preference to represent
0677: * @param early The earliest time this preference can have
0678: * @param end The last time this preference can have (such as Oplan end time)
0679: * @param aspectType The AspectType of the preference- should be start_time or end_time
0680: * @param clusterId Agent cluster ID
0681: * @param planningFactory Planning factory from plugin
0682: * @param thePG InventoryPG for the item maintained by a refill task
0683: * @return Preference The new Time Preference
0684: **/
0685: public Preference createTimePreference(long bestDay, long early,
0686: long end, int aspectType, MessageAddress clusterId,
0687: PlanningFactory planningFactory, LogisticsInventoryPG thePG) {
0688: double daysBetween;
0689: long late;
0690: if (thePG != null) {
0691: daysBetween = ((end - bestDay) / thePG.getBucketMillis()) - 1;
0692: late = bestDay + thePG.getBucketMillis();
0693: } else {
0694: late = getTimeUtils().addNDays(bestDay, 1);
0695: daysBetween = ((end - bestDay) / 86400000);
0696: }
0697:
0698: // Negative value here is bad. Note that end==bestDay is OK. This case
0699: // is handled below, where we skip adding the end AspectScorePoint
0700: if (daysBetween < 0.0) {
0701: if (logger.isWarnEnabled())
0702: logger
0703: .warn(clusterId
0704: + ".createTimePref had OplanEnd < bestDay! OplanEnd: "
0705: + new Date(end) + ". Best: "
0706: + new Date(bestDay));
0707: }
0708:
0709: //Use .0033 as a slope for now
0710: double late_score = .0033 * daysBetween;
0711: // define alpha .25
0712: double alpha = .25;
0713:
0714: Vector points = new Vector();
0715: AspectScorePoint earliest = new AspectScorePoint(AspectValue
0716: .newAspectValue(aspectType, early), alpha);
0717: AspectScorePoint best = new AspectScorePoint(AspectValue
0718: .newAspectValue(aspectType, bestDay), 0.0);
0719: AspectScorePoint first_late = new AspectScorePoint(AspectValue
0720: .newAspectValue(aspectType, late), alpha);
0721: AspectScorePoint latest = new AspectScorePoint(AspectValue
0722: .newAspectValue(aspectType, end), (alpha + late_score));
0723:
0724: // Don't add the early point if best is same time or earlier
0725: if (bestDay > early) {
0726: points.addElement(earliest);
0727: } else if (bestDay == early) {
0728: if (logger.isInfoEnabled()) {
0729: logger
0730: .info(clusterId
0731: + ".createTimePref skipping early point: best == early (OplanStart)! bestDay: "
0732: + new Date(bestDay) + ". AspectType: "
0733: + aspectType);
0734: }
0735: } else {
0736: if (logger.isWarnEnabled()) {
0737: logger
0738: .warn(clusterId
0739: + ".createTimePref skipping early point: best < early (OplanStart)! bestDay: "
0740: + new Date(bestDay) + ", early: "
0741: + new Date(early) + ". AspectType: "
0742: + aspectType);
0743: }
0744: }
0745:
0746: points.addElement(best);
0747: points.addElement(first_late);
0748:
0749: // Only add the "late" point if it's value is later than first_late
0750: if (end > late) {
0751: points.addElement(latest);
0752: } else if (logger.isInfoEnabled()) {
0753: // Note that this case is equivalent to any daysBetween value <= 1.0,
0754: // including the case above where daysBetween < 0.0
0755:
0756: // If bestDay == end, this is almost certainly an end Preference, where the preference
0757: // is OplanEnd. So best+1 is necessarily > end
0758: // check aspectType == AspectType.END_TIME
0759: logger
0760: .info(clusterId
0761: + ".createTimePref skipping end point: end <= late! end: "
0762: + new Date(end)
0763: + ", late: "
0764: + new Date(late)
0765: + ((bestDay == end && aspectType == AspectType.END_TIME) ? ". A Task EndPref where best==OplanEnd."
0766: : ". AspectType: " + aspectType));
0767: }
0768:
0769: ScoringFunction timeSF = ScoringFunction
0770: .createPiecewiseLinearScoringFunction(points.elements());
0771: return planningFactory.newPreference(aspectType, timeSF);
0772: }
0773:
0774: /** copies a Supply task from another to split it**/
0775: public NewTask copySupplyTask(Task origTask, long start, long end,
0776: LogisticsInventoryPG invPG, InventoryManager inventoryPlugin) {
0777:
0778: NewTask task = inventoryPlugin.getPlanningFactory().newTask();
0779: task.setVerb(origTask.getVerb());
0780: task.setDirectObject(origTask.getDirectObject());
0781: task.setParentTaskUID(origTask.getParentTaskUID());
0782: task.setContext(origTask.getContext());
0783: task.setPlan(origTask.getPlan());
0784: Enumeration pp = origTask.getPrepositionalPhrases();
0785: Vector ppv = new Vector();
0786: while (pp.hasMoreElements()) {
0787: ppv.addElement(pp.nextElement());
0788: }
0789: NewPrepositionalPhrase newPP = inventoryPlugin
0790: .getPlanningFactory().newPrepositionalPhrase();
0791: newPP.setPreposition("SplitTask");
0792: ppv.add(newPP);
0793: task.setPrepositionalPhrases(ppv.elements());
0794: task.setPriority(origTask.getPriority());
0795: task.setSource(inventoryPlugin.getClusterId());
0796: changeDatePrefs(task, start, end, inventoryPlugin, invPG);
0797: // TODO: is this ok to to just add these prefs to the a vector?
0798: // TODO: the changeDatePrefs clones the scoring function
0799: Enumeration origPrefs = task.getPreferences();
0800: Vector newPrefs = new Vector();
0801: Preference currentPref;
0802: while (origPrefs.hasMoreElements()) {
0803: currentPref = (Preference) origPrefs.nextElement();
0804: newPrefs.add(currentPref);
0805: }
0806: // old pref-style rate w/o rate_schedule
0807: AspectValue rate_best = getPreferenceBest(task,
0808: AlpineAspectType.DEMANDRATE);
0809: if (rate_best != null) {
0810: Rate rate = ((AspectRate) rate_best).getRateValue();
0811: if (rate != null) {
0812: newPrefs.addElement(createDemandRatePreference(
0813: inventoryPlugin.getPlanningFactory(), rate));
0814: }
0815: }
0816: // start and end from schedule element
0817:
0818: task.setPreferences(newPrefs.elements());
0819: return task;
0820: }
0821:
0822: public void changeDatePrefs(NewTask task, long start, long end,
0823: InventoryManager inventoryPlugin, LogisticsInventoryPG invPG) {
0824: Preference startPref = createTimePreference(start,
0825: inventoryPlugin.getOPlanArrivalInTheaterTime(),
0826: inventoryPlugin.getOPlanEndTime(),
0827: AspectType.START_TIME, inventoryPlugin.getClusterId(),
0828: inventoryPlugin.getPlanningFactory(), invPG);
0829: Preference endPref = createTimePreference(end, inventoryPlugin
0830: .getOPlanArrivalInTheaterTime(), inventoryPlugin
0831: .getOPlanEndTime(), AspectType.END_TIME,
0832: inventoryPlugin.getClusterId(), inventoryPlugin
0833: .getPlanningFactory(), invPG);
0834:
0835: Enumeration origPrefs = task.getPreferences();
0836: Preference currentPref, copiedPref;
0837: Vector newPrefs = new Vector();
0838: while (origPrefs.hasMoreElements()) {
0839: currentPref = (Preference) origPrefs.nextElement();
0840: if (!(currentPref.getAspectType() == AspectType.START_TIME || currentPref
0841: .getAspectType() == AspectType.END_TIME)) {
0842: copiedPref = inventoryPlugin.getPlanningFactory()
0843: .newPreference(
0844: currentPref.getAspectType(),
0845: (ScoringFunction) currentPref
0846: .getScoringFunction().clone());
0847: newPrefs.add(copiedPref);
0848: }
0849: }
0850: newPrefs.add(startPref);
0851: newPrefs.add(endPref);
0852: synchronized (task) {
0853: task.setPreferences(newPrefs.elements());
0854: }
0855: }
0856:
0857: public Collection splitProjection(Task task, List howToSplit,
0858: InventoryManager invPlugin) {
0859: ArrayList newSplitTasks = new ArrayList();
0860: Asset asset = task.getDirectObject();
0861: Inventory inventory = invPlugin.findOrMakeInventory(asset);
0862: LogisticsInventoryPG invPG = (LogisticsInventoryPG) inventory
0863: .searchForPropertyGroup(LogisticsInventoryPG.class);
0864: //remove the orig task from the BG - we'll re-add after the split
0865: invPG.removeRefillProjection(task);
0866: Iterator tsIt = howToSplit.iterator();
0867: TimeSpan first = (TimeSpan) tsIt.next();
0868: //first element from howToSplit is the one to reuse the allocation
0869: long startOfSplit = first.getStartTime();
0870: long endOfSplit = first.getEndTime();
0871: TimeSpan second = (TimeSpan) tsIt.next();
0872: long startOfSecondSplit = second.getStartTime();
0873: long endOfSecondSplit = second.getEndTime();
0874: if (task.getPlanElement() != null) {
0875: changeDatePrefs((NewTask) task, startOfSplit, endOfSplit,
0876: invPlugin, invPG);
0877: invPG.addRefillProjection(task);
0878: invPlugin.publishChange(task);
0879: //add the changed list to newSplitTasks to be sent to the ExtAlloc so it can update its estimated result
0880: newSplitTasks.add(task);
0881: newSplitTasks.add(makeNewSplit(task, startOfSecondSplit,
0882: endOfSecondSplit, invPG, invPlugin, inventory));
0883: } else {
0884: newSplitTasks.add(makeNewSplit(task, startOfSplit,
0885: endOfSplit, invPG, invPlugin, inventory));
0886: newSplitTasks.add(makeNewSplit(task, startOfSecondSplit,
0887: endOfSecondSplit, invPG, invPlugin, inventory));
0888: }
0889: return newSplitTasks;
0890: }
0891:
0892: private Task makeNewSplit(Task task, long startOfSplit,
0893: long endOfSplit, LogisticsInventoryPG invPG,
0894: InventoryManager invPlugin, Inventory inventory) {
0895: Task newSplitTask = copySupplyTask(task, startOfSplit,
0896: endOfSplit, invPG, invPlugin);
0897: if (logger.isDebugEnabled()) {
0898: logger.debug("Made a new split task with dates of: "
0899: + new Date(startOfSplit) + "..."
0900: + new Date(endOfSplit));
0901: }
0902: invPG.addRefillProjection(newSplitTask);
0903: //hookup newSplitTask
0904: invPlugin.publishRefillTask(newSplitTask, inventory);
0905: return newSplitTask;
0906: }
0907:
0908: public long getReportedStartTime(Task task) {
0909: PlanElement pe = task.getPlanElement();
0910: // If the task has no plan element then return the StartTime Pref
0911: if (pe == null) {
0912: return getStartTime(task);
0913: }
0914: AllocationResult ar = pe.getReportedResult();
0915: if (ar == null) {
0916: ar = pe.getEstimatedResult();
0917: } else if (!ar.isSuccess()) {
0918: return getStartTime(task);
0919: }
0920: return (long) getStartTime(ar);
0921: }
0922:
0923: public long getReportedEndTime(Task task) {
0924: PlanElement pe = task.getPlanElement();
0925: // If the task has no plan element then return the EndTime Pref
0926: if (pe == null) {
0927: return getEndTime(task);
0928: }
0929: AllocationResult ar = pe.getReportedResult();
0930: if (ar == null) {
0931: ar = pe.getEstimatedResult();
0932: }
0933: // make sure that we got atleast a valid reported OR estimated allocation result
0934: if (ar != null) {
0935: if (!ar.isSuccess()) {
0936: getEndTime(task); // bug?
0937: }
0938: double resultTime;
0939: // make sure END_TIME is specified - otherwise use START_TIME
0940: // UniversalAllocator plugin only gives start times
0941: if (ar.isDefined(AspectType.END_TIME)) {
0942: resultTime = ar.getValue(AspectType.END_TIME);
0943: } else {
0944: resultTime = ar.getValue(AspectType.START_TIME);
0945: }
0946: return (long) resultTime;
0947: } else {
0948: // if for some reason we have a pe but no ar return the pref
0949: return getEndTime(task);
0950: }
0951: }
0952:
0953: public double calculateDemand(Task t, long minStart, long maxEnd) {
0954: if (isProjection(t)) {
0955: long start = Math.max(getReportedStartTime(t), minStart);
0956: long end = Math.min(getReportedEndTime(t), maxEnd);
0957: return getTotalQuantity(t, start, end);
0958: }
0959: long taskEnd = getEndTime(t);
0960: if ((taskEnd < minStart) || (taskEnd > maxEnd)) {
0961: return 0.0d;
0962: }
0963: return getQuantity(t);
0964: }
0965:
0966: public double calculateFilled(Task t, long minStart, long maxEnd) {
0967: PlanElement pe = t.getPlanElement();
0968: AllocationResult ar = null;
0969: if (pe != null) {
0970: ar = pe.getReportedResult();
0971: if (ar == null) {
0972: ar = pe.getEstimatedResult();
0973: }
0974: }
0975: if (isProjection(t)) {
0976: long start = Math.max(getReportedStartTime(t), minStart);
0977: long end = Math.min(getReportedEndTime(t), maxEnd);
0978: if (ar != null && !ar.isSuccess()) {
0979: return 0.0d;
0980: }
0981: double taskQty = getTotalQuantity(t, start, end);
0982: if (ar == null || !ar.isPhased()) {
0983: return taskQty;
0984: }
0985:
0986: int[] ats = ar.getAspectTypes();
0987: int rateInd = LogisticsInventoryFormatter.getIndexForType(
0988: ats, AlpineAspectType.DEMANDRATE);
0989: int startInd = LogisticsInventoryFormatter.getIndexForType(
0990: ats, AspectType.START_TIME);
0991: int endInd = LogisticsInventoryFormatter.getIndexForType(
0992: ats, AspectType.END_TIME);
0993:
0994: double totalQty = 0;
0995: for (Enumeration phasedResults = ar.getPhasedResults(); phasedResults
0996: .hasMoreElements();) {
0997: double[] results = (double[]) phasedResults
0998: .nextElement();
0999: double phaseRate = results[rateInd];
1000: double phaseStart = results[startInd];
1001: double phaseEnd = results[endInd];
1002: start = Math.max((long) phaseStart, minStart);
1003: end = Math.min((long) phaseEnd, maxEnd);
1004: totalQty += getTotalQuantity(t, phaseRate, start, end);
1005: }
1006: return totalQty;
1007: }
1008: long taskEnd = getEndTime(t);
1009: if ((taskEnd < minStart) || (taskEnd > maxEnd)) {
1010: return 0.0d;
1011: }
1012:
1013: if (ar == null) {
1014: return getQuantity(t);
1015: }
1016: if (!ar.isPhased()) {
1017: if (ar.isSuccess()) {
1018: double arEnd = getEndTime(ar);
1019: double taskQty = getQuantity(t, ar);
1020: if ((arEnd >= minStart) && (arEnd <= maxEnd)) {
1021: return taskQty;
1022: }
1023: }
1024: return 0.0d;
1025: }
1026:
1027: int[] ats = ar.getAspectTypes();
1028: int qtyInd = LogisticsInventoryFormatter.getIndexForType(ats,
1029: AspectType.QUANTITY);
1030: int endInd = LogisticsInventoryFormatter.getIndexForType(ats,
1031: AspectType.END_TIME);
1032:
1033: double totalQty = 0;
1034: for (Enumeration phasedResults = ar.getPhasedResults(); phasedResults
1035: .hasMoreElements();) {
1036: double[] results = (double[]) phasedResults.nextElement();
1037: double phaseQty = results[qtyInd];
1038: double phaseEnd = results[endInd];
1039: if (phaseEnd <= maxEnd) {
1040: totalQty += phaseQty;
1041: }
1042: }
1043: return totalQty;
1044: }
1045:
1046: public boolean isProjFailure(Task t, long minStart,
1047: boolean includeTemps) {
1048: PlanElement pe = t.getPlanElement();
1049: if (pe == null) {
1050: return false;
1051: }
1052: AllocationResult ar = pe.getReportedResult();
1053: if (ar == null) {
1054: ar = pe.getEstimatedResult();
1055: }
1056: if (ar == null) {
1057: return false;
1058: }
1059: if (ar.isSuccess() && (!includeTemps || !ar.isPhased())) {
1060: return false;
1061: }
1062: int[] ats = ar.getAspectTypes();
1063: int rateInd = LogisticsInventoryFormatter.getIndexForType(ats,
1064: AlpineAspectType.DEMANDRATE);
1065: if (rateInd < 0) {
1066: // no rate response, assume success?
1067: return false;
1068: }
1069:
1070: long start = Math.max(getReportedStartTime(t), minStart);
1071: long end = getReportedEndTime(t);
1072: double taskTotal = getTotalQuantity(t, start, end);
1073: if ((!ar.isSuccess()) && (taskTotal > 0)) {
1074: return true;
1075: }
1076: if (!includeTemps || !ar.isPhased()) {
1077: return false;
1078: }
1079:
1080: int startInd = LogisticsInventoryFormatter.getIndexForType(ats,
1081: AspectType.START_TIME);
1082: int endInd = LogisticsInventoryFormatter.getIndexForType(ats,
1083: AspectType.END_TIME);
1084:
1085: double totalQty = 0;
1086: long maxPhaseEnd = 0;
1087:
1088: for (Enumeration phasedResults = ar.getPhasedResults(); phasedResults
1089: .hasMoreElements();) {
1090: double[] results = (double[]) phasedResults.nextElement();
1091: double phaseRate = results[rateInd];
1092: double phaseStart = results[startInd];
1093: double phaseEnd = results[endInd];
1094: long arStart = Math.max((long) phaseStart, start);
1095: //long arEnd = (long) Math.min(end, (long) phaseEnd);
1096: totalQty += getTotalQuantity(t, phaseRate, arStart,
1097: (long) phaseEnd);
1098: maxPhaseEnd = Math.max((long) phaseEnd, maxPhaseEnd);
1099: }
1100: // When doing all this addition of double rates some precision is lost so we
1101: // need a small offset to avoid "false shortfalls".
1102: double offset = 0.001d;
1103: if (taskTotal > (totalQty + offset)) {
1104: return true;
1105: } else if (maxPhaseEnd > getEndTime(t)) {
1106: return true;
1107: }
1108: return false;
1109: }
1110:
1111: public boolean isActualShortfall(Task t, boolean includeTemps) {
1112: PlanElement pe = t.getPlanElement();
1113: if (pe == null) {
1114: return false;
1115: }
1116: AllocationResult ar = pe.getReportedResult();
1117: if (ar == null) {
1118: ar = pe.getEstimatedResult();
1119: }
1120: if ((ar == null) || isProjection(t)) {
1121: return false;
1122: }
1123: if (!ar.isSuccess()) {
1124: return true;
1125: }
1126: double unfilled = 0;
1127: double arEndTime = 0;
1128: double taskEndTime = getEndTime(t);
1129:
1130: if (!ar.isPhased()) {
1131: unfilled = getQuantity(t) - getQuantity(ar);
1132: arEndTime = getEndTime(ar);
1133: } else {
1134: int[] ats = ar.getAspectTypes();
1135: int qtyInd = -1;
1136: int endInd = -1;
1137: double totalQty = 0;
1138: qtyInd = LogisticsInventoryFormatter.getIndexForType(ats,
1139: AspectType.QUANTITY);
1140: endInd = LogisticsInventoryFormatter.getIndexForType(ats,
1141: AspectType.END_TIME);
1142: Enumeration phasedResults = ar.getPhasedResults();
1143: while (phasedResults.hasMoreElements()) {
1144: double[] results = (double[]) phasedResults
1145: .nextElement();
1146: if (qtyInd != -1) {
1147: totalQty += results[qtyInd];
1148: } else {
1149: totalQty = getQuantity(t);
1150: }
1151: double endTime = (endInd == -1 ? taskEndTime
1152: : results[endInd]);
1153: arEndTime = Math.max(arEndTime, endTime);
1154: }
1155: unfilled = getQuantity(t) - totalQty;
1156: }
1157: double offset = 0.001d;
1158: if ((unfilled - offset) > 0) {
1159: return true;
1160: } else if (includeTemps && (arEndTime > taskEndTime)) {
1161: return true;
1162: }
1163: return false;
1164: }
1165:
1166: public double getGrantedQuantity(Task t) {
1167: PlanElement pe = t.getPlanElement();
1168: if (pe == null) {
1169: return 0;
1170: }
1171: AllocationResult ar = pe.getReportedResult();
1172: if (ar == null) {
1173: ar = pe.getEstimatedResult();
1174: }
1175: double taskQty;
1176: if (ar == null) {
1177: taskQty = getTotalQuantity(t);
1178: } else if (isProjection(t)) {
1179: if (ar.isSuccess()) {
1180: taskQty = 0;
1181: } else {
1182: taskQty = getTotalQuantity(t);
1183: }
1184: } else {
1185: taskQty = getQuantity(ar);
1186: }
1187: return taskQty;
1188: }
1189:
1190: public double getActualDemand(Task task, long startTime,
1191: long endTime, long minStart) {
1192: if (!isProjection(task)) {
1193: return getQuantity(task);
1194: }
1195: long start = (long) getPreferenceBestValue(task,
1196: AspectType.START_TIME);
1197: long end = (long) getPreferenceBestValue(task,
1198: AspectType.END_TIME);
1199: start = Math.max(start, minStart);
1200: if ((start >= end) || (start >= endTime - 1)) {
1201: // task is not in this interval
1202: return 0.0;
1203: }
1204: // get the time spanned (if any) for this task within the specified bucket
1205: long interval_start = Math.max(start, startTime);
1206: long interval_end = Math.min(end, endTime);
1207: long time_spanned = interval_end - interval_start;
1208: // add quantity for overlapping timespan
1209: Rate rate = getRate(task, interval_start, interval_end);
1210: try {
1211: Scalar scalar = (Scalar) rate.computeNumerator(Duration
1212: .newMilliseconds((double) time_spanned));
1213: return getDouble(scalar);
1214: } catch (Exception e) {
1215: if (logger.isErrorEnabled()) {
1216: logger.error(taskDesc(task) + " Start: "
1217: + (new Date(start)) + " time_spanned: "
1218: + time_spanned);
1219: }
1220: return 0.0;
1221: }
1222: }
1223:
1224: public Collection getDailyQuantities(Task task) {
1225: if (task == null) {
1226: return null;
1227: }
1228:
1229: long startTime = -1;
1230: if (getPreferenceBest(task, AspectType.START_TIME) != null) {
1231: startTime = getStartTime(task);
1232: }
1233:
1234: long endTime = getEndTime(task);
1235: if (startTime == -1) {
1236: startTime = endTime - 1;
1237: }
1238:
1239: double dailyRate = 0.0d;
1240:
1241: if (!isProjection(task)) {
1242: dailyRate = getQuantity(task);
1243: } else {
1244: Rate rate = null;
1245:
1246: PrepositionalPhrase pp_rate = task
1247: .getPrepositionalPhrase(Constants.Preposition.DEMANDRATE);
1248: if (pp_rate != null) {
1249: Object indObj = pp_rate.getIndirectObject();
1250: if (indObj instanceof Schedule) {
1251: Schedule sched = (Schedule) indObj;
1252: Collection rate_elems = sched
1253: .getOverlappingScheduleElements(startTime,
1254: endTime);
1255: int n = (rate_elems == null ? 0 : rate_elems.size());
1256: if (n == 1) {
1257: ObjectScheduleElement ose = (ObjectScheduleElement) rate_elems
1258: .iterator().next();
1259: rate = (Rate) ose.getObject();
1260: } else if (n > 1) {
1261: // return a schedule of daily rates
1262: List ret = new ArrayList(n);
1263: for (Iterator iter = rate_elems.iterator(); iter
1264: .hasNext();) {
1265: ObjectScheduleElement ose = (ObjectScheduleElement) iter
1266: .next();
1267: Rate r = (Rate) ose.getObject();
1268: double d = getDailyQuantity(r);
1269: ScheduleElement se = new QuantityScheduleElementImpl(
1270: ose.getStartTime(), ose
1271: .getEndTime(), d);
1272: ret.add(se);
1273: }
1274: return ret;
1275: }
1276: }
1277: }
1278:
1279: if (rate == null) {
1280: AspectValue best = getPreferenceBest(task,
1281: AlpineAspectType.DEMANDRATE);
1282: if (best != null) {
1283: rate = ((AspectRate) best).getRateValue();
1284: }
1285: }
1286:
1287: if (rate != null) {
1288: dailyRate = getDailyQuantity(rate);
1289: }
1290: }
1291:
1292: ScheduleElement se = new QuantityScheduleElementImpl(startTime,
1293: endTime, dailyRate);
1294: return Collections.singleton(se);
1295: }
1296:
1297: public Collection getReportedDailyQuantities(Task task) {
1298: if (task == null) {
1299: return null;
1300: }
1301: PlanElement pe = task.getPlanElement();
1302: if (pe == null) {
1303: return null;
1304: }
1305: AllocationResult ar = pe.getReportedResult();
1306: if (ar == null) {
1307: ar = pe.getEstimatedResult();
1308: }
1309: if (ar == null) {
1310: return null;
1311: }
1312: return getReportedDailyQuantities(task, ar);
1313: }
1314:
1315: // This function is based heavily off of logAllocationResult in the
1316: // LogisticsInventoryFormatter
1317: public Collection getReportedDailyQuantities(Task task,
1318: AllocationResult ar) {
1319: if (!ar.isSuccess()) {
1320: // logger.warn("Allocation Result was failure. Not returning.");
1321: return null;
1322: }
1323:
1324: if (!ar.isPhased()) {
1325: long endTime = (long) getEndTime(ar);
1326: long startTime = 0;
1327:
1328: if (isProjection(task)) {
1329: startTime = (long) getStartTime(ar);
1330: if (startTime == endTime) {
1331: startTime = endTime - 1;
1332: }
1333: } else {
1334: // if supply or withdraw task then we don't have a start time
1335: startTime = endTime - 1;
1336: }
1337: if (startTime == endTime) {
1338: startTime = endTime - 1;
1339: }
1340:
1341: double quantity = 0;
1342: try {
1343: quantity = getQuantity(task, ar);
1344: } catch (RuntimeException re) {
1345: throw re;
1346: }
1347:
1348: return Collections
1349: .singleton(new QuantityScheduleElementImpl(
1350: startTime, endTime, quantity));
1351: }
1352:
1353: Collection returnQSEs = new HashSet();
1354:
1355: int[] ats = ar.getAspectTypes();
1356: int qtyInd = -1;
1357: if (isProjection(task)) {
1358: qtyInd = LogisticsInventoryFormatter.getIndexForType(ats,
1359: AlpineAspectType.DEMANDRATE);
1360: } else {
1361: qtyInd = LogisticsInventoryFormatter.getIndexForType(ats,
1362: AspectType.QUANTITY);
1363: }
1364: int startInd = LogisticsInventoryFormatter.getIndexForType(ats,
1365: AspectType.START_TIME);
1366: int endInd = LogisticsInventoryFormatter.getIndexForType(ats,
1367: AspectType.END_TIME);
1368: Enumeration phasedResults = ar.getPhasedResults();
1369: while (phasedResults.hasMoreElements()) {
1370: double[] results = (double[]) phasedResults.nextElement();
1371: long startTime = 0;
1372: if (startInd != -1) {
1373: startTime = (long) results[startInd];
1374: }
1375: long endTime = 0;
1376: if (endInd == -1) {
1377: /** MWD The following line of code which replaces the
1378: * allocation result end time with the task end time
1379: * is only due to a current error in the
1380: * UniversalAllocator. The UA is only setting
1381: * the start time in the allocation result. There
1382: * is a bug in and when the UA is fixed this line
1383: * of code should be removed. If there is no end time
1384: * in the allocation result, none should be appended.
1385: * GUI needs the end
1386: * times for the rates.
1387: */
1388: endTime = getEndTime(task);
1389: } else {
1390: endTime = (long) results[endInd];
1391: }
1392: if ((qtyInd < 0) || (qtyInd >= results.length)) {
1393: // logger.error("qtyInd is " + qtyInd + " - No Qty in this phase of allocation results:");
1394: continue;
1395: }
1396: double dailyRate = convertResultsToDailyRate(task,
1397: results[qtyInd]);
1398: double quantity = dailyRate;
1399:
1400: if (startTime == 0) {
1401: startTime = endTime - 1;
1402: }
1403: if (startTime > endTime) {
1404: // logger.error("Error - start time can't be later than end time");
1405: continue;
1406: }
1407: // logger.warn("2nd Method adding (" + startTime + ", " + endTime + ", " + quantity + ")");
1408: returnQSEs.add(new QuantityScheduleElementImpl(startTime,
1409: endTime, quantity));
1410: }
1411: // logger.warn("AR Was Null. Result of " + returnQSEs.size() + " is alternate method");
1412: return returnQSEs;
1413: }
1414: }
|