Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Divide and conquer the Inventory class #463

Closed
mokun opened this issue Oct 3, 2021 · 120 comments
Closed

Divide and conquer the Inventory class #463

mokun opened this issue Oct 3, 2021 · 120 comments
Assignees
Milestone

Comments

@mokun
Copy link
Member

mokun commented Oct 3, 2021

Is your feature request related to a problem? Please describe.

  • Simplify the Inventory class

Describe the solution you'd like

  • We may separate the use of Inventory to various class. Currently, it holds
    -- Unit class such as Person, Robot, Vehicle, Equipment, etc.
    -- Amount Resources
    -- Item Resources

Describe alternatives you've considered

  • Leave it alone at the expense of high cpu utilization

Additional context

  • Previous threads of issues and discussions :
  1. Serialization #293 (comment).
  2. Cannot store previous demand Good Value, lightweight Inventory #348.
  3. Have a single means to reference Resources #306.
@mokun
Copy link
Member Author

mokun commented Oct 3, 2021

@bevans2000

Now, I start working on removing the use of Inventory for EVASuit.

It could use a lightweight form of inventory, much like those container types (Bag, Specimen Box, etc.).

Currently, EVASuit tracks only 3 specific resources (oxygen, water and co2) and so it doesn't need to own a full blown Inventory class.

@bevans2000
Copy link
Member

The current Inventory pays 3 roles

  1. Holder of AmountResources - references by AmountResource
  2. Holder of Equipment - referenced by EquipmentType
  3. Holder of Parts - referenced by Part

Each of these could be represented as a dedicated Interface with separate implementations. Then certain Unit sub classes would implement the appropriate interface, e.g Equipment would just be HolderAmountResource. A settlement would be all 3.; however the implementation for Settlement would also record demand automatically.

Each of the interfaces follow the same behaviour and would have just:

  • How much is stored?
  • Remove an amount - return how much was actually removed.
  • Add an amount - return how much was actually added
  • Transfer and amount to another instance of the same interface.
  • Drop the exception throwing if there is not enough stored; method return how much was actually transferred

mokun added a commit that referenced this issue Oct 4, 2021
r6240
2021-10-03

## DISCUSSION
1. #463
2. #293 (reply in thread)

## NEW
1. Adopt a lightweight approach to storing resoures for EVASuit
   - Remove the need of having an Inventory instance
1. Testing microstream
   - Add microstream related maven artifacts.
   - Create an instance of DataRoot and EmbeddedStorageManager
     in SimulationConfig.
   - Save using microstream's EmbeddedStorageManager
   - a collection of settlement
   - located in .mars-sim/saved/

## CHANGE
1. Modify EVASuit and related class that used to use Inventory
   for storing and retrieving resources.
@mokun
Copy link
Member Author

mokun commented Oct 4, 2021

Then certain Unit sub classes would implement the appropriate interface, e.g Equipment would just be HolderAmountResource

Sounds good. Please do go ahead with this plan to simplify the object graph of Inventory

@mokun
Copy link
Member Author

mokun commented Oct 4, 2021

@bevans2000 ,

After this commit, currently, there's a bug that creates the following weight issue on the EVA suit :

00-Adir-01:558.743 (Severe) Inventory : [New Pompeii - Pranav Jai] EVA Suit 063 - Had a mass of 1401.6 kg - too much to put on 'Pranav Jai' to carry. Remaining Gen Cap : 59.9 kg. (Gen Cap : 60.0 kg)
00-Adir-01:558.743 (Severe) Inventory : [Unknown] EVA Suit 063 - Could not be stored.
00-Adir-01:558.884 (Severe) Inventory : [New Pompeii - Aradhana Sandeep] EVA Suit 064 - Had a mass of 1331.4 kg - too much to put on 'Aradhana Sandeep' to carry. Remaining Gen Cap : 64.9 kg. (Gen Cap : 65.0 kg)
00-Adir-01:558.884 (Severe) Inventory : [Unknown] EVA Suit 064 - Could not be stored.

It is caused by the method canStoreUnit(Unit unit, boolean allowDirty) in Inventory. Somehow it reports that an EVA suit weighs too much and can't be put on. Everything looks okay to me and I have no idea why.

Can you take a look and figure out why ? Thanks !

@mokun
Copy link
Member Author

mokun commented Oct 4, 2021

