001: /*
002: * <copyright>
003: *
004: * Copyright 2001-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: package org.cougaar.logistics.plugin.trans;
027:
028: import java.math.BigDecimal;
029:
030: import java.util.Collection;
031: import java.util.Enumeration;
032: import java.util.HashSet;
033: import java.util.Iterator;
034: import java.util.List;
035: import java.util.Set;
036: import java.util.Vector;
037:
038: import org.cougaar.logistics.ldm.Constants;
039:
040: import org.cougaar.glm.ldm.asset.Container;
041: import org.cougaar.glm.ldm.asset.ContainPG;
042: import org.cougaar.glm.ldm.asset.ForUnitPG;
043: import org.cougaar.glm.ldm.asset.GLMAsset;
044: import org.cougaar.glm.ldm.asset.MovabilityPG;
045: import org.cougaar.glm.ldm.asset.NewForUnitPG;
046: import org.cougaar.glm.ldm.asset.NewPhysicalPG;
047: import org.cougaar.glm.ldm.asset.PhysicalPG;
048: import org.cougaar.glm.ldm.asset.PropertyGroupFactory;
049: import org.cougaar.glm.ldm.plan.GeolocLocation;
050:
051: import org.cougaar.logistics.plugin.trans.GLMTransConst;
052:
053: import org.cougaar.glm.util.GLMPrepPhrase;
054:
055: import org.cougaar.lib.callback.UTILAssetCallback;
056: import org.cougaar.lib.callback.UTILAssetListener;
057:
058: import org.cougaar.lib.filter.UTILExpanderPluginAdapter;
059:
060: import org.cougaar.planning.ldm.asset.AggregateAsset;
061: import org.cougaar.planning.ldm.asset.Asset;
062: import org.cougaar.planning.ldm.asset.AssetGroup;
063: import org.cougaar.planning.ldm.asset.ItemIdentificationPG;
064: import org.cougaar.planning.ldm.asset.NewItemIdentificationPG;
065: import org.cougaar.planning.ldm.asset.PropertyGroup;
066:
067: import org.cougaar.planning.ldm.measure.*;
068:
069: import org.cougaar.planning.ldm.plan.Task;
070: import org.cougaar.planning.ldm.plan.MPTask;
071: import org.cougaar.planning.ldm.plan.NewTask;
072:
073: /**
074: * Breaks up incoming tasks into aggregates that are no bigger than the largest carrier asset.
075: * Carrier could be truck, ship, or plane.
076: */
077: public class SeaTransportExpanderPlugin extends TransportExpanderPlugin {
078:
079: protected static final double CAP_FUDGE = 0.1;
080:
081: /**
082: * <pre>
083: * expands aggregate assets into truck-sized chunks, putting the
084: * subtasks into <code>subtasks</code>
085: *
086: * Rounds the item wt to the same precision as vishnu uses so no disaggreements
087: * about how much a truck can hold.
088: * </pre>
089: **/
090: protected void expandAggregates(Task task, Vector subtasks) {
091: AggregateAsset directObject = (AggregateAsset) task
092: .getDirectObject();
093: GLMAsset itemProto = (GLMAsset) directObject.getAsset();
094: ForUnitPG unitPG = getForUnitPG(directObject);
095:
096: boolean isTruck = isVehicle(itemProto);
097: boolean isContainer = isContainer(itemProto);
098:
099: double itemContrib;
100:
101: if (isTruck) {
102: itemContrib = getItemAreaContribution(itemProto);
103: } else if (isContainer) {
104: itemContrib = 1;
105: } else {
106: itemContrib = getItemVolumeContribution(itemProto);
107: }
108:
109: double maxCap = ((isTruck) ? maxAreaCapacity
110: : (isContainer ? maxContainerCapacity
111: : maxVolumeCapacity))
112: - CAP_FUDGE;
113: // double maxCap = (isPerson) ? maxPassengerCapacity : maxContainCapacity - CAP_FUDGE; // fudge necessary?
114: String unit = (isTruck) ? "m^2" : (isContainer ? "container"
115: : "m^3");
116: // round item weight to same precision as Vishnu
117: BigDecimal bigD = new BigDecimal(itemContrib);
118: itemContrib = bigD.setScale(2, BigDecimal.ROUND_UP)
119: .doubleValue();
120:
121: int remainingQuantity = getAssetQuantity(directObject);
122: double totalAggregateContrib = ((double) remainingQuantity)
123: * itemContrib;
124:
125: boolean mustExpand = (totalAggregateContrib > maxCap);
126:
127: if (isDebugEnabled()) {
128: debug(".expandAggregates - item contribution "
129: + itemContrib + " quantity " + remainingQuantity
130: + " total " + totalAggregateContrib
131: + " maxCapacity " + maxCap
132: + ((mustExpand) ? " must expand " : ""));
133: }
134:
135: int numItemsOnTruck = (int) (maxCap / itemContrib);
136:
137: // sanity checking
138: if (numItemsOnTruck == 0) {
139: warn(".expandAggregates - WARNING - max items on truck "
140: + numItemsOnTruck
141: + " is ZERO. Base asset of aggregate : "
142: + itemProto + " is " + itemContrib + " " + unit
143: + ", which is larger than"
144: + " carrier asset's max capacity " + maxCap + " "
145: + unit);
146: numItemsOnTruck = 1;
147: }
148:
149: if (remainingQuantity == 0)
150: error(".expandAggregates - ERROR - aggregate asset quantity is zero for direct object "
151: + directObject + " of task " + task.getUID());
152:
153: double maxOnTruck = ((double) numItemsOnTruck) * itemContrib;
154:
155: if (isDebugEnabled())
156: debug(".expandAggregates - max items on truck "
157: + numItemsOnTruck + " max num " + maxOnTruck);
158:
159: // keep making subtasks
160: while (totalAggregateContrib > maxCap) {
161: Task newtask;
162: Asset truckSizedSet = ldmf.createAggregate(itemProto,
163: numItemsOnTruck);
164: setItemPG(truckSizedSet, itemProto);
165: subtasks
166: .add(newtask = makeTask(task, truckSizedSet, unitPG));
167: totalAggregateContrib -= maxOnTruck;
168: remainingQuantity -= numItemsOnTruck;
169:
170: if (isDebugEnabled())
171: debug(".expandAggregates - cargo > truckload, "
172: + "Expanding with " + numItemsOnTruck
173: + " items on carrier, task id "
174: + newtask.getUID() + " remaining quantity "
175: + remainingQuantity + ", contribution "
176: + totalAggregateContrib);
177: }
178:
179: // if there's any left over, make one last task
180: if (remainingQuantity > 0) {
181: Asset truckSizedSet = (mustExpand) ? ldmf.createAggregate(
182: itemProto, remainingQuantity) : task
183: .getDirectObject();
184: setItemPG(truckSizedSet, itemProto);
185:
186: if (isDebugEnabled() && mustExpand)
187: debug(".expandAggregates - cargo was > truckload, "
188: + remainingQuantity
189: + " items on carrier, truckSizedSet had "
190: + ((AggregateAsset) truckSizedSet)
191: .getQuantity() + " items");
192: subtasks.add(makeTask(task, truckSizedSet, unitPG));
193: }
194: }
195:
196: /**
197: * <pre>
198: * expands aggregate assets into truck-sized chunks, putting the
199: * subtasks into <code>subtasks</code>
200: *
201: * Rounds the item wt to the same precision as vishnu uses so no disaggreements
202: * about how much a truck can hold.
203: * </pre>
204: **/
205: protected void expandLowFiAsset(Task task, Vector subtasks) {
206: if (isDebugEnabled())
207: debug("expanding low fi asset for task " + task.getUID());
208: // test();
209: GLMAsset itemProto = (GLMAsset) task.getDirectObject();
210: if (isDebugEnabled()) {
211: debug(".expandLowFiAsset d.o. "
212: + itemProto.getUID()
213: + " original dimensions :"
214: + " m "
215: + itemProto.getPhysicalPG().getMass().getTons()
216: + " tons, "
217: + " a "
218: + itemProto.getPhysicalPG().getFootprintArea()
219: .getSquareMeters()
220: + " m^2"
221: + " v "
222: + itemProto.getPhysicalPG().getVolume()
223: .getCubicMeters() + " m^3");
224: }
225:
226: ForUnitPG unitPG = getForUnitPG(itemProto);
227:
228: double totalContrib = getItemAreaContribution(itemProto);
229: boolean originalWasTiny = (totalContrib <= 0.00001);
230: double maxCap = maxAreaCapacity - CAP_FUDGE;
231:
232: // round item weight to same precision as Vishnu
233: BigDecimal bigD = new BigDecimal(totalContrib);
234: totalContrib = bigD.setScale(2, BigDecimal.ROUND_UP)
235: .doubleValue();
236:
237: boolean mustExpand = (totalContrib > maxCap);
238: double itemContrib = (mustExpand) ? maxCap : totalContrib;
239:
240: if (originalWasTiny) {
241: warn(".expandLowFiAsset - item contribution "
242: + totalContrib + " for task " + task.getUID()
243: + "'s direct object " + itemProto
244: + " is < 0.00001, was " + totalContrib);
245: }
246:
247: if (isDebugEnabled()) {
248: debug(".expandLowFiAsset - item contribution "
249: + itemContrib + " maxCapacity " + maxCap
250: + ((mustExpand) ? " must expand " : ""));
251: }
252:
253: int numItemsOnTruck = 1;
254:
255: double maxOnTruck = maxCap; // area
256:
257: if (isDebugEnabled())
258: debug(".expandLowFiAsset - max items on truck "
259: + numItemsOnTruck + " max num " + maxOnTruck);
260:
261: PhysicalPG originalPhysicalPG = itemProto.getPhysicalPG();
262:
263: // keep making subtasks
264: while (totalContrib > maxCap) {
265: Task newtask;
266: Asset truckSizedAsset = assetHelper.createInstance(
267: ldmProtoCache,
268: GLMTransConst.LOW_FIDELITY_PROTOTYPE,
269: getUniqueID(itemProto));
270: adjustDimensions((GLMAsset) truckSizedAsset,
271: originalPhysicalPG, maxOnTruck);
272:
273: subtasks.add(newtask = makeTask(task, truckSizedAsset,
274: unitPG));
275: totalContrib -= itemContrib;
276:
277: if (isDebugEnabled())
278: debug(".expandLowFiAsset - cargo > truckload, "
279: + "Expanding with " + numItemsOnTruck
280: + " items on carrier, task id "
281: + newtask.getUID() + ", contribution "
282: + maxOnTruck + " total now " + totalContrib);
283: }
284:
285: // if there's any left over, make one last task
286: if (totalContrib > 0.00001 || originalWasTiny) {
287: Asset truckSizedAsset;
288: if (mustExpand) {
289: truckSizedAsset = assetHelper.createInstance(
290: ldmProtoCache,
291: GLMTransConst.LOW_FIDELITY_PROTOTYPE,
292: getUniqueID(itemProto));
293: adjustDimensions((GLMAsset) truckSizedAsset,
294: originalPhysicalPG, totalContrib);
295: } else
296: truckSizedAsset = task.getDirectObject();
297:
298: if (isDebugEnabled() && mustExpand)
299: debug(".expandLowFiAsset - cargo was > carrier load, "
300: + " truckSizedAsset is " + totalContrib
301: + " square meters");
302: subtasks.add(makeTask(task, truckSizedAsset, unitPG));
303: }
304: if (isDebugEnabled()) {
305: debug(".expandLowFiAsset d.o. "
306: + itemProto.getUID()
307: + " after dimensions :"
308: + " m "
309: + itemProto.getPhysicalPG().getMass().getTons()
310: + " tons, "
311: + " a "
312: + itemProto.getPhysicalPG().getFootprintArea()
313: .getSquareMeters()
314: + " m^2"
315: + " v "
316: + itemProto.getPhysicalPG().getVolume()
317: .getCubicMeters() + " m^3");
318: }
319: }
320:
321: /**
322: * gets the contribution each individual item makes to consuming
323: * the capacity of the transport vehicle
324: * Sub classes may want to override this
325: * @param itemAsset -- the asset of the direct object of the task
326: * @return double of the contribution in TONS
327: */
328: public double getItemVolumeContribution(GLMAsset itemAsset) {
329: double itemVolume = 0.01;
330: try {
331: itemVolume = itemAsset.getPackagePG().getPackVolume()
332: .getCubicMeters();
333: } catch (Exception e) {
334: try {
335: itemVolume = itemAsset.getPhysicalPG().getVolume()
336: .getCubicMeters();
337: } catch (Exception ee) {
338: if (!itemAsset.hasPersonPG())
339: warn(".getItemVolumeContribution - unable to determine "
340: + itemAsset.getUID() + "'s volume.");
341: }
342: }
343:
344: return itemVolume;
345: }
346:
347: /**
348: * gets the contribution each individual item makes to consuming
349: * the capacity of the transport vehicle
350: * Sub classes may want to override this
351: * @param itemAsset GLMAsset -- the asset of the direct object of the task
352: * @return double of the contribution in TONS
353: */
354: public double getItemAreaContribution(GLMAsset itemAsset) {
355: double itemArea = 0.01;
356: try {
357: itemArea = itemAsset.getPackagePG().getPackFootprintArea()
358: .getSquareMeters();
359: } catch (Exception e) {
360: try {
361: itemArea = itemAsset.getPhysicalPG().getFootprintArea()
362: .getSquareMeters();
363: /*
364: if (itemArea < 0.00001) {
365: itemArea = itemAsset.getPhysicalPG().getLength().getMeters()*
366: itemAsset.getPhysicalPG().getWidth().getMeters();
367: }
368: */
369: } catch (Exception ee) {
370: if (!itemAsset.hasPersonPG())
371: warn(".getItemContribution - unable to determine "
372: + itemAsset.getUID() + "'s area.");
373: }
374: }
375:
376: return itemArea;
377: }
378:
379: /**
380: * <pre>
381: * Something is a vehicle if
382: * a) it has a ground vehicle PG OR
383: * b) it has a movability PG with a cargo category code whose
384: * first character is either R or A
385: *
386: * </pre>
387: * @return true if asset is a vehicle
388: */
389: protected boolean isVehicle(GLMAsset asset) {
390: if (asset.hasGroundVehiclePG())
391: return true;
392:
393: if (!asset.hasMovabilityPG())
394: return false;
395:
396: try {
397: MovabilityPG move_prop = asset.getMovabilityPG();
398: String cargocatcode = move_prop.getCargoCategoryCode();
399: char first = cargocatcode.charAt(0);
400: if (first == 'R' || first == 'A')
401: return true;
402: } catch (Exception e) {
403: return false;
404: }
405:
406: return false;
407: }
408:
409: protected boolean isContainer(GLMAsset asset) {
410: return asset instanceof Container;
411: }
412:
413: protected void adjustDimensions(GLMAsset asset,
414: PhysicalPG originalPhysicalPG, double squareMeters) {
415: if (isDebugEnabled())
416: debug(".adjustDimensions called on " + asset.getUID());
417:
418: double aggregateSquareMeters = originalPhysicalPG
419: .getFootprintArea().getSquareMeters();
420:
421: double ratio = squareMeters / aggregateSquareMeters;
422:
423: double length = originalPhysicalPG.getLength().getMeters();
424: double width = originalPhysicalPG.getWidth().getMeters();
425: double height = originalPhysicalPG.getHeight().getMeters();
426: double area = originalPhysicalPG.getFootprintArea()
427: .getSquareMeters();
428: double volume = originalPhysicalPG.getVolume().getCubicMeters();
429: double mass = originalPhysicalPG.getMass().getKilograms();
430:
431: NewPhysicalPG newPhysicalPG = PropertyGroupFactory
432: .newPhysicalPG();
433: newPhysicalPG.setLength(new Distance(length * ratio,
434: Distance.METERS));
435: newPhysicalPG.setWidth(new Distance(width * ratio,
436: Distance.METERS));
437: newPhysicalPG.setHeight(new Distance(height * ratio,
438: Distance.METERS));
439: newPhysicalPG.setMass(new Mass(mass * ratio, Mass.KILOGRAMS));
440:
441: newPhysicalPG.setFootprintArea(new Area(area * ratio,
442: Area.SQUARE_METERS));
443: newPhysicalPG.setVolume(new Volume(volume * ratio,
444: Volume.CUBIC_METERS));
445:
446: if (isDebugEnabled()) {
447: debug(".adjustDimensions chunk "
448: + asset.getUID()
449: + " original dimensions :"
450: + " m "
451: + asset.getPhysicalPG().getMass().getTons()
452: + " tons, "
453: + " a "
454: + asset.getPhysicalPG().getFootprintArea()
455: .getSquareMeters() + " m^2, " + " v "
456: + asset.getPhysicalPG().getVolume().getCubicFeet()
457: + " m^3");
458: }
459:
460: asset.setPhysicalPG(newPhysicalPG);
461:
462: if (isDebugEnabled()) {
463: debug(".adjustDimensions chunk "
464: + asset.getUID()
465: + " after setting dimensions :"
466: + " m "
467: + asset.getPhysicalPG().getMass().getTons()
468: + " tons, "
469: + " a "
470: + asset.getPhysicalPG().getFootprintArea()
471: .getSquareMeters()
472: + " m^2, "
473: + " v "
474: + asset.getPhysicalPG().getVolume()
475: .getCubicMeters() + " m^3");
476: }
477: }
478:
479: // protected double getRatio (PhysicalPG originalPhysicalPG, double originalAggregate) {
480: // double aggregateTons = originalPhysicalPG.getMass().getTons();
481: //
482: // double ratio = tons/aggregateTons;
483: // }
484:
485: /**
486: * calculates max weight, vol, pax for glmasset.
487: *
488: * if doesn't have pg or field on pg, slot gets Double.MAX_VALUE.
489: */
490: public double[] getAssetMaxContain(GLMAsset glmasset) {
491: double max[] = new double[3];
492:
493: max[0] = Double.MAX_VALUE;
494: max[1] = Double.MAX_VALUE;
495: max[2] = Double.MAX_VALUE;
496:
497: if (glmasset.hasContainPG()) {
498: try {
499: max[0] = glmasset.getContainPG()
500: .getMaximumFootprintArea().getSquareMeters();
501: } catch (Exception e) {
502: if (isDebugEnabled())
503: logger.debug(
504: "getAssetMaxContain, getting area, got exception for asset "
505: + glmasset, e);
506: }
507:
508: try {
509: max[1] = glmasset.getContainPG().getMaximumVolume()
510: .getCubicMeters();
511: } catch (Exception e) {
512: if (isDebugEnabled())
513: logger.debug(
514: "getAssetMaxContain, getting volume, got exception for asset "
515: + glmasset, e);
516: }
517:
518: try {
519: max[2] = (double) glmasset.getContainPG()
520: .getMaximumContainers();
521: } catch (Exception e) {
522: if (isDebugEnabled())
523: logger.debug(
524: "getAssetMaxContain, getting containers, got exception for asset "
525: + glmasset, e);
526: }
527:
528: if (isDebugEnabled())
529: debug(".getAssetMaxContain : max area - " + max[0]
530: + " max vol " + max[1] + " max containers "
531: + max[2]);
532: } else {
533: warn("getAssetMaxContain " + glmasset
534: + " doesn't have a contain pg?");
535: }
536: return max;
537: }
538:
539: public void resetCapacities() {
540: Collection carriers = myAssetCallback.getSubscription()
541: .getCollection();
542: handleNewAssets(java.util.Collections.enumeration(carriers));
543: if (isInfoEnabled()) {
544: info(getName()
545: + ".resetCapacities - recalculated maxContainContrib after rehydration using "
546: + carriers.size() + " ships.");
547: }
548:
549: if (maxAreaCapacity == Double.MAX_VALUE) {
550: if (isWarnEnabled()) {
551: warn(getName()
552: + ".resetCapacities - maxContainCapacity has not been set, it's "
553: + maxContainCapacity + " - checked - "
554: + carriers.size() + " ships.");
555: }
556: if (!carriers.isEmpty()) {
557: GLMAsset ship = (GLMAsset) carriers.iterator().next();
558: if (isWarnEnabled()) {
559: warn(getName()
560: + ".resetCapacities - first carrier is "
561: + ship + " with contain pg "
562: + ship.getContainPG());
563: }
564: }
565: }
566: }
567:
568: /** calculates the max contain -- smallest of all seen */
569: protected void calculateCommonMaxContain(double[] maxcontain) {
570: if (maxcontain[0] < maxAreaCapacity && maxcontain[0] > 0
571: && (maxcontain[0] > 0)) {
572: maxAreaCapacity = maxcontain[0];
573: if (isInfoEnabled())
574: info("Max Area now " + maxAreaCapacity);
575: }
576:
577: if (maxcontain[1] < maxVolumeCapacity && maxcontain[1] > 0
578: && (maxcontain[1] > 0)) {
579: maxVolumeCapacity = maxcontain[1];
580: if (isInfoEnabled())
581: info("Max Volume now " + maxVolumeCapacity);
582: }
583:
584: if (maxcontain[2] < maxContainerCapacity && maxcontain[2] > 0
585: && (maxcontain[2] > 0)) {
586: maxContainerCapacity = maxcontain[2];
587: if (isInfoEnabled())
588: info("Max container now " + maxContainerCapacity);
589: }
590: }
591:
592: protected double maxAreaCapacity = Double.MAX_VALUE;
593: protected double maxVolumeCapacity = Double.MAX_VALUE;
594: protected double maxContainerCapacity = Double.MAX_VALUE;
595: }
|