OVERALL: 

 

Excellent introduction and overall organization.

Good set of patterns, giving a good variety of things for the user to work with.

No major objections to anything.

 

Most of my comments are to improve clarity. Here are some general points, followed by detailed comments and suggested rewrites.

 

DESCRIBING THE PATTERNS:

 

English: my pet peeve…

Please more simple English text to explain the formaleze to help reader gets the idea more easily.

 

Purpose / requirements for the patterns:

I think it will be helpful to focus more on the specific requirements that users may have for given use cases.  What are they going to do with the ontologies? Do they need inferencing? What specific inferences do they require? These things will determine in large part, the best representational choices and tradeoffs. For example, if you require a specific kind of inference, then you may be willing to make a particular assumption, which may not be strictly true, or it may be a bit hacky, but it may be useful nevertheless.

--

 

Each pattern should be introduced/motivated by the requirements in a given use case. For example, pattern 3 might be motivated by the need to derive a taxonomy automatically.

--

 

Don’t mix up the purpose/motivation  (e.g. to derive a taxonomy) of a pattern with the description of the pattern itself. It might have other uses as well.

--

 

The phrase “extend ontology” is ambiguous. Does it mean extend the core ontology for importation? In the case of pattern 3, it seems not, it seems to mean extend the ontology from pattern 2. So when I get to pattern 4, I’m really confused by what you might mean. Pattern 5 seems to extend pattern 3. All this needs to be more clear.

--

 

It is quite hard to go from the steps in the pattern to the completed examples. Better to elaborate each step, then give the full and final answer/code. Users will have to do that anyway.  This follows the convention from other notes.

 

SEPARATE the description of the patterns themselves from the examples. Let the patterns stand alone, and illustrate them with examples.

 

GENERAL GUIDELINES: there are some general points and guidelines that turn up in this [and other] notes, but which are not specific to the overt subject of the note   It would be useful to collect up such guidelines and put them in a separate note? Here are some examples form this not that do not pertain specifically to parts and whole:

 

FIGURES: It would be a big help to have some figures like in the other notes. Perhaps Natasha has spoiled us with her great figures. It is quite difficult to grasp the essential idea of a pattern by reading words.

--

 

SPECIFIC COMMENTS

 

 

“an device” à “a device”

 

Use cases: some filler text and more consistent grammar would be helpful making it read better. For example,  

 

Parts and wholes are ubiquitous, [MFU: here are 4 different use cases that we will examine:]

  1. A parts inventory for the devices made in a factory in which we want to be able to find the "explosion" of parts required (i.e. for each part we can see the sub-parts).
  2. A fault finding system for an device in which we want to progressively narrow down the functional region of the fault.
  3. An anatomy representation such as the Digital Anatomist Foundational Model of Anatomy [FMA], [MFU: in which you want to do what?]
  4. A document retrieval system, in which documents are divided into chapters, sections, paragraphs etc. (However, note that parthood, as explained in this document, does not take order into account).

The remark on use case 4 might be skipped here, and included in the main discussion?

--

 

“relations are one of”- seeming number disagreement.  Replace ‘are’ with ‘constitute’?

--

 

This sentence: “OWL, and to a lesser degree RDFS, do support sufficient machinery to express much of what one may want to represent about part-whole relations.” reads a bit awkwardly. Maybe say something like: “has sufficient machinery to do useful things…”

--

 

Reword: [style/clarity]

“An important and common requirement for the basic relation from a part to its whole that it is transitive, i.e. if A is part of B, and B is part of C, then A is part of C. OWL provides a general construct for declaring properties to be transitive. If we define a property, say partOf, to be transitive, then any reasoner conformant with OWL will draw the conclusions that both A and B are parts of C. ”

 

to

 

“An important and commonly arising requirement is for the part-whole relation to be transitive; the reasoner should be able to infer that A is a part of C from the separate facts that 1) A is a part of B and 2) B is a part of C.  There is an explicit OWL construct for stating that a property, say part of, is transitive. In the above example, that would mean any  reasoner conformant with OWL will draw the conclusion that both A is a part of C.”

--

 

[style] ‘useful to use’ à “helpful to use”  avoid redundancy.

--

 

“It is therefore often useful to use the property hierarchy to define a subproperty of hasPart that is not transitive and links each subpart just to the next level.”

 