Also, the getMass() in Unit looks normal as follows:

	/**
	 * Gets the unit's mass including inventory mass.
	 * 
	 * @return mass of unit and inventory
	 * @throws Exception if error getting the mass.
	 */
	public double getMass() {
		double invMass = 0;
		if (this instanceof Equipment) {
			if (this instanceof EVASuit)
				invMass = ((EVASuit)this).getStoredMass();
			else
				invMass = ((Equipment)this).getStoredMass();
		}
		else {
			if (inventory == null) { 
				logger.severe(this + ": inventory is null.");
			}
			else 
				inventory.getTotalInventoryMass(false);
			if (invMass == 0)
				return baseMass;
		}
		
		return baseMass + invMass;
	}

Guess there's a better way to code getMass() to avoid all those instanceof.

It would call getStoredMass() in EVASuit to obtain the weight of the just resources in an EVA suit.

The baseMass of an empty EVAsuit was computed at the start of the sim as the summation of all the parts the compose the suit, namely, the array EVASUIT_PARTS in ItemResourceUtil.

@bevans2000
Copy link
Member

Sure. I think this code highlights the problem we face where there are a lot of instanceof to cater for Units that do not have an Inventory.

@mokun
Copy link
Member Author

mokun commented Oct 4, 2021

Sure. I think this code highlights the problem we face where there are a lot of instanceof to cater for Units that do not have an Inventory.

Yea. Say, after we fix this problem for handling resources for EVA suit , we can for sure take a closer look at optimizing it and getting rid of those instanceof's.

bevans2000 added a commit that referenced this issue Oct 4, 2021
Changes:
- The resource mass record in the suit keep growing instead of one per
resource type.
- Override the getMass method for Equipment to use stored mass
- Inventory transfer put Unit back into source if the new Owner can not
hold it. This prevents a "leak" of Equipment.

#463
@bevans2000
Copy link
Member

OK so I looked at this. The problem is in setQuantity you use 'add' instead of 'set' so it keeps adding to the quantities instead of updating the existing value. The was also a mistake in the Unit.getMass method where it was not using the mass of the inventory. There are still a few warnings about a EVA Suit being too heavy to store but these cases look like the Person is just carrying too much stuff as the EVA Suit mass is reasonable. For what I can see these problem cases are when the Person has a small capacity; maybe it is something wrong with the change to do carrying capacity related to age?

Having the separate parallel lists is a dangerous approach because they can get out of synch. Why not just bit the bullet and use a Map? It will be efficient. Each Map Entry would be a simple POJO holding the current amount & capacity.

What I can see is the work you've done in EVASuit & Equipment containers is very similar. One just holds a fixed set of resources and the Containers just hold a single resource. I think what could be done to improve this is to create a new class ResourceStorageImpl that encapsulates the logic which moves the resource logic out of EVASuit into a new place. The supported Resources would be passed in the constructor. Hence the same class can also be used for the Bag, Box, etc BUT only a single resource is used.
I would then put an interface ResourceStorage holding the key methods to retrieve & store and then implement this on the appropriate Units. Then many of the instanceof code can be replaced by checking against the interface instead which is always more acceptable. Then the Units would use a delegate pattern to use the ResourceStorageImpl class. This class would be easy to Unit test in isolation as well which is a bonus.
The other improvement I would make to the simple class approach is to hold the total mass as a property instead of recalculating each time. The mass will be constant and only change when resources are added or removed. The size of an extra double is nothing compared to the processing avoided by not continuously adding up the volumes. Asking for current volumes is more frequent than adding/removing.
Then further ahead; this new class could be backfilled into the existing Inventory to replace logic there.

@mokun
Copy link
Member Author

mokun commented Oct 4, 2021

Having the separate parallel lists is a dangerous approach because they can get out of synch. Why not just bit the bullet and use a Map? It will be efficient. Each Map Entry would be a simple POJO holding the current amount & capacity.

okay. I'll switch to Map

create a new class ResourceStorageImpl that encapsulates the logic which moves the resource logic
I would then put an interface ResourceStorage holding the key methods to retrieve & store

I'll let you lead the way to implement this correctly. Is it okay ?

I suppose this can be extend to hold Item Resources as well in future.

We can use this in replace of the Inventory inside the vehicle as vehicle allows a few other resources to be stored.

The other improvement I would make to the simple class approach is to hold the total mass as a property instead of recalculating each time

