Closed drewcdisc closed 1 year ago
The Timeline class is used to compose all of the sequence elements related to the SoA.
We will use this class to collect the entries, exits and sequenced timepoints that will be pointed to by objects such as encounters and activities.
The idea here is to provide a seqencing perspective of the activities, events and subject encounters along with the rules used to define the schedule and its progression.
Usual id for the instance
A textual description of the timeline. There will likely be numerous timelines in a study and this field provides the context for the particular timeline.
It makes sense to have object references to SoA structure objects (timepoint, entry, exit). This should be the highest level in the JSON payload to attach the object details. Below this level (such as pointers between timepoints) references will be ID references to avoid duplication. The timeline entry and exit don't seem to be as important in the composition of a timeline, if we reference "timelines" from higher in the class hierarchy. If every timeline has a discrete entry and exit point, then why do we really need seperate, referenceable Entry and Exit classes. This could simply be just some useful attribution in a timeline.
Example, if I'm grabbing timeline named "base timeline for this study", and I grab the timeline, why do I need to deferefeence the entry? It seems as if I would just ask for the first timepoint, ordinally. Maybe entry is an attribute of a timepoint? Just my thoughts.
Ditto from above for exit.
At this point, this is an unordered list of timepoints. We might consider more encapsulation by creating a timepointSequence wrapper.
Are cycles really discrete timelines that provide some type of iteration mechanism?
Do we force the design to break cyclic seqences off from strictly linear sequences? Or, do we add complexity to the definition of a timeline
Maybe a cycle is just attached to an existing timeline defines a time loop? Remember, these aren't your typical "timeines"...they are more of a seqencical structuring of activities, conditions and encounters. So, it's quite logical to want to repeat a portion of a longer sequence to meet a particular condition. I must noodle on this...
Ok, my initial thoughts lead to a sentinel that observes a timeline and has a cycle start and end maybe... and there must be an iteration condition (iterate? Yes, No).
A timepoint of type Cycle with a relationship that points to a cycle start (another timepoint) and with a condition attached that determines progression? This could muddy the timepoint and it's truly polymorphic while currently the Branch vs Node types don't really have anly overloaded behaviors (yet).
However, I'm still for it because how is a cycle that much different than a branch except it points to something upstream as opposed to downstream?
It seems plausible to encapsulate starts, ends and loops in the actual timeline class itself.
The Timepoint class is used to link activities and encounters to a schedule timeline.
Usual instance id
The textual representation of the timepoint.
Denotes the type timepoint object added to the timeline. The value can be either a node or a branch. A branch being used to link alternate or sub-timelines to an existing timeline.
The condition that may be associated with the timepoint, if the timepoint is of type branch (according to the presentation material).
Even though a condition could or should be re-used across multiple timepoints and/or entries this reference should be an object reference as there would be no other object reference available to ensure inclusion in the JSON payload (to my understanding)
Unsure of the nescessity of this id reference to an actual Exit class.
It seems to make sense to associate an exit condition and maybe an exit flag to a timepoint.
What attributes are required to be associated with an Exit that should be solely contained in an Exit class? Maybe just saying a timepoint is a final timepoint is just as intuitive?
Must assume this is an object reference as no other references exist in the model except for Encounter and that would not necessarily be the same timepoint being referenced, so no duplication will likely exist.
This could be considered an attribute of the timepoint because I'm not sure that the timing has any value outside of its inclusion in the timepoint data (except for maybe...reuse?)
when referencing objects from the timeline, it's important to use id references because the API JSON payload would result in duplicate expressions of objects pointing to the timeline. This assumption should be asserted.
All of these fields below should be defined as relationships in the CT.
In particular for pointers between timepoints, it seems to me that there should be some clear understanding that only a Branch type timepoint is capable of pointing to more than one previous or next timepoint. Am I misunderstanding the the use of the type attribute?
I'm somewhat confused as to why an encounter has multiple touchpoints in the timeline, but I haven't heard of a broad set of use cases for traversal of the timeline.
You can get to a timepoint from an encounter via a timing. You then have a circular reference from the timing via the timepoint. There is potential for these to be out of sync as well, correct?
This is the only way to associate activities with timepoints, as we've decided that the cardinality from timepoint to activities is one to many, correct?
I'm still waffling on this entry concept. We know the first timepoint in any sequence simply because it has no pointer to a predecessor. If a timepoint can be a node or a branch, why can't it also be an entry timepoint or an exit timepoint. Polymorphism has been problematic, however, much like BC data, it is more elegant that trying to provide solid semantics to differentiate things that are ideally seen as similar yet unique among themselves. Like managing anything as a category without actually referencing the category (i.e. StudyData).
The Timing class is used to relate timepoints. In graph, this information would likely sit on relationship that exists between timepoints. Timepoints can have relationship context more sophisitcated the previous and next. This is where that information is captured.
Usual instance id
Code values that describe the type of timing. Valid values include Before, After and Absolute.
According to the presentation, the value will be provide further context based on the type of the timing.
For example, if the timing type is absolute then maybe something like "first dose, day 0" and if the type is Before it could be "1 day before x".
Code values that describe the timing relative to the associated timepoint, I believe. Somewhat unsure here.
Values are typical of gant task relationship dependencies. They are: StartToStart, StartToEnd, EndToEnd and EndToStart.
Defines window of time associated with the timing. This seems like slack in a project timeline.
Example value could be 2 hour window. In a standard task sequence that sounds like "2 hours of slack" in the schedule to accomplish associated activities, etc... Is this correct?
"A guide that governs the allocation of subjects to operational options at a discrete decision point or branch (e.g., assignment to a particular arm, discontinuation) within a clinical trial plan." <<< from the existing TransitionRule class.
We have deprecated the TransitionRule class and replaced it with condition. Now...the question is...is the above description appropriate for a condition?
If not, I believe that deprecating the TransitionRule was a mistake and that we will likely need to change the design to provide for both Condition and TransitionRule classes and their assoiated logic.
Usual instance id
The textual representation of the transition rule. 'Nuff said.
Not much to this class. Doesn't seem like enough information to reside in its own class definition.
Are we defining this class strictly for reuse in timelines, like codes?
Still is hard to argue that it's way better as a class reference than a string field, since the conditionId is the only thing we're associating with the class except for description.
The answer must be that we are not done defining the class.
Condition
General
"A guide that governs the allocation of subjects to operational options at a discrete decision point or branch (e.g., assignment to a particular arm, discontinuation) within a clinical trial plan." <<< from the existing TransitionRule class.
We have deprecated the TransitionRule class and replaced it with condition. Now...the question is...is the above description appropriate for a condition?
If not, I believe that deprecating the TransitionRule was a mistake and that we will likely need to change the design to provide for both Condition and TransitionRule classes and their assoiated logic.
private final String conditionId;
Usual instance id
private String conditionDescription;
The textual representation of the transition rule. 'Nuff said.
Notes
Not much to this class. Doesn't seem like enough information to reside in its own class definition.
Are we defining this class strictly for reuse in timelines, like codes?
Still is hard to argue that it's way better as a class reference than a string field, since the conditionId is the only thing we're associating with the class except for description.
The answer must be that we are not done defining the class.
@cupkes I have pondered whether or not TransitionRule and Condition are one class or two. Happy to have both. I can see condition becoming more "machine readable" before transition rule because transition rule is a human readable form. So for now, I think the best is to keep separate
Extracted from @cupkes notes
Are cycles really discrete timelines that provide some type of iteration mechanism?
Do we force the design to break cyclic seqences off from strictly linear sequences? Or, do we add complexity to the definition of a timeline
Maybe a cycle is just attached to an existing timeline defines a time loop? Remember, these aren't your typical "timeines"...they are more of a seqencical structuring of activities, conditions and encounters. So, it's quite logical to want to repeat a portion of a longer sequence to meet a particular condition. I must noodle on this...
Ok, my initial thoughts lead to a sentinel that observes a timeline and has a cycle start and end maybe... and there must be an iteration condition (iterate? Yes, No).
A timepoint of type Cycle with a relationship that points to a cycle start (another timepoint) and with a condition attached that determines progression? This could muddy the timepoint and it's truly polymorphic while currently the Branch vs Node types don't really have anly overloaded behaviors (yet).
However, I'm still for it because how is a cycle that much different than a branch except it points to something upstream as opposed to downstream?
It seems plausible to encapsulate starts, ends and loops in the actual timeline class itself.
Cycles
Extracted from above from @cupkes notes
Are cycles really discrete timelines that provide some type of iteration mechanism?
Do we force the design to break cyclic seqences off from strictly linear sequences? Or, do we add complexity to the definition of a timeline
Maybe a cycle is just attached to an existing timeline defines a time loop? Remember, these aren't your typical "timeines"...they are more of a seqencical structuring of activities, conditions and encounters. So, it's quite logical to want to repeat a portion of a longer sequence to meet a particular condition. I must noodle on this...
Ok, my initial thoughts lead to a sentinel that observes a timeline and has a cycle start and end maybe... and there must be an iteration condition (iterate? Yes, No).
A timepoint of type Cycle with a relationship that points to a cycle start (another timepoint) and with a condition attached that determines progression? This could muddy the timepoint and it's truly polymorphic while currently the Branch vs Node types don't really have anly overloaded behaviors (yet).
However, I'm still for it because how is a cycle that much different than a branch except it points to something upstream as opposed to downstream?
It seems plausible to encapsulate starts, ends and loops in the actual timeline class itself.
Tried to keep the building blocks simple and build "patterns" to build the logic. So we have a start, end, timepoint and decision (cycle/branch) nodes types. Leave start and end out of it for the moment, more connected with timelines.
We have timepoint and "branch". Leaning towards keeping them distinct node types or class / sub-class, dont really mind. A branch will never connect to an activity, another timeline or an encounter. Timepoint will.
Updates this sketch to highlight the "cycle" pattern. Note that the timepoint could link to another timeline (reuse of a profile to example) or to an a set of activities, that is independent of the cycle management.
Timeline Entry & Exit
General
The Timeline class is used to compose all of the sequence elements related to the SoA.
We will use this class to collect the entries, exits and sequenced timepoints that will be pointed to by objects such as encounters and activities.
The idea here is to provide a seqencing perspective of the activities, events and subject encounters along with the rules used to define the schedule and its progression.
private final String timelineId;
Usual id for the instance
private String timelineDescription;
A textual description of the timeline. There will likely be numerous timelines in a study and this field provides the context for the particular timeline.
private Entry timelineEntry;
It makes sense to have object references to SoA structure objects (timepoint, entry, exit). This should be the highest level in the JSON payload to attach the object details. Below this level (such as pointers between timepoints) references will be ID references to avoid duplication. The timeline entry and exit don't seem to be as important in the composition of a timeline, if we reference "timelines" from higher in the class hierarchy. If every timeline has a discrete entry and exit point, then why do we really need seperate, referenceable Entry and Exit classes. This could simply be just some useful attribution in a timeline.
Example, if I'm grabbing timeline named "base timeline for this study", and I grab the timeline, why do I need to deferefeence the entry? It seems as if I would just ask for the first timepoint, ordinally. Maybe entry is an attribute of a timepoint? Just my thoughts.
private Exit timelineExit;
Ditto from above for exit.
private List timelineTimepoints;
At this point, this is an unordered list of timepoints. We might consider more encapsulation by creating a timepointSequence wrapper.
General
Are cycles really discrete timelines that provide some type of iteration mechanism?
Do we force the design to break cyclic seqences off from strictly linear sequences? Or, do we add complexity to the definition of a timeline
Maybe a cycle is just attached to an existing timeline defines a time loop? Remember, these aren't your typical "timeines"...they are more of a seqencical structuring of activities, conditions and encounters. So, it's quite logical to want to repeat a portion of a longer sequence to meet a particular condition. I must noodle on this...
Ok, my initial thoughts lead to a sentinel that observes a timeline and has a cycle start and end maybe... and there must be an iteration condition (iterate? Yes, No).
A timepoint of type Cycle with a relationship that points to a cycle start (another timepoint) and with a condition attached that determines progression? This could muddy the timepoint and it's truly polymorphic while currently the Branch vs Node types don't really have anly overloaded behaviors (yet).
However, I'm still for it because how is a cycle that much different than a branch except it points to something upstream as opposed to downstream?
It seems plausible to encapsulate starts, ends and loops in the actual timeline class itself.
With respect to Entry, Exit, Timepoiint and Timeline. Originally I did not have timeline in the model. Only when you look at the JSON packaging do you sense it is useful. So I think we can promote Entry and Exit to timeline and have an array / list of timepoints.
Entry as a notion is needed, we need an entry condition for the timeline. We will generally have a "main" timeline for the study with a condition for entry such as "individual identified as potential subject". They go through informed consent, screening etc etc and pass into the study should everything go ok. This is where the bulk of what we think of as the SoA today sits. We then have other timelines for unscheduled events (e.g. Adverse Events). So timelines are akin to event driven programming, event, resulting processing. We always need one timeline, the main study logic. How we display these, separately, together etc is not a model issue, presentation / tooling problem.
Exit is not so much needed now. However, HL7 FHIR SoA has exit "logic" and I sense, in the future, we will need such. Does a subject continue or is this subject leaves the study type stuff. So I am tempted to have a placeholder at least for the exit
For @cupkes
private Code timepointType
Denotes the type timepoint object added to the timeline. The value can be either a node or a branch. A branch being used to link alternate or sub-timelines to an existing timeline.
We can use a type or class / sub class mechanism
private Condition timepointCondition
Even though a condition could or should be re-used across multiple timepoints and/or entries this reference should be an object reference as there would be no other object reference available to ensure inclusion in the JSON payload (to my > understanding)
Agree
private String timepointExitId
Unsure of the nescessity of this id reference to an actual Exit class.
It seems to make sense to associate an exit condition and maybe an exit flag to a timepoint.
What attributes are required to be associated with an Exit that should be solely contained in an Exit class? Maybe just saying a timepoint is a final timepoint is just as intuitive?
Just thinking longer term, may have different types of exit, subject exits study, subject stays on study. Placeholder for the future
private Timing timepointScheduledAt
Must assume this is an object reference as no other references exist in the model except for Encounter and that would not necessarily be the same timepoint being referenced, so no duplication will likely exist.
This could be considered an attribute of the timepoint because I'm not sure that the timing has any value outside of its inclusion in the timepoint data (except for maybe...reuse?)
It would be a complex type, I assume any multi attribute entity is a separate class a la Code
private List
nextTimepointIds when referencing objects from the timeline, it's important to use id references because the API JSON payload would result in duplicate expressions of objects pointing to the timeline. This assumption should be asserted.
All of these fields below should be defined as relationships in the CT.
In particular for pointers between timepoints, it seems to me that there should be some clear understanding that only a Branch type timepoint is capable of pointing to more than one previous or next timepoint. Am I misunderstanding the the use of the type attribute?
I was in two minds about a "next" pointer, an array would do the job. Mikkel made the point they maiintain it so left in for the moment. More of an aid to displaying the timeline
private String timepointEncounterId
I'm somewhat confused as to why an encounter has multiple touchpoints in the timeline, but I haven't heard of a broad set of use cases for traversal of the timeline.
You can get to a timepoint from an encounter via a timing. You then have a circular reference from the timing via the timepoint. There is potential for these to be out of sync as well, correct?
The Encounter -> timing is for an encounter window. I would like to see if we can keep all the timing within one place, namely timing. Now, if we had a weird visit, do something, wait 4 hours then do something else. Designers of the study consider this a single visit / encounter. We create two timepoints for the two distinct bits of logic and a nice precise timing node handling the four hours (in the past this was a textual footnote in a PDF). We associate both timepoints with the encounter. OK cool. But we also want a window on the encounter, This relationship allows the encounter to refer to the timing node with its window, probably the timing associated with the first of the two timepoints. Make sense?
Have a look at the examples in the diagram
private List
timepointActivityIds This is the only way to associate activities with timepoints, as we've decided that the cardinality from timepoint to activities is one to many, correct?
Yes, unless we find a good reason not to!
private String timepointEntryId
I'm still waffling on this entry concept. We know the first timepoint in any sequence simply because it has no pointer to a predecessor. If a timepoint can be a node or a branch, why can't it also be an entry timepoint or an exit timepoint. Polymorphism has been problematic, however, much like BC data, it is more elegant that trying to provide solid semantics to differentiate things that are ideally seen as similar yet unique among themselves. Like managing anything as a category without actually referencing the category (i.e. StudyData).
See other comments
private String timingValue According to the presentation, the value will be provide further context based on the type of the timing.
For example, if the timing type is absolute then maybe something like "first dose, day 0" and if the type is Before it could be "1 day before x".
The 1 day before X is 1 day and point to X. Also want to allow for text but also ISO 8601 encoded values
private Code timingRelativeToFrom Code values that describe the timing relative to the associated timepoint, I believe. Somewhat unsure here.
Values are typical of gant task relationship dependencies. They are: StartToStart, StartToEnd, EndToEnd and EndToStart.
Most of the time it would be end to start (from the end of previous to start). But sometimes we need precision, 5 mins after end of previous do this (end to start)
private String timingWindow Defines window of time associated with the timing. This seems like slack in a project timeline.
Example value could be 2 hour window. In a standard task sequence that sounds like "2 hours of slack" in the schedule to accomplish associated activities, etc... Is this correct?
We see the subject every 4 weeks, plus or minus 3 days. Encounter window is -3 .. +3 days. We need to be careful of units, i.e. -1 hour .. +2 days. Some windows are minutes, some are days. Sometimes windows not permitted, dose drug, take BP for next hour every 5 mins (but that is more of a profile). We need windows for encounters but also for other reasons. so want to keep flexible.
UML from @cupkes from old thread/ticket
Latest sketch taking into account questions, comment and last week's discussion
fyi @cupkes @ggasg
Here's the new diagram, but I am not finished. I have a couple of things that I think need to be changed.
Regarding TimeLine Entry as a new class name. I feel that TimelineEntry is confusing. If there is a timeline entry, then there must be a timeline. Yet, in the diagram, the two concepts are conflated into the TimelineEntry. I suggest keeping Timeline and adding entry attribution as condition and timepoint references.
There is an ongoing concept of entry because of a need for a condition. I propose that the entry itself is not an actual object, or independent concept. Instead I believe that every timeline has an entry condition and that the timepoints associated with the timeline are all post "condition met" timepoints. Do we ever have timepoints that aren't collected in a timeline? I argue that all timepoints exist in timelines, and therefore, for the first timeline, there can't be any previous "timepoints" that could point to conditions. "which came first, the timepoint or the timeline?" kind of thing. So, to solve this, I add a pointer to a condition in the timeline. This condition is simply used to record the "why" of the timeline, from what I can glean so far.
private Condition entryCondition;
If the timeline was due to a condition that was met for traversal from a previous timepoint, then we should have a handle to that timepoint.
private String entryTimepointId;
// In the diagram, this is timelineEntryId but I'm worried that will me misinterpreted since it's just a string.
// I propose entryTimelineId because it points to the entry to a new timeline.
// if this is the case, then we don't have to have this timepoint branch to another timepoint, but
// to another timeline. Thoughts?
private String entryTimelineId;
Firstly, why aren't we referring to these things as plans or schedules? I'm assuming you've already mulled this over, however the current naming is becoming somewhat problematic as I'm sort of divining an object hierarchy for the polymorphic nature of the timepoints in a timeline.
If I was working with a schedule or a plan than I would have generic Event objects that could either be Activities, Procedures or Decisions. If the timepoints are truly polymorphic then they could be any of these themselves.
We could also refer to them as specific events (ActivityEvents, EncounterEvents or DecisionEvents).
If this doesn't work for whatever reason, then I'm left with something like...Timepoint as the superclass with subclasses or EventTimepoint and DecisionTimepoint. Would this work?
Regarding the diagram and your conversation tomorrow @daveih , I think it's important to stress that we haven't nailed down the hierarchy of things that will be attached to the timeline and that right now, there's just a single Timepoint class with a simple type attribute that defines it as a general node or a decision or branch. This won't be good enough to ensure that the different types are misused or mislabeled.
Thoughts anybody?
The TransitionRule will not be deprecated, and the Condition class will be introduced. I believe that Condition class is too simple at the moment and that it should be used to encapsulate some kind of logic. Maybe returning a boolean or possibly returning some array of values. Thinking out loud here.
TransitionRule vs. Condition.
The TransitionRule will not be deprecated, and the Condition class will be introduced. I believe that Condition class is too simple at the moment and that it should be used to encapsulate some kind of logic. Maybe returning a boolean or possibly returning some array of values. Thinking out loud here.
@cupkes Both Conditon and TransitionRule are pretty simple, both contain a "string logic" statement. Lets keep them separate. I suspect longer term they will merge into some more complex machine readable entity
// In the diagram, this is timelineEntryId but I'm worried that will me misinterpreted since it's just a string. // I propose entryTimelineId because it points to the entry to a new timeline. // if this is the case, then we don't have to have this timepoint branch to another timepoint, but // to another timeline. Thoughts? private String entryTimelineId;
@cupkes Rename as you see fit (liaise with @EMuhlbradt and @czwickl as well). The names I used were "first cut" and naming is always tricky
There is an ongoing concept of entry because of a need for a condition. I propose that the entry itself is not an actual object, or independent concept. Instead I believe that every timeline has an entry condition and that the timepoints associated with the timeline are all post "condition met" timepoints. Do we ever have timepoints that aren't collected in a timeline? I argue that all timepoints exist in timelines, and therefore, for the first timeline, there can't be any previous "timepoints" that could point to conditions. "which came first, the timepoint or the timeline?" kind of thing. So, to solve this, I add a pointer to a condition in the timeline. This condition is simply used to record the "why" of the timeline, from what I can glean so far.
private Condition entryCondition;
If the timeline was due to a condition that was met for traversal from a previous timepoint, then we should have a handle to that timepoint.
private String entryTimepointId;
@cupkes happy with that
Final thoughts on timelines, timing and timepoints.
Firstly, why aren't we referring to these things as plans or schedules? I'm assuming you've already mulled this over, however the current naming is becoming somewhat problematic as I'm sort of divining an object hierarchy for the polymorphic nature of the timepoints in a timeline.
If I was working with a schedule or a plan than I would have generic Event objects that could either be Activities, Procedures or Decisions. If the timepoints are truly polymorphic then they could be any of these themselves.
We could also refer to them as specific events (ActivityEvents, EncounterEvents or DecisionEvents).
If this doesn't work for whatever reason, then I'm left with something like...Timepoint as the superclass with subclasses or EventTimepoint and DecisionTimepoint. Would this work?
Regarding the diagram and your conversation tomorrow @daveih , I think it's important to stress that we haven't nailed down the hierarchy of things that will be attached to the timeline and that right now, there's just a single Timepoint class with a simple type attribute that defines it as a general node or a decision or branch. This won't be good enough to ensure that the different types are misused or mislabeled.
Thoughts anybody?
This bit worried me
We could also refer to them as specific events (ActivityEvents, EncounterEvents or DecisionEvents).
Activity and Encounter are part of the timeline as such, they map into the tmeline (Same with Epoch), I see them as overlays on the timeline. Given that I am much happier with the following suggestion. I was guessing this is the direction we would go
If this doesn't work for whatever reason, then I'm left with something like...Timepoint as the superclass with subclasses or EventTimepoint and DecisionTimepoint. Would this work?
So, yes, this would work
This will be based on Dave's documentation, both the design image and the slide document he has shared.
This first version will be the untested version, as it will undergo several different tests subsequently.
Deliverables will be draft UML and code comments for all the fields. Will include the image and the notes themselves.