Two points,

  1. why use hasPart here instead of partOf  which you just used? Slightly confusing, better to mention it before using it.
  2. there is no ‘property hierarchy’ per se,  to use, you create one if you want one. In this case, you have a single link in the ‘property hierarchy’, not very interesting. I suggest shorten to:

 

“It is therefore often useful to define a subproperty of hasPart that is not transitive and links each subpart just to the next level.”

--

 

“Note of course that the mere idea of a "direct" part is subjective, one may invent intermediate direct parts depending on numerous factors, or eliminate them. For example, we may choose not to represent engine as a part of cars, but rather represent all the components of engines as direct car parts. ”

 

What is an ‘intermediate direct part’?

“engine as a part of cars” number disagreement.


Reword to:

 

“Note that choosing which parts are direct, is a subjective modeling decision that needs to be made in light of your specific requirements. One may have a flat part hierarchy consisting only of direct parts, one may have a few intermediate-level parts, or have a deep and broad hierarchy of them.  For example, we may choose not to represent engine as a part of a car, but rather represent all the components of engines as direct car parts.”

--

 

The section: "Choosing whether to use partOf or hasPart” has excellent content, but might better be named:  “Inverse relations: hasPart and part of”. The current title suggests the major focus is that you will have to choose one or the other. That is only the case if you have certain inference requirements. 

 

Also, you say: “Often it is preferable to use partOf because the most common queries and class definitions are for the parts of things, e.g. the class of all parts of a car.” Then the first example, you use hasPart; you should say something about when hasPart may be preferred.

--

 

This is hard to follow in the abstract, give an example so the reader can easily see that the implication is false.

“To say that "All As are parts of some B" does not imply that "All Bs have some As as parts"

--

 

I find the following paragraph a bit confusing, particularly the phrase: ‘hypothetical entities’. What are you getting at?

 

“The subsequent patterns deal with part-whole relationships for so-called hypothetical entities. These patterns are not meant to be used with instances, rather they are intended to represent the typical components of an aggregate whole in a way that allows a system to reason about what parts a whole may have, and how they are related.”

--

 

 

PATTERN 1:

Why choose hasPart instead of partOf? Indeed, you have both when you surely mean only one.

--

 

The following mixes up terminology in a potentially confusing way:

 

“We can define hasPart as a property in RDF Schema or OWL, just as we might for the owner relation.”.

 

I suggest shortening to:

“We can define hasPart as a property in RDF Schema or OWL, just as we might define an ownerOf property.”

 

or elaborating to:

 

“We can define hasPart as a property in RDF Schema or OWL representing the link between a whole and its part, just as we might define a property called owner to represent the link between an object and its owner.”

--

 

change: “except as noted above to make a sub-property for direct parts”

 

 to

“except  to make a sub-property for direct parts (as noted above)”

--

 

Naming: “partOf_directly” vs. “directPartOf

You might comment on the reasons for having multiple conventions, one with a relation ending with ‘of’ and the other not doing so. Lurking, is a sub-convention for special cases so the main relation always is in the beginning of the name, which is convenient when seeing alpha ordered relations. Perhaps this goes on the list of naming conventions someone is compiling?

--

 

[clarity] Shorten the following:

:While RDFS allows one to define domain and range for properties, it is not recommended to do so in this case. The partOf relation is sufficiently general that just about anything can have a part or be a part.”

 

to

 

“This is all you need to do. Because just about anything can have a part or be a part, we do not recommend using the domain and range constraints that RDFS supports.”

--

 

[clarity] Step 4 is confusing, it should be two separate procedures, depending on whether you do or do not choose to represent the inverses. What is the reader to do if they follow your advice and don’t model it with inverses?  It is surprising and potentially confusing to the reader that you recommend against inverses, then give an example that uses them. 

 

Also, why say not to use domain/range constraints with RDFS, but then do what [seemingly] amounts to the same thing with OWL? 

 

Also, it would be helpful to give common English descriptions for what you are specifying using the allValues construct as instructed in the 2nd and 3rd bullets.

 

After reading the example, my best guess is (in not very nice wording):

Identify all the classes of all parts of the whole.

Create a restriction that states that every part of every member of the class of wholes [e.g. car]  is an instance of one of the part classes.

 

Say why you want to do this? What help is it? Why not just attach the parts to the wholes and be done with it?