Sure. It shouldn't need to be recalculated.

@bevans2000
Copy link
Member

Having the separate parallel lists is a dangerous approach because they can get out of synch. Why not just bit the bullet and use a Map? It will be efficient. Each Map Entry would be a simple POJO holding the current amount & capacity.

okay. I'll switch to Map

create a new class ResourceStorageImpl that encapsulates the logic which moves the resource logic
I would then put an interface ResourceStorage holding the key methods to retrieve & store

I'll let you lead the way to implement this correctly. Is it okay ?

I suppose this can be extend to hold Item Resources as well in future.
Well I would go simple and have a different class and interface for Item Resources. This would remove the need to always check the range if the resource id before using it. Same pattern as Resources.

We can use this in replace of the Inventory inside the vehicle as vehicle allows a few other resources to be stored.
Yes. But small steps are needed here since Inventory is so key at the moment.

I should have said I did a commit earlier that fixed the EVA suit problem.

@mokun
Copy link
Member Author

mokun commented Oct 4, 2021

Yes. Thanks for fixing that.

@mokun
Copy link
Member Author

mokun commented Oct 7, 2021

Calculating mass is still an issue from time to time as follows:

00-Adir-10:333.979 (Info) EnterAirlock [x264] : [0.00 N 0.00 W] Ray Bradbury - Could not enter airlock to EVA Airlock 3. Already full.
00-Adir-10:333.979 (Info) EnterAirlock [x264] : [0.00 N 2.23 W] Anna Svoboda - Could not enter airlock to EVA Airlock 3. Already full.
00-Adir-10:338.873 (Info) PlanMission : [New Plymouth] Sarah Thompson - Looking into the settlement's mission needs.
00-Adir-10:338.873 (Info) DeliveryMeta : [New Plymouth] Drone 001 available for delivery mission.
00-Adir-10:338.873 (Warning) UnitManager : Unit not found 60052 type:EQUIPMENT baseID:3753
00-Adir-10:338.873 (Warning) UnitManager : Unit not found 60052 type:EQUIPMENT baseID:3753
00-Adir-10:338.873 (Warning) UnitManager : Unit not found 60052 type:EQUIPMENT baseID:3753
00-Adir-10:338.873 (Warning) UnitManager : Unit not found 60052 type:EQUIPMENT baseID:3753
00-Adir-10:338.873 (Severe) UnitManager$SettlementTask : Problem with pulse on Europa: null
java.lang.NullPointerException
	at org.mars_sim.msp.core.Inventory.updateUnitTotalMassCache(Inventory.java:3131)
	at org.mars_sim.msp.core.Inventory.getUnitTotalMassCache(Inventory.java:3118)
	at org.mars_sim.msp.core.Inventory.getUnitTotalMass(Inventory.java:1373)
	at org.mars_sim.msp.core.Inventory.getGeneralStoredMass(Inventory.java:1155)
	at org.mars_sim.msp.core.Inventory.getRemainingGeneralCapacity(Inventory.java:1165)
	at org.mars_sim.msp.core.Inventory.updateAmountResourceCapacityCache(Inventory.java:2729)
	at org.mars_sim.msp.core.Inventory.getAmountResourceCapacityCacheValue(Inventory.java:2637)
	at org.mars_sim.msp.core.Inventory.getAmountResourceCapacity(Inventory.java:634)
	at org.mars_sim.msp.core.Inventory.getAmountResourceRemainingCapacity(Inventory.java:726)
	at org.mars_sim.msp.core.foodProduction.FoodProductionUtil.getFoodProductionProcessItemValue(FoodProductionUtil.java:194)
	at org.mars_sim.msp.core.structure.goods.GoodsManager.getPartFoodProductionProcessDemand(GoodsManager.java:3084)
	at org.mars_sim.msp.core.structure.goods.GoodsManager.getPartFoodProductionDemand(GoodsManager.java:3048)
	at org.mars_sim.msp.core.structure.goods.GoodsManager.determineItemResourceGoodValue(GoodsManager.java:2586)
	at org.mars_sim.msp.core.structure.goods.GoodsManager.determineGoodValue(GoodsManager.java:459)
	at org.mars_sim.msp.core.structure.Settlement.timePassing(Settlement.java:1087)
	at org.mars_sim.msp.core.UnitManager$SettlementTask.call(UnitManager.java:704)
	at org.mars_sim.msp.core.UnitManager$SettlementTask.call(UnitManager.java:1)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:829)

00-Adir-10:338.873 (Info) MeteorologyStudyFieldWork [x58] : [Drifter] Eloise Belanger - clearDown::totalCollected: 0.0
00-Adir-10:338.873 (Warning) UnitManager : Unit not found 60084 type:EQUIPMENT baseID:3755
00-Adir-10:338.873 (Warning) UnitManager : Unit not found 60084 type:EQUIPMENT baseID:3755
00-Adir-10:338.873 (Warning) UnitManager : Unit not found 60084 type:EQUIPMENT baseID:3755
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - food (balue: 42.4)  Buyer: New Plymouth  Seller: Europa.
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - gasket (balue: 13.0)  Buyer: New Plymouth  Seller: Europa.
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - gasket - Buyer: New Plymouth  Seller: Europa  totalBuyingValue: 8356.1  totalDelivered: 127.0
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - lubricant bottle (balue: 9.7)  Buyer: New Plymouth  Seller: Europa.
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - lubricant bottle - Buyer: New Plymouth  Seller: Europa  totalBuyingValue: 1084.7  totalDelivered: 22.0
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - counter pressure suit (balue: 9.6)  Buyer: New Plymouth  Seller: Europa.
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - counter pressure suit - Buyer: New Plymouth  Seller: Europa  totalBuyingValue: 1513.7  totalDelivered: 31.0
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - eva antenna (balue: 7.5)  Buyer: New Plymouth  Seller: Europa.
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - eva antenna - Buyer: New Plymouth  Seller: Europa  totalBuyingValue: 541.9  totalDelivered: 15.0
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - power transistor (balue: 1.6)  Buyer: New Plymouth  Seller: Europa.
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - power transistor - Buyer: New Plymouth  Seller: Europa  totalBuyingValue: 35.6  totalDelivered: 4.0
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - Buyer: New Plymouth  Seller: Europa  buyerLoadValue: 16047.3  deliveryList: [gasket, counter pressure suit, food, lubricant bottle, power transistor, bag, eva antenna]
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - pulp (balue: 190.7)  Buyer: Europa  Seller: New Plymouth.
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - concrete (balue: 41.7)  Buyer: Europa  Seller: New Plymouth.
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - electrical wire (balue: 31.3)  Buyer: Europa  Seller: New Plymouth.
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - electrical wire - Buyer: Europa  Seller: New Plymouth  totalBuyingValue: 325678.6  totalDelivered: 488.0
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - wire connector (balue: 12.3)  Buyer: Europa  Seller: New Plymouth.
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - wire connector - Buyer: Europa  Seller: New Plymouth  totalBuyingValue: 2571.9  totalDelivered: 9.0
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - Buyer: Europa  Seller: New Plymouth  buyerLoadValue: 341105.2  deliveryList: [wire connector, concrete, bag, electrical wire, pulp]
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Load Credit: 372295.1
00-Adir-10:338.873 (Info) DeliveryUtil : [Europa] Load Credit: 390671.9
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Load Credit: 20097.2
00-Adir-10:338.873 (Info) DeliveryUtil : [Europa] Load Credit: 16124.9
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Selling Credit Home: 372295.1
00-Adir-10:338.873 (Info) DeliveryUtil : [Europa] Selling Credit Remote: 390671.9
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Buying Credit Home: 20097.2
00-Adir-10:338.873 (Info) DeliveryUtil : [Europa] Buying Credit Remote: 16124.9
00-Adir-10:338.873 (Info) DeliveryUtil : [Europa] totalProfit: 22349.0
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Estimated Revenue: 22349.0
00-Adir-10:338.873 (Info) VehicleMission : [New Plymouth] Drone 001 - tripDistance: 2562.0 km   fuel economy: 42.6 km/kg   composite fuel margin factor: 1.0   Amount of fuel: 60.2 kg
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Load Credit: 1.6
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Estimated Cost: 1.6
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Delivering to Europa  best profit: 22347.4
00-Adir-10:338.873 (Info) DeliveryMeta : [New Plymouth] Sarah Thompson - DeliveryMeta's probability: 398.0
00-Adir-10:338.873 (Info) MissionManager : [New Plymouth] Sarah Thompson - Mission Delivery with probability=398.0
00-Adir-10:338.873 (Info) MissionManager : [New Plymouth] Sarah Thompson - Mission Mineral Exploration with probability=98.0
00-Adir-10:338.873 (Info) Mission : [New Plymouth] Sarah Thompson - Began organizing a Delivery mission.
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - food (balue: 42.4)  Buyer: New Plymouth  Seller: Europa.
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - gasket (balue: 13.0)  Buyer: New Plymouth  Seller: Europa.
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - gasket - Buyer: New Plymouth  Seller: Europa  totalBuyingValue: 8356.1  totalDelivered: 127.0
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - lubricant bottle (balue: 9.7)  Buyer: New Plymouth  Seller: Europa.
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - lubricant bottle - Buyer: New Plymouth  Seller: Europa  totalBuyingValue: 1084.7  totalDelivered: 22.0
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - counter pressure suit (balue: 9.6)  Buyer: New Plymouth  Seller: Europa.
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - counter pressure suit - Buyer: New Plymouth  Seller: Europa  totalBuyingValue: 1513.7  totalDelivered: 31.0
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - eva antenna (balue: 7.5)  Buyer: New Plymouth  Seller: Europa.
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - eva antenna - Buyer: New Plymouth  Seller: Europa  totalBuyingValue: 541.9  totalDelivered: 15.0
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - power transistor (balue: 1.6)  Buyer: New Plymouth  Seller: Europa.
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - power transistor - Buyer: New Plymouth  Seller: Europa  totalBuyingValue: 35.6  totalDelivered: 4.0
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - Buyer: New Plymouth  Seller: Europa  buyerLoadValue: 16047.3  deliveryList: [gasket, counter pressure suit, food, lubricant bottle, power transistor, bag, eva antenna]
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - pulp (balue: 190.7)  Buyer: Europa  Seller: New Plymouth.
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - concrete (balue: 41.7)  Buyer: Europa  Seller: New Plymouth.
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - electrical wire (balue: 31.3)  Buyer: Europa  Seller: New Plymouth.
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - electrical wire - Buyer: Europa  Seller: New Plymouth  totalBuyingValue: 325678.6  totalDelivered: 488.0
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - wire connector (balue: 12.3)  Buyer: Europa  Seller: New Plymouth.
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - wire connector - Buyer: Europa  Seller: New Plymouth  totalBuyingValue: 2571.9  totalDelivered: 9.0
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Drone 001 - Buyer: Europa  Seller: New Plymouth  buyerLoadValue: 341105.2  deliveryList: [wire connector, concrete, bag, electrical wire, pulp]
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Load Credit: 372295.1
00-Adir-10:338.873 (Info) DeliveryUtil : [Europa] Load Credit: 390671.9
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Load Credit: 20097.2
00-Adir-10:338.873 (Info) DeliveryUtil : [Europa] Load Credit: 16124.9
00-Adir-10:338.873 (Info) DeliveryUtil : [New Plymouth] Load Credit: 1.6
00-Adir-10:338.873 (Info) Mission : [New Plymouth] Sarah Thompson - Delivery #1 tagged with 'Not enough members recruited'.
00-Adir-10:338.873 (Info) Mission : [New Plymouth] Sarah Thompson - Ended Delivery #1.
00-Adir-10:338.873 (Info) Mission : [New Plymouth] Sarah Thompson - Disbanded mission member(s) : [Sarah Thompson]
00-Adir-10:341.431 (Warning) Unit : EVA Suit 017 expected pulse #27795 but received 27796
00-Adir-10:341.431 (Warning) Unit : EVA Suit 018 expected pulse #27795 but received 27796

@mokun
Copy link
Member Author

mokun commented Oct 7, 2021

@bevans2000

I received this error :

00-Adir-10:338.873 (Warning) UnitManager : Unit not found 60084 type:EQUIPMENT baseID:3755
00-Adir-10:338.873 (Warning) UnitManager : Unit not found 60084 type:EQUIPMENT baseID:3755
00-Adir-10:338.873 (Warning) UnitManager : Unit not found 60084 type:EQUIPMENT baseID:3755

Can we get a printout of all the unit id and resource id via a command in the console ?

@bevans2000
Copy link
Member

Sure. I have seen something similar but rarely. It happens when the simulation adds Equipment. There is a flaw in the logic of events as well. The Unit constructor fire an event but of course the object is not fully constructed so a NPE appears in the monitor tool. That is why I logged #309 .

@bevans2000
Copy link
Member

Looking at the stack trace the question is why are we updating the Inventory if we are just getting the capacity?

@bevans2000
Copy link
Member

Sure. I have seen something similar but rarely. It happens when the simulation adds Equipment. There is a flaw in the logic of events as well. The Unit constructor fire an event but of course the object is not fully constructed so a NPE appears in the monitor tool. That is why I logged #309 .

You can enable diagnostics via the diagnostics command in the Console. This will dump to a text file whenever a Unit is created.

@bevans2000
Copy link
Member

I think this may have something to do with Equipment registering themselves in the Settlement in the constructor. Generally a quote I found is
The rules of Java state that you should never pass 'this' to another method from its constructor because the this object is not fully constructed
It is certainly a race condition somewhere. I'm going to have a play with some ideas.

@mokun
Copy link
Member Author

mokun commented Oct 7, 2021

Looking at the stack trace the question is why are we updating the Inventory if we are just getting the capacity?

Great question !

image

It was calling getUnitTotalMass(), which in turns called getUnitTotalMassCache()

I suppose enabling the cache of the mass would mean faster reading but less accurate result.

It's just too many things to decipher in the Inventory class.

@bevans2000
Copy link
Member

Yes it's a beast to understand.

@bevans2000
Copy link
Member

One big problem I see is the use of Class as a filter on getting particular types of Equipment out of the inventory. This is not good practice since it create a very strong coupling between Inventory and the Equipment subclasses. In fact I think we could drop the Box, Bag etc classes and replace with a generic Container class that use the EquipmentType as a selector. All containers essentially function the same so there is no need to have separate classes.

bevans2000 added a commit that referenced this issue Oct 7, 2021
Changes:
- Remove registering the Equipment in teh constructor as Unit is not
fully constructed
- Move the registration of new Equipment to the EquipmentFactory class
- Added an Equipment command to show used Equipment of a Unit, Person,
Vehicle & Settlement.
- Reused the minimumPath method of Exploration in the Collection
missions.

#463
@mokun
Copy link
Member Author

mokun commented Oct 7, 2021

drop the Box, Bag etc classes and replace with a generic Container class that use the EquipmentType as a selector. All containers essentially function the same so there is no need to have separate classes.

Sure.

I'm working on replacing the following method in Inventory :

	/**
	 * Checks if any of a given class of unit is in storage.
	 * 
	 * @param unitClass the unit class.
	 * @return if class of unit is in storage.
	 */
	public boolean containsUnitClass(Class<? extends Unit> unitClass) {
		boolean result = false;
		// Check if unit of class is in inventory.
		if (containsUnitClassLocal(unitClass)) {
			return true;
		}
		return result;
	}

@bevans2000
Copy link
Member

Super. .My thoughts were the methods that use the explicit subclasses like Bag make it harder to understand. Certainly increases the coupling.

The EquipmentFactory is another related bad example of using Class. So I may try and remove the dependencies of the Class references and replacement with EquiomentType. Then dropping in a generic Container will be easier.

mokun added a commit that referenced this issue Oct 7, 2021
r6262
2021-10-07

## ISSUE
1. #463

## NEW
1. Add containsEquipment(), containsVehicleType()
   and containsEVASuit() in Inventory.

## CHANGE
1. Rename containsUnitClass() containsEquipment(int typeID) and
   Rework to use EquipmentType enum.
2. Rework containsUnit()
mokun added a commit that referenced this issue Oct 7, 2021
r6263
2021-10-07

## ISSUE
1. #463

## FIX
1. Rework containsUnit() in Inventory to fix maven test.
@mokun
Copy link
Member Author

mokun commented Oct 20, 2021

In terms of transfer, we have the following scenarios:
S = Settlement
M = Mars Surface
V = Vehicle
P = Person
R = Robot
E = Equipment

For Person

Origin Destination
S M
M S
S V
V S
V M
M V

For Equipment

Origin Destination
S P
P S
V P
P V
R S
S R
R V
V R

For Vehicle

Origin Destination
S M
M S

@mokun
Copy link
Member Author

mokun commented Oct 20, 2021

But I've come across the same problem s you with no one being able to get to the surface. Did you have any luck finding out why? I think the problem is in Unit.transfer

I'm beginning to wonder if it has to do with the recent changes made in recognizing MarsSurface as an Unit inside Inventory.

@mokun
Copy link
Member Author

mokun commented Oct 20, 2021

Or it's because in retrieveUnit() in Inventory, containedUnitIDs doesn't really contain the person's instance to begin with.

So retrieveUnit() always return false.

@mokun
Copy link
Member Author

mokun commented Oct 20, 2021

oh I found the reason. It's missing an else clause in transfer() in Unit. Committing the change in a moment.

mokun added a commit that referenced this issue Oct 20, 2021
r6309
2021-10-19

## ISSUE
1. #463

## FIX
1. Modify retrieveUnit() in Inventory
   - Ensure calling setContainerUnit(null) when only retrieving
     a unit.
2. Modify transfer() in Unit.
@bevans2000
Copy link
Member

Good.

@bevans2000
Copy link
Member

In terms of transfer, we have the following scenarios: S = Settlement M = Mars Surface V = Vehicle P = Person R = Robot E = Equipment

For Person

Origin Destination
S M
M S
S V
V S
V M
M V
For Equipment

Origin Destination
S P
P S
V P
P V
R S
S R
R V
V R
For Vehicle

Origin Destination
S M
M S

So ,looking at these tables it feels like we could move the transfer to the specific Unit classes. Also we can consider Person and Vehicle the same if we use EquipmentOwner. I will commit my changes later today.

@mokun
Copy link
Member Author

mokun commented Oct 20, 2021

btw, one change to make is adding that an equipment can be transferred between two persons, between two robots and between a person and a robot.

@mokun
Copy link
Member Author

mokun commented Oct 20, 2021

could move the transfer to the specific Unit classes.

True. then it will need less if-else conditional clauses in each type of unit.

@bevans2000
Copy link
Member

I create a new issue for this #474

@bevans2000
Copy link
Member

Most things seem to be working OK. I've updated the Inventory & Equipment console commands so they work in all cases now. In particular you can use these to see the EquipmentInventory class working correctly when a Person is digging local resources. Inventory command shows the Bag contents as well as the Bag itself.

Outstanding issues:

  • There are a few "use Inventory class anymore." message appearing that need chasing down.
  • Consolidate containers is disabled for Vehicles. This needs converting to handle an EquipmentOwner. However this might be best to wait until we solve the other problems.
  • Robot needs to be converted to EquipmenetInventory like Person & Vehicle. The use of EquipmentOwner & ResourceHolder interfaces means the conversion should be more painless.
  • Should we remove the getInventory method from Unit now? Only Settlement & Building need it now but it make break a lot of code. It is the correct thing to do eventually.
  • Replace the use of Inventory in Settlement with a version of EquipmentInventory that records the demand automatically when we call 'retrieve' methods. It would then allows us to simplify fix the Consolidate containers.

I have created a new Project for the Inventory rework so we can start creating smaller Issues than the current #463 mammoth.

bevans2000 added a commit to bevans2000/mars-sim that referenced this issue Oct 20, 2021
Problem relates to logic being based on the heavyweight Inventory class
and not the smaller EquipmentOwner.

Changes:
- Console inventory command correctly handles Person, Robot, Vehicle &
Settlement now
- Change Tasks & Mission classes that do EVAs from Vehicles
- EatDrink Task changes as food comes from different classes now
- Mind stopped it removing mission members based on Coordinates.
Coordinates can only be trusted when on the MarsSurface.
- Temporarily stopped ConsolidateContainers running in Vehicles.
- DigLocal Tasks were not checking the Person was in a Settlement. Due
to other problem this allowed Vehicle people to jump out and start
digging.
mars-sim#463
bevans2000 added a commit to bevans2000/mars-sim that referenced this issue Oct 20, 2021
Changes:
- Removed ResourceHolder.hasResource method as not needed
- Fixed problem in UnitTests
- Fixed concurrent modification as People/Equipment disembark by holding
a private list copy
mars-sim#463
mokun added a commit that referenced this issue Oct 20, 2021
r6317
2021-10-20

## ISSUE
1. #463

## FIX
1. Modify canCollectMinerals() in CollectMinedMinerals
2. Modify doffEVASuit() in EnterAirlock.
3. Modify canStoreUnit() in Inventory.
4. Modify repairWithParts() in Malfunction.
mokun added a commit that referenced this issue Oct 21, 2021
r6318
2021-10-20

## ISSUE
1. #475
2. #463

## CHANGE
1. Convert various class to supporting Robot's use of
   EquipmentInventory.
2. Modify getMalfunctionables() in MalfunctionFactory.

## FIX
1. Correct isFullyUnloaded() in UnloadVehicleEVA.
2. Modify GoodsManager, Trade, TradeUtil, Delivery, and
   DeliveryUtil to quit calling Inventory for vehicle.
mokun added a commit that referenced this issue Oct 21, 2021
r6319
2021-10-20

## ISSUE
1. #475
2. #463

## FIX
1. Correct unable to carry regolith or ice or other resources
   - Modify getRemainingCarryingCapacity() in Person and Robot.
mokun added a commit that referenced this issue Oct 21, 2021
r6320
2021-10-20

## ISSUE
1. #463
2. #479

## CHANGE
1. Remove use of Inventory for MarsSurface
2. Modify transfer() in Unit.
3. Add personList and vehicleList in MarsSuface.

## FIX
1. Worker class to extend EquipmentOwner.
2. Remove calling getInventory() in Worker.
mokun added a commit that referenced this issue Oct 22, 2021
r6321
2021-10-21

NOTE: fail a lot of maven tests. Await for further debugging.

## ISSUE
1. #463
2. #479

## NEW
1. Add new methods in Settlement
   - findNumContainersOfType()
   - getVehicleTypeList()
   - getEquipmentTypeList()
   - findNumVehiclesOfType()

2. Add new methods in EquipmentInventory
   - findAllContainers()
   - addCapacity()
   - removeCapacity()
   - setResourceCapacity()
   - setResourceCapacityMap()
   - getRemainingCargoCapacity()

3. Add new methods in MicoInventory
   - addCapacity()
   - removeCapacity()

4. Add methods in ResourceHolder
   - hasItemResource()

## CHANGE
1. Remove getInventory() from Malfunctionable.
2. Building to implement Malfunctionable.
3. Revise getAmountResourceRemainingCapacity()
   in EquipmentInventory.
mokun added a commit that referenced this issue Oct 22, 2021
r6322
2021-10-21

NOTE: fail a lot of maven tests. Await for further debugging.

## ISSUE
1. #463
2. #476

## FIX
1. Add back setting the container unit when a unit takes
   the ownership of another unit.
   - Call setContainerUnit() in Person, Robot, Settlement,
     Vehicle, MarsSuface.
mokun added a commit that referenced this issue Oct 22, 2021
r6323
2021-10-21

NOTE: fail a lot of maven tests. Await for further debugging.

## ISSUE
1. #463
2. #476

## FIX
1. Comment out timePassing(pulse, getEquipmentList())
   in timePassing() of Settlement.
mokun added a commit that referenced this issue Oct 22, 2021
r6324
2021-10-21

NOTE: simulation can run normally but still need to fix
the failed maven tests.

## ISSUE
1. #463
2. #476

## FIX
1. Revise hasMaintenanceParts() in Maintenance.
mokun added a commit that referenced this issue Oct 22, 2021
r6326
2021-10-22

## ISSUE
1. #463
2. #476

## FIX
1. Correct update() in EquipmentTableModel in InventoryTabPanel.
   - Cast into EquipmentOwner
mokun added a commit that referenced this issue Oct 24, 2021
r6331
2021-10-24

## ISSUE
1. #476
2. #463

## NEW
1. Add calling fireUnitUpdate() in Unit and MicroInventory.
   - INVENTORY_RESOURCE_EVENT
   - INVENTORY_STORING_UNIT_EVENT
   - INVENTORY_RETRIEVING_UNIT_EVENT
2. Add getUnit() in Loggable.
   Q: should Unit implement Loggable ?

## FIX
1. Avoid ConcurrentModificationException in MicroInventory
   - Revise updateAmountResourceTotalMass()
2. Avoid ConcurrentModificationException in EquipmentInventory
   - Revise getAmountResourceStored() to use Iterator
3. Add capacity for initial resources in Storage.
   - Call setResourceCapacityMap()
@bevans2000
Copy link
Member

Should be close some of these Issues now? Stability seems to be returning

@mokun
Copy link
Member Author

mokun commented Oct 24, 2021

Sure. If we see any anomaly, let's open a new thread. Closing it.

@mokun mokun closed this as completed Oct 24, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants