001: /*
002: * <copyright>
003: *
004: * Copyright 1997-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.logistics.plugin.inventory;
028:
029: import org.cougaar.planning.ldm.asset.Asset;
030: import org.cougaar.planning.ldm.asset.TypeIdentificationPG;
031: import org.cougaar.glm.ldm.asset.Inventory;
032: import org.cougaar.glm.ldm.asset.Organization;
033: import org.cougaar.logistics.ldm.Constants;
034: import org.cougaar.glm.ldm.plan.GeolocLocation;
035: import org.cougaar.planning.ldm.plan.AspectScorePoint;
036: import org.cougaar.planning.ldm.plan.AspectType;
037: import org.cougaar.planning.ldm.plan.AspectValue;
038: import org.cougaar.planning.ldm.plan.NewTask;
039: import org.cougaar.planning.ldm.plan.Preference;
040: import org.cougaar.planning.ldm.plan.NewPrepositionalPhrase;
041: import org.cougaar.planning.ldm.plan.PrepositionalPhrase;
042: import org.cougaar.planning.ldm.plan.ScoringFunction;
043: import org.cougaar.planning.ldm.plan.Task;
044:
045: import java.util.ArrayList;
046: import java.util.Collection;
047: import java.util.Date;
048: import java.util.Enumeration;
049: import java.util.Iterator;
050: import java.util.Vector;
051:
052: import java.text.DecimalFormat;
053: import java.math.BigDecimal;
054:
055: /** The Refill Generator Module is responsible for generating new
056: * refill tasks as needed when new demand is received. This Refill
057: * Generator uses a total replan algorithm which ignores all previously
058: * generated refill tasks (that are not yet committed) and replans by
059: * creating new refills based on the new due out totals and the
060: * inventory levels. The Comparator module will decide whether to
061: * rescind all previous refills and publish all new refills generated
062: * by this module or whether to compare and merge the 'old' and
063: * 'new' refill tasks.
064: * Called by the Inventory Plugin when there is new demand.
065: * Uses the InventoryBG module for inventory bin calculations
066: * Generates Refill tasks which are passed to the InventoryPlugin
067: * to be added to the MaintainInventory workflow and published.
068: **/
069:
070: public class RefillGenerator extends InventoryLevelGenerator implements
071: RefillGeneratorModule {
072:
073: private transient Organization myOrg = null;
074: private transient String myOrgName = null;
075: private transient GeolocLocation homeGeoloc = null;
076: private transient DecimalFormat myDecimalFormatter = null;
077: ClassicRefillGeneratorInventoryManager classicInventoryManager;
078:
079: //private transient String debugItem;
080:
081: /** Need to pass in the IM Plugin for now to get services
082: * and util classes.
083: **/
084: public RefillGenerator(InventoryManager imPlugin) {
085: super (imPlugin);
086: if (imPlugin instanceof ClassicRefillGeneratorInventoryManager) {
087: this .classicInventoryManager = (ClassicRefillGeneratorInventoryManager) imPlugin;
088: }
089: }
090:
091: /** Called by the Inventory Plugin to re-calculate refills when an demand has changed
092: * for an inventory. This method creates Refill Tasks and publishes them through the
093: * Inventory Plugin.
094: * @param touchedInventories The collection of changed Inventories.
095: * @param myComparator The RefillComparator to use.
096: **/
097: public void calculateRefills(Collection touchedInventories,
098: ComparatorModule myComparator) {
099: ArrayList newRefills = new ArrayList();
100: ArrayList oldRefills = new ArrayList();
101: int orderShipTime = classicInventoryManager.getOrderShipTime();
102: int maxLeadTime = classicInventoryManager.getMaxLeadTime();
103:
104: //Should we push now to the end of today? For now we WILL NOT.
105: //long today = getTimeUtils().
106: // pushToEndOfDay(inventoryPlugin.getCurrentTimeMillis());
107: long today = inventoryPlugin.getCurrentTimeMillis();
108: //start time (k) is today plus OST.
109: //long start = getTimeUtils().addNDays(today, orderShipTime);
110: long start;
111:
112: Iterator tiIter = touchedInventories.iterator();
113: while (tiIter.hasNext()) {
114: // clear the refill lists from the last inventory
115: oldRefills.clear();
116: newRefills.clear();
117: Inventory anInventory = (Inventory) tiIter.next();
118:
119: //debugItem = anInventory.getItemIdentificationPG().getItemIdentification();
120:
121: LogisticsInventoryPG thePG = (LogisticsInventoryPG) anInventory
122: .searchForPropertyGroup(LogisticsInventoryPG.class);
123:
124: start = today + (orderShipTime * thePG.getBucketMillis());
125:
126: // DEBUG
127: // String myOrgName = inventoryPlugin.getOrgName();
128: String myItemId = anInventory.getItemIdentificationPG()
129: .getItemIdentification();
130:
131: //Only magically recalculate the initial inventory level
132: //(the prepo) up to when the prepo arrives.
133: if (today <= classicInventoryManager.getPrepoArrivalTime()) {
134: thePG.recalculateInitialLevel();
135: }
136:
137: // only process Level 6 inventories
138: if (!thePG.getIsLevel2()) {
139: //clear the refills
140: oldRefills.addAll(thePG
141: .clearRefillTasks(new Date(today)));
142:
143: int startBucket = thePG.convertTimeToBucket(start,
144: false);
145: // refill time is start + 1 bucket (k+1)
146: int refillBucket = nextLegalRefillBucket(thePG,
147: startBucket);
148: // max lead day is today + maxLeadTime
149: //int maxLeadBucket = thePG.convertTimeToBucket(getTimeUtils().
150: //addNDays(today, maxLeadTime), false);
151: // Do not count partial buckets hear because when planning we want the start of the
152: // bucket. This prevents us from removing refills that because of OST, cannot be
153: // replaced leaving holes in supply.
154: int maxLeadBucket = thePG.convertTimeToBucket(today,
155: false)
156: + maxLeadTime;
157: int firstLegalRefillBucket = thePG.convertTimeToBucket(
158: classicInventoryManager.getRefillStartTime(),
159: false)
160: + orderShipTime;
161: boolean clearTargetLevels = true;
162: int clearTargetBucket = refillBucket;
163: double prevTarget = 0;
164:
165: //calculate inventory levels for time ZERO through start (today + OST)
166: //Time period which refillGenerator should not touch
167: calculateInventoryLevelsForRG(0, startBucket, thePG);
168:
169: //System.out.println("############## ITEM "+debugItem);
170:
171: // create the refills
172: // RJB
173: int lastRefillBucket = refillBucket;
174:
175: while (refillBucket <= maxLeadBucket) {
176: double invLevel = thePG.getLevel(startBucket)
177: - thePG.getActualDemand(refillBucket);
178: if (logger.isDebugEnabled()) {
179: logger
180: .debug("\n Item "
181: + thePG.getResource()
182: + " Inv Level for startBucket:"
183: + startBucket
184: + " is: "
185: + thePG.getLevel(startBucket)
186: + " - the actual demand for refillbucket:"
187: + refillBucket
188: + " is: "
189: + thePG
190: .getActualDemand(refillBucket)
191: + ".... The Critical Level for the refill bucket is: "
192: + thePG
193: .getCriticalLevel(refillBucket));
194: }
195:
196: // Note we had the following to fix some weirdness in subsistence charts
197: // but the critical == 0.0 prevents refills from being created during
198: // times when we get demand that causes us to go below 0 and the critical level
199: // is 0. For now just check that we are below and if we see weird behavior with
200: // subsistence charts we'll put in another check.
201: // if ((thePG.getCriticalLevel(refillBucket)< invLevel) ||
202: // (thePG.getCriticalLevel(refillBucket) == 0.0)) {
203:
204: // create an offset to account for the ammo rounding - otherwise we refill
205: // more then we need to because the refill might cause us to go below the
206: // critical level by .05 or so - pad with .06 to make sure we cover the bases.
207: // Later on this was taken out and set to 0.00 because we were
208: // finding this was causing the shortfall at standown at 191.
209: // See bug #12726
210: double criticalLevelOffset = 0.00;
211: if (inventoryPlugin.getSupplyType().equals(
212: "Ammunition")) {
213: criticalLevelOffset = 0.0;
214: }
215: if (((thePG.getCriticalLevel(refillBucket) - criticalLevelOffset) < invLevel)
216: || ((thePG.getCriticalLevel(refillBucket) == 0.0) && (invLevel >= 0.0))) {
217: thePG.setLevel(refillBucket, invLevel);
218: if (logger.isDebugEnabled()) {
219: logger
220: .debug("\nSetting the Inv Level for refillbucket: "
221: + refillBucket
222: + " to level: " + invLevel);
223: }
224: } else {
225: // int reorderPeriodEndBucket = refillBucket + (int)thePG.getReorderPeriod();
226: // double refillQty = generateRefill(invLevel, refillBucket,
227: // reorderPeriodEndBucket, thePG);
228: int reorderPeriodEndBucket = refillBucket
229: + (int) thePG.getReorderPeriod();
230: double targetLevel = getTargetLevel(
231: refillBucket, reorderPeriodEndBucket,
232: thePG);
233: if (clearTargetLevels) {
234: clearTargetLevels = false;
235: thePG.clearTargetLevels(clearTargetBucket);
236: }
237: thePG.setTarget(refillBucket, targetLevel);
238: if (thePG.getFillToCapacity()) {
239: double capacity = thePG.getCapacity();
240: if (targetLevel > capacity) {
241: logger
242: .warn("Target Level of "
243: + targetLevel
244: + " for inventory: "
245: + thePG
246: .getResource()
247: .getTypeIdentificationPG()
248: .getTypeIdentification()
249: + " at "
250: + getMyOrganization()
251: + " was clipped to meet capacity of "
252: + capacity);
253: }
254: targetLevel = capacity;
255: }
256: double refillQty = (targetLevel - invLevel);
257: // do some rounding/formatting
258: // System.out.println("\nrefillqty is:" + refillQty + " for agent:" +
259: // inventoryPlugin.getClusterId() + " supplytype:" +
260: // inventoryPlugin.getSupplyType() + " for item:"+
261: // debugItem);
262: if (inventoryPlugin.getSupplyType().equals(
263: "Ammunition")) {
264: /**
265: String formatted = getDecimalFormatter().format(refillQty);
266: refillQty = (new Double(formatted)).doubleValue();
267: ***/
268: refillQty = roundAmmoToHundrethsPlace(refillQty);
269: } else {
270: // make the refill a integer
271: refillQty = Math.ceil(refillQty);
272: //refillQty = Math.rint(refillQty);
273: }
274: // System.out.println("\nrefillqty after formatting is:" + refillQty + " for agent:" +
275: // inventoryPlugin.getClusterId() + " supplytype:" +
276: // inventoryPlugin.getSupplyType() + " for item:"+
277: // debugItem);
278: if (refillBucket < firstLegalRefillBucket) {
279: double criticalLevel = thePG
280: .getCriticalLevel(refillBucket);
281:
282: String refillBucketTime = getTimeUtils()
283: .dateString(
284: thePG
285: .convertBucketToTime(refillBucket));
286:
287: if ((criticalLevel <= 0) || (invLevel <= 0)) {
288: // if((criticalLevel < -1E-8) && logger.isWarnEnabled()) {
289: if ((criticalLevel < 0)
290: && logger.isWarnEnabled()) {
291: // Accounts for rounding errors
292: logger
293: .warn("At "
294: + inventoryPlugin
295: .getOrgName()
296: + "-"
297: + inventoryPlugin
298: .getSupplyType()
299: + "-Item:"
300: + myItemId
301: + ":"
302: + "Critical Level is "
303: + criticalLevel
304: + " and inventory level is "
305: + invLevel
306: + " at refill bucket time "
307: + refillBucketTime
308: + "!");
309: } else if (logger.isDebugEnabled()) {
310: logger
311: .debug("At "
312: + inventoryPlugin
313: .getOrgName()
314: + "-"
315: + inventoryPlugin
316: .getSupplyType()
317: + "-Item:"
318: + myItemId
319: + ":"
320: + "Critical Level is "
321: + criticalLevel
322: + " and inventory level is "
323: + invLevel
324: + " at refill bucket time "
325: + refillBucketTime
326: + "!");
327: }
328: }
329: //if the drop below critical level is greater than 5% then log a warning otherwise
330: //a debug message
331: else if ((criticalLevel - invLevel) > (0.20 * criticalLevel)) {
332: if (logger.isDebugEnabled()) {
333: logger
334: .debug("At "
335: + inventoryPlugin
336: .getOrgName()
337: + "-"
338: + inventoryPlugin
339: .getSupplyType()
340: + "-Item:"
341: + myItemId
342: + ":"
343: + " not ordering a refill on day "
344: + refillBucketTime
345: + " when we've fallen below critical level by "
346: + (((criticalLevel - invLevel) / criticalLevel))
347: + "percent, because it is before supplier arrival time + ost. Supplier arrival time is "
348: + TimeUtils
349: .dateString(classicInventoryManager
350: .getSupplierArrivalTime())
351: + " and add ost which is "
352: + orderShipTime);
353: }
354: } else if (logger.isDebugEnabled()) {
355: logger
356: .debug("At "
357: + inventoryPlugin
358: .getOrgName()
359: + "-"
360: + inventoryPlugin
361: .getSupplyType()
362: + "-Item:"
363: + myItemId
364: + ":"
365: + " not ordering a refill on day "
366: + refillBucketTime
367: + " when we've fallen below critical level by "
368: + (((criticalLevel - invLevel) / criticalLevel))
369: + "percent, because it is before supplier arrival time + ost. Supplier arrival time is "
370: + TimeUtils
371: .dateString(classicInventoryManager
372: .getSupplierArrivalTime())
373: + " and add ost which is "
374: + orderShipTime);
375: }
376: } else if (refillQty > 0.00) {
377: lastRefillBucket = refillBucket;
378: if (logger.isDebugEnabled()) {
379: logger
380: .debug("\n Creating Refill for bucket: "
381: + refillBucket
382: + " of quantity: "
383: + refillQty);
384: }
385: // make a task for this refill and publish it to glue plugin
386: // and apply it to the LogisticsInventoryBG
387: Task theRefill = createRefillTask(
388: refillQty,
389: thePG
390: .convertBucketToTime(refillBucket),
391: thePG, today, orderShipTime);
392:
393: newRefills.add(theRefill);
394: invLevel = invLevel + refillQty;
395:
396: } else if (logger.isDebugEnabled()) {
397: logger
398: .debug("Not placing a refill order of qty: "
399: + refillQty);
400: }
401:
402: thePG.setLevel(refillBucket, invLevel);
403: if (logger.isDebugEnabled()) {
404: double printsum = targetLevel;
405: logger
406: .debug("\nSetting the InventoryLevel and the TargetLevel to: "
407: + printsum);
408: }
409: prevTarget = targetLevel;
410: }
411: //reset the buckets
412: startBucket = refillBucket;
413: refillBucket = nextLegalRefillBucket(thePG,
414: startBucket);
415: }
416: // Set the target levels for projection period here since very similar
417: // calculations are done for both projection and refill period.
418: //setTargetForProjectionPeriod(thePG, maxLeadBucket+1, prevTarget);
419: // RJB
420: setTargetForProjectionPeriod(thePG,
421: lastRefillBucket + 1, prevTarget);
422: // call the Comparator for this Inventory which will compare the old and
423: // new Refills and then publish the new Refills and Rescind the old Refills.
424: myComparator.compareRefills(newRefills, oldRefills,
425: anInventory);
426: inventoryPlugin.disposeOfUnusedMILTask(anInventory,
427: newRefills.isEmpty());
428: } // end of if not level 2 inventory
429: } // done going through inventories
430: }
431:
432: public int nextLegalRefillBucket(LogisticsInventoryPG thePG,
433: int startBucket) {
434: int refillBucket = startBucket + 1;
435:
436: long refillTime = thePG.convertBucketToTime(refillBucket);
437: long nextLegalRefill = classicInventoryManager
438: .getNextLegalRefillTime(refillTime);
439: if (refillTime < nextLegalRefill) {
440: int nextLegalRefillBucket = thePG.convertTimeToBucket(
441: nextLegalRefill, false);
442: if (logger.isDebugEnabled()) {
443: logger.debug("Refill Time is " + new Date(refillTime)
444: + "==bucket(" + refillBucket
445: + ") and next legal refill time is "
446: + new Date(nextLegalRefill) + "==bucket("
447: + nextLegalRefillBucket + ")");
448: }
449:
450: /****
451: if((getOrgName().startsWith("159-")) ||
452: (getOrgName().startsWith("158-"))) {
453: logger.warn("Refill Time is " + new Date(refillTime) + "==bucket(" + refillBucket + ") and next legal refill time is " + new Date(nextLegalRefill) + "==bucket(" + nextLegalRefillBucket + ")");
454: }
455: **/
456: refillBucket = nextLegalRefillBucket;
457: }
458: return refillBucket;
459: }
460:
461: /** Make a Refill Task
462: * @param quantity The quantity of the Refill Task
463: * @param endDay The desired delivery date of the Refill Task
464: * @param thePG The LogisticsInventoryPG for the Inventory.
465: * @param today Time representing now to use as the earliest possible delivery
466: * @param ost The OrderShipTime used to calculate the CommitmentDate
467: * @return Task The new Refill Task
468: **/
469: private Task createRefillTask(double quantity, long endDay,
470: LogisticsInventoryPG thePG, long today, int ost) {
471: // make a new task
472: NewTask newRefill = inventoryPlugin.getPlanningFactory()
473: .newTask();
474: newRefill.setVerb(Constants.Verb.Supply);
475: newRefill.setDirectObject(thePG.getResource());
476: //set the commitment date to endDay - ost.
477: newRefill.setCommitmentDate(new Date(endDay
478: - (thePG.getBucketMillis() * ost)));
479: // newRefill.setCommitmentDate(new Date(getTimeUtils().subtractNDays(endDay, ost)));
480: // create preferences
481: Vector prefs = new Vector();
482: Preference p_end, p_qty;
483: p_end = getTaskUtils().createTimePreference(endDay, today,
484: inventoryPlugin.getOPlanEndTime(), AspectType.END_TIME,
485: inventoryPlugin.getClusterId(),
486: inventoryPlugin.getPlanningFactory(), thePG);
487: p_qty = createRefillQuantityPreference(quantity);
488: prefs.add(p_end);
489: prefs.add(p_qty);
490: newRefill.setPreferences(prefs.elements());
491:
492: //create Prepositional Phrases
493: Vector pp_vector = new Vector();
494: pp_vector.add(createPrepPhrase(Constants.Preposition.FOR,
495: getOrgName()));
496: pp_vector.add(createPrepPhrase(Constants.Preposition.OFTYPE,
497: inventoryPlugin.getSupplyType()));
498:
499: Object io;
500: Enumeration geolocs = getAssetUtils().getGeolocLocationAtTime(
501: getMyOrganization(), endDay);
502: if (geolocs.hasMoreElements()) {
503: io = geolocs.nextElement();
504: } else {
505: io = getHomeLocation();
506: }
507: pp_vector.add(createPrepPhrase(Constants.Preposition.TO, io));
508: Asset resource = thePG.getResource();
509: TypeIdentificationPG tip = resource.getTypeIdentificationPG();
510: MaintainedItem itemID = MaintainedItem
511: .findOrMakeMaintainedItem("Inventory", tip
512: .getTypeIdentification(), null, tip
513: .getNomenclature(), inventoryPlugin);
514: pp_vector.add(createPrepPhrase(
515: Constants.Preposition.MAINTAINING, itemID));
516: pp_vector.add(createPrepPhrase(Constants.Preposition.REFILL,
517: null));
518:
519: newRefill.setPrepositionalPhrases(pp_vector.elements());
520:
521: if ((endDay < classicInventoryManager.getRefillStartTime())
522: && (logger.isWarnEnabled())) {
523: logger
524: .warn("Creating new refill task for day "
525: + getTimeUtils().dateString(endDay)
526: + " before arrival in theatre time or arrival of supplier of "
527: + getTimeUtils().dateString(
528: classicInventoryManager
529: .getRefillStartTime())
530: + ". The task that is about to be published is "
531: + newRefill);
532: }
533:
534: return newRefill;
535: }
536:
537: /** Utility method to create a Refill Quantity preference
538: * We use a Strictly At scoring function for this preference.
539: * Note that out use of strictly at allows for multiple shipments as
540: * long as the total amount delivered meets the best quantity for this
541: * preference inside the feasable delivery time (defined by the end_time
542: * scoring function)
543: * @param refill_qty The quantity we want for this Refill Task
544: * @return Preference The new quantity preference for the Refill Task
545: **/
546: protected Preference createRefillQuantityPreference(
547: double refill_qty) {
548: ScoringFunction qtySF = ScoringFunction
549: .createStrictlyAtValue(AspectValue.newAspectValue(
550: AspectType.QUANTITY, refill_qty));
551: return inventoryPlugin.getPlanningFactory().newPreference(
552: AspectType.QUANTITY, qtySF);
553: }
554:
555: /** Utility method to create a Refill Task Prepositional Phrase
556: * @param prep The preposition
557: * @param io The indirect object
558: * @return PrepositionalPhrase A new prep phrase for the task
559: **/
560: protected PrepositionalPhrase createPrepPhrase(String prep,
561: Object io) {
562: NewPrepositionalPhrase newpp = inventoryPlugin
563: .getPlanningFactory().newPrepositionalPhrase();
564: newpp.setPreposition(prep);
565: newpp.setIndirectObject(io);
566: return newpp;
567: }
568:
569: /** Utility method to get and keep organization info from the InventoryPlugin. **/
570: protected Organization getMyOrganization() {
571: if (myOrg == null) {
572: myOrg = inventoryPlugin.getMyOrganization();
573: // if we still don't have it after we ask the inventory plugin, throw an error!
574: if (myOrg == null && logger.isErrorEnabled()) {
575: logger
576: .error("RefillGenerator can not get MyOrganization from "
577: + "the InventoryPlugin");
578: }
579: }
580: return myOrg;
581: }
582:
583: /** Utility method to get the Org Name from my organization and keep it around. **/
584: protected String getOrgName() {
585: if (myOrgName == null) {
586: myOrgName = getMyOrganization().getItemIdentificationPG()
587: .getItemIdentification();
588: }
589: return myOrgName;
590: }
591:
592: /** Utility method to get the default (home) location of the Org **/
593: protected GeolocLocation getHomeLocation() {
594: if (homeGeoloc == null) {
595: Organization org = getMyOrganization();
596: if (org.getMilitaryOrgPG() != null) {
597: GeolocLocation geoloc = (GeolocLocation) org
598: .getMilitaryOrgPG().getHomeLocation();
599: if (geoloc != null) {
600: homeGeoloc = geoloc;
601: } else {
602: //if we can't find the home loc either print an error
603: if (logger.isErrorEnabled()) {
604: logger
605: .error("RefillGenerator can not generate a "
606: + "Home Geoloc for org: " + org);
607: }
608: }
609: }
610: }
611: return homeGeoloc;
612: }
613:
614: protected void calculateInventoryLevelsForRG(int startBucket,
615: int endBucket, LogisticsInventoryPG thePG) {
616: //calculate inventory levels for today through start (today + OST)
617: startBucket = (startBucket < thePG.getStartBucket()) ? thePG
618: .getStartBucket() : startBucket;
619: while (startBucket <= endBucket) {
620: double level;
621: if (startBucket == 0) {
622: level = thePG.getLevel(0);
623: } else {
624: level = thePG.getLevel(startBucket - 1)
625: - thePG.getActualDemand(startBucket);
626: }
627: double committedRefill = findCommittedRefill(startBucket,
628: thePG, false);
629: thePG.setLevel(startBucket, (level + committedRefill));
630: startBucket = startBucket + 1;
631: }
632:
633: }
634:
635: protected DecimalFormat getDecimalFormatter() {
636: if (myDecimalFormatter == null) {
637: myDecimalFormatter = new DecimalFormat("##########.##");
638: }
639: return myDecimalFormatter;
640: }
641:
642: protected double roundAmmoToHundrethsPlace(double refillQty) {
643: BigDecimal roundedQty = ((new BigDecimal((double) refillQty))
644: .setScale(2, BigDecimal.ROUND_UP));
645: return roundedQty.doubleValue();
646: }
647: }
|