--

 

[clarity/simplicity]

“To begin with, let's set up a special importable ontology for the simple family of part relations discussed here, as these will be reused in subsequent examples.”

 

with

 

“To begin with, we set up a special ontology for the simple family of part relations discussed here. It will be imported and reused in subsequent examples.”

--

 

[clarity/simplicity]

Replace “using OWL, but in order” with “using OWL. In order”

--

 

I don’t yet get what you are going to do here using restrictions, or why:

“we can define some classes of things with parts and then restrict specific classes to have the appropriate values”

--

 

‘below example’ à ‘example below’

--

 

Replace: ‘namespace nickname’ with ‘nick-namespace’ [just kidding]

 

Maybe replace: ‘give it a namespace nickname’ with ‘give the namespace a nickname’.

--

 

I’m trying to come up with English to help me understand the restriction:

Class(Car partial 
  restriction(part:hasPart allValuesFrom(unionOf(Wheel Engine Headlight))))

 

A car is a subclass of the class of those things, all of whose parts are one of: engine, headlight, wheel.

i.e. Every part of every car is either an engine, a headlight or a wheel.

 

[Aside: I had to look at the RDF-XML which is ugly as sin, to understand the meaning of the abstract syntax that I’m unfamiliar with].

 

In step 4 it says:

“Also, there should be restrictions for each of the following, as described above:

·  define allValuesFrom restriction on the property partOf for all classes of things that are parts to the classes of things they are parts of

·  define allValuesFrom restriction for the inverse property hasPart”

 

I only see one, and am not even sure which one.

--

 

Discussion:

 

Replace: “the following patterns” with “patterns 2-4” to be more explicit.

--

 

“A common modeling pitfall in general when representing parts is to create a class that is the superclass of all the possible classes that can be car parts, and use this class instead of the union class in the restriction on hasPart for Cars. It is important to realize that making, e.g. Engine a subclass of e.g. CarPart means that all engines are car parts - which is simply not true (engines can be parts of boats, planes, generators, etc.).”

 

Replace: “A common modeling pitfall in general”  with “A common mistake”

Replace: “that can be car parts” with “that can be car parts, (e.g. CarPart).

 

Also, using Carpart by itself is not wrong, you could say make CarEngine a subclass of CarPart, and BoatEngine a subclass of BoatPart.  I suggest reword this paragraph to:

 

“A common pitfall when representing parts is to create a class that is the superclass of all the possible classes that can be car parts (e.g. CarPart), and use this class instead of the union class in the restriction on hasPart for Cars.  By itself, this is not wrong. However, if you then make e.g. Engine a subclass of CarPart that means that all engines are car parts - which is simply not true (engines can be parts of boats, planes, generators, etc.). You could instead make CarEngine a subclass of CarPart, and BoatEngine a subclass of BoatPart etc. The need to do this is avoided if you create the union class as described above.”

--

 

PATTERN 2

 

Step 2: this is not the same advice as in pattern 1, although it is consistent with the note about inverses – this needs consistency throughout.

 

Step 5 refers to ‘this example’, it should probably be ‘the example below for this pattern’ or similar.

--

 

For each step, please have a simple English example so reader gets the idea more easily. I can't really grasp it right away, having to look at examples and then look back again to the pattern description.

--

 

It seems rather late on to start talking about inferences for the first time. I recommend putting some discussion of this forward to the beginning, in the use cases.

 

It is quite hard to go from the 5 steps of the pattern to the completed example. Better to elaborate each step, then give the full and final answer/code. Users will have to do that anyway.  For example:

 

  1. Import the partOf relation ontology defined above.
  2. Choose whether to use the partOf or hasPart relation as the basic relation amongst classes. If in doubt, choose partOf.
  3. Express the part-whole relations amongst individuals using hasValue() with partOf_directly.
    e.g. ??
  4. Express the part-whole relations amongst classes using someValuesFrom() with partOf_directly.
    e.g. Every crankcase is part of at least one engine
  5. If there are any universal (allValuesFrom) constraints, add those.
    e.g. ?? Every crankcase is part of only engines.?? [MFU: I never remember this…]

 

# Step 1

Namespace(part = <http://www.w3.org/2001/sw/BestPractices/OEP/SimplePartWhole/part.owl#>)
 
Ontology( <http://www.w3.org/2001/sw/BestPractices/OEP/SimplePartWhole/example2.owl>
 Annotation( owl:imports <http://www.w3.org/2001/sw/BestPractices/OEP/SimplePartWhole/part.owl>)
 

# Step 2

In this example, we use both relations, noting that for large examples one must make a choice. [remove this text from the steps above, separate the steps from the example].

 

# Step 3

Huh? There is no hasValue in this example.

 

# Step 4

Class(Car partial)
 Class(Engine partial 
  restriction(part:partOf_directly someValuesFrom(Car)))
 Class(Carburetor partial 
restriction(part:partOf_directly someValuesFrom(Engine)))

# The class Crankcase is a subclass of the class of all things that are direct parts of at least one engine. i.e. every crankcase is part of at least one engine.

 Class(Crankcase partial 
  restriction(part:partOf_directly someValuesFrom(Engine)))
 Class(Headlight partial 
  restriction(part:partOf_directly someValuesFrom(Car)))
 Class(HeadlightBulb partial 
  restriction(part:partOf_directly someValuesFrom(Headlight)))
 Class(Reflector partial 
  restriction(part:partOf_directly someValuesFrom(Headlight)))
 Class(Wheel partial 
  restriction(part:partOf_directly someValuesFrom(Car)))
)

 

# Step 5

In this case there are none.

 

--

 

Discussion Pattern 2:

 

Replace:

       a crankcase is part of at least one engine ” with
“every crankcase is part of at least one engine ”

--

 

“We may be tempted to add a cardinality restriction (e.g. maxCardinality 1) on partOf to the definition of crankcase, but this would be a mistake; since partOf is transitive, a crankcase is also part of the car the engine is part of.”

 

Please spell out why this is an error? What false inference would be drawn?

Anyway, why would anyone be tempted to put the cardinality constraint on the partOf  relation, not partOfDirectly (as you note below). It might be better to talk about the semantically sensible thing first, then later note that it is incorrect to add a cardinality constraint on partOf.

--

 

“In general it is best to avoid placing restrictions (including range restrictions) on transitive properties at all.”

 

This is a general rule that is relevant here, and also true for any modeling context. Such rules that are more general than the note they are found in, should be collected and put in one place where general guidelines may be found.

--

 

The following paragraph has great content, but is too brief for the reader to take away anything much that is both specific and useful as a guideline:

“In this case, adding a cardinality restriction on all the partOf_directly properties would significantly increase the amount of information handed to a reasoner. One must consider precisely what the ontology will be used for to determine which is more important (enforcing semantic constraints vs. classification). The examples in this note are aimed primarily at use-cases in which no instances of the classes are present.”

 

It begs the following questions:

--

 

Re: QCRs: please give a punch line here, that summarizes the key points about QCRs.

--

I find the following paragraph to be very important, but slightly confusing.

 

“When considering restrictions on the partOf_directly property for different kinds of parts, the issue of using a universal (owl:allValuesFrom) vs. an existential restriction arises. Many different kinds of things have engines (boats, planes, etc.), and in fact even car engines can exist without being part of a car. This indicates that, ontologically, the existential restriction is simply not true. However, what we are trying to capture here is, as mentioned above, not a schema for specifying actual concrete parts, but the intuitive composition of cars that corresponds to statements in English like, "Cars are made of engines, wheels, headlights, ..." 

 

Please give a simple English sentence/example for the allValuesFrom and someValuesFrom case to make it easy to understand.

 

Also, the general point may be more clear if you stated up front what kinds of requirements and inferences you wanted from your part-whole representation scheme.  You can then examine the tradeoffs and say something like: if you want these inferences, here is a way to proceed. However, it makes some assumptions that in general don’t hold, but that give you the right effect for your problem. It is not an issue if you are making a local application, however it will be an issue if others want to share your ontology.

[See general comment at top of review]

--

 

PATTERN 3:

 

Motivate the pattern first before saying what it is. Don’t mix up the purpose/motivation  (e.g. to derive a taxonomy) of a pattern with the description of the pattern itself. It might have other uses as well.

--

 

CarPart_directly is a grammatically misleading name. It suggests action, since it is an adverb. CarPart_direct would be an improvement. For sheer readability, direct_CarPart would be better still.

 

Please say what the class CarPart-directly means, in English. e.g.

CarPart == anything that is the part of any car (possibly indirectly)

CarPartDirectly == anything that is a direct part of a car.

 

Aside: these are special kinds of classes that are defined on the basis of what participates in a given role for a given relation.  I have called these role-defined classes, and they are important, turning up in various circumstances. Might it be worth mentioning? Might they go into a general note that cuts across the many different notes?

--

 

Pattern 3 seems more like a variant or an extension of Pattern 2, than a different pattern.

In either case, the description of the pattern might be improved by being more explicit. e.g.

 

Here is a way that the Pattern 3 section could start off:

replace:

===

Extend ontology with classes of parts for each level in the part hierarchy (e.g. Car Parts, Engine Parts, etc.), in such a way that a taxonomy can be derived automatically.

===

with something like:

 

===

The next pattern extends pattern 2 and is useful when there is a need to automatically derive a taxonomy of kinds of parts.

 

Step 1: repeat steps 1-5 of pattern 2

Step 2: Extend the ontology by adding part classes for each kind of part in the part hierarchy (e.g. Car Parts, Engine Parts, etc.).

===

 

Also, the explanation could be elaborated a bit to be more clear, I consider replacing:

===

A classifier could then infer that CarPart_directly subsumes Engine, Headlight, Wheel and that CarPart subsumes CarPart_directly, Crankcase, Carburetor, HeadlightBulb, Reflector. You can see this yourself by loading this simple ontology into Protégé and classifying the ontology.

This is only a first step towards a hierarchy of car parts, in that it is just a simple list. To get a part hierarchy it is necessary to systematically to define a class for the parts of each part, e.g.

 Class(EnginePart complete 
  restriction(part:partOf someValuesFrom(ex2:Engine)))
 Class(HeadlightPart complete 
  restriction(part:partOf someValuesFrom(ex2:Headlight)))

If all are defined in this way we get a hierarchy from the classifier (ignoring CarPart_directly):

CarPart
  Engine
  EnginePart
    Crankcase
    Carburetor
  Headlight
  HeadlightPart
    HeadlightBulb
    Reflector
  Wheel

===

 with something like

===

A classifier can then infer that CarPart_directly subsumes all classes that correspond to direct parts of the car, specifically: Engine, Headlight, and Wheel. It can also infer that CarPart subsumes all classes that correspond to any part of a car, or categories of parts of cars; specifically: Crankcase, Carburetor, HeadlightBulb, Reflector and CarPart_directly.  You can see this yourself by loading this simple ontology into Protégé and classifying the ontology.

This is only a first step towards a hierarchy of car parts, in that it is just a simple list. It does not capture the fact that a crankcase is part of an engine. To get a complete part hierarchy it is necessary to systematically to define a class for all the kinds of parts. e.g.

 Class(EnginePart complete 
restriction(part:partOf someValuesFrom(ex2:Engine)))

[… add another entry here for crank case?]

 Class(HeadlightPart complete 
  restriction(part:partOf someValuesFrom(ex2:Headlight)))

If all are defined in this way we get a hierarchy from the classifier (ignoring CarPart_directly):

CarPart
  Engine
  EnginePart
    Crankcase
    Carburetor
  Headlight
  HeadlightPart
    HeadlightBulb
    Reflector
  Wheel

===

--

 

Why do we have to ignore CarPart_directly? Where would it fit into the hierarchy in the general case? It seems that this is a limited subset of the actual code. What exactly is left out? What is simplified? I presume the full code is available? I could look to see – better also to state it explicitly, one way or the other.

--

 

For various reasons, I propose the following version to replace the current discussion section with a new version below:

Most of the content is the same, but I have used a different ‘story’ to include it.

===

This approach achieves the goal of letting the automated reasoner will do the work of building a taxonomy of different kinds of parts, that reflects the explicitly defined part hierarchy.   This alleviates the need to make explicit statements like the following to declare that Headlight (or any other part) is a subclass of CarPart: 

 Class(Headlight partial CarPart
  restriction(part:partOf someValuesFrom(ex2:Car)))

Instead the reasoner infers this information, resulting in a more compact representation of the ontology. It has been argued that such an approach increases maintainability and modularity [R-NORM].

The inference works properly with the existential restrictions on the direct part properties as shown. To get a classifier to infer the above hierarchy using universal restrictions on the partOf_direct property in the first pattern, there would also have to be minimum cardinality restrictions on the property.  This is one reason that existential restrictions are often chosen in these circumstances.

[MFU comment: this seems odd; I would think that choosing between existential and universal should be based on what is most accurate and complete, or what is necessary to get the right inferencing, not whether or not cardinality constraints are necessary. And, what is the problem with having cardinality constraints? Is it a matter of convenience? Correctness? efficiency? Does the argument above about problems with cardinality constraints apply here?]

Note that we have chosen this representation primarily to facilitate the use of inference to produce a part class taxonomy from an explicit representation of a part whole hierarchy. This approach seems harmless at first glance, but there are some caveats.  What this representation is literally saying is that all engines are car parts, and that all car parts are parts of actual cars.  Strictly, this is not true. Some engines are boat engines, and an engine for a 1969 Porsche 911E is generally considered a "car part" regardless of whether or not it is in a car (it may be for sale).

The right choice depends on what is needed in a particular situation. To the extent that the following are true, this approach may be the right one to meet your needs:

·       there is a pressing need to have the kind of inferencing required

·       if you have a single local application, and the assumptions are clearly stated (even if strictly false). 

·       if the scope of the application only includes cars and car parts, in which case boat engines are irrelevant.

·       you don’t need to distinguish between being an actual part of an actual car, vs. or being a part intended for use in some [unspecified] car

·       if there is no need to interoperate, or if all interoperating applications make the same assumption.

Conversely, it may be the wrong choice if the above things are not true. Of particular importance is the case when you wish for your ontology to be re-used for a wide variety of contexts and shared in a broader community. That is when making assumptions that are strictly false can create problems.

===

 

I chose to throw out the contentious and confusion-inducing statement:

“Recall again, however, that the intent here is to create an intuitive model of what "whole cars" are made of, not a schema for concrete instances of these classes.”

Is there anything that you (ChrisW) intended by this statement that still needs to go back in?

--

 

PATTERN 4:

You say: “Such hierarchies do need to be recreated in situations that obey the rule "A fault of the part is a kind of fault of the whole", but what do you mean by “such hierarchies”?

--

You don’t say that the hierarchy of Fault Classes is induced/inferred automatically, in a very analogous way to how the part classes are in the prior pattern(s).

Here is a suggested rewrite of the first part of this section, everything up to the example.

===

This pattern is intended to facilitate reasoning about faults in the context of parts. For example, you can call for assistance with a fault in your car if your crankcase is damaged; this is because a crankcase is part of your car.  In general, we wish to have the reasoner conclude that a fault in a part is also a fault in the whole.

To achieve the required reasoning we are going to create a set of fault classes, one for each whole and every kind of part.  For example: Fault in Car, Fault in Crankcase. We want the reasoner to infer the hierarchy of Fault Classes, based on the partOf relationships. Specifically, because a crankcase is part of a car, the class Fault in Crankcase should be inferred to be a subclass of Fault in Car.  The steps to implement this pattern are:

 

Step 1: Import the core ontology

Step 2: Extend the ontology by adding a fault class for each part. A given fault class is the class of all faults that occur in the given part of the whole.

 

Before we illustrate this pattern, we first highlight the difference between the part-whole hierarchy with the subclass hierarchy. One is generated by the partOf property, and the other by the subClassOf property. They are easily confused, because in many library and related applications, part-whole and subclass relations are deliberately conflated into a single "broader than / narrower than" axis[MFU: not to mention pattern 3 above creates a subclass hierarchy that mirrors the part hierarchy, also potentially confusing]. For example consider the following:

Vehicle

  Car

    Engine

      Crankcase

        Aluminum Crankcase

"Car" is a kind of "Vehicle", but "Engine" is a part of a "Car", "Crankcase" is a part of an "Engine", but "Aluminum Crankcase" is a kind of "Crankcase". Such hierarchies serve well for navigation, however they are conflating the two relations (partOf and subClassOf). Statements about "all vehicles" do not necessarily, or even probably, hold for "all engines".

===

PATTERN 5:

 

Replace:

“each element is part of one other element”

with

“each element is part of exactly one other element”

CONSIDERATIONS:

It would be a good idea to illustrate the 2nd bullet.

Also, it might be a good idea here to review some of the above tradeoffs, especially with respect to making ontologically ‘wrong’ modeling decisions.