Search in sources :

Example 1 with DateRange

use of org.sagebionetworks.bridge.models.DateRange in project BridgeServer2 by Sage-Bionetworks.

the class EventStreamAdherenceReportGenerator method generate.

public EventStreamAdherenceReport generate(AdherenceState state) {
    LocalDate earliestDate = LATEST_LOCAL_DATE;
    LocalDate latestDate = EARLIEST_LOCAL_DATE;
    int min = Integer.MAX_VALUE;
    int max = Integer.MIN_VALUE;
    String earliestEventId = null;
    for (TimelineMetadata meta : state.getMetadata()) {
        if (meta.isTimeWindowPersistent()) {
            continue;
        }
        int startDay = meta.getSessionInstanceStartDay();
        int endDay = meta.getSessionInstanceEndDay();
        String eventId = meta.getSessionStartEventId();
        Integer daysSinceEvent = state.getDaysSinceEventById(eventId);
        DateTime timestamp = state.getEventTimestampById(eventId);
        LocalDate localDate = (timestamp == null) ? null : timestamp.toLocalDate();
        LocalDate startDate = (localDate == null) ? null : localDate.plusDays(startDay);
        LocalDate endDate = (localDate == null) ? null : localDate.plusDays(endDay);
        // Produce one report for each event ID. Create them lazily as we find each eventId;
        EventStream stream = state.getEventStreamById(eventId);
        stream.setDaysSinceEvent(daysSinceEvent);
        stream.setStudyBurstId(meta.getStudyBurstId());
        stream.setStudyBurstNum(meta.getStudyBurstNum());
        // Get the adherence information for this session instance and derive the state of the session
        AdherenceRecord record = state.getAdherenceRecordByGuid(meta.getSessionInstanceGuid());
        SessionCompletionState sessionState = calculateSessionState(record, startDay, endDay, daysSinceEvent);
        // Retrieve the event stream. All items in this stream start on the same day, but can end on different days
        EventStreamDay eventStreamDay = state.getEventStreamDayByKey(meta);
        eventStreamDay.setStartDay(startDay);
        eventStreamDay.setStartDate(startDate);
        // Create a window entry (windows are flattened in the list of timeline metadata records...all session
        // records in the metadata table are actually session window records)
        EventStreamWindow windowEntry = new EventStreamWindow();
        windowEntry.setSessionInstanceGuid(meta.getSessionInstanceGuid());
        windowEntry.setTimeWindowGuid(meta.getTimeWindowGuid());
        windowEntry.setEndDay(endDay);
        windowEntry.setEndDate(endDate);
        windowEntry.setState(sessionState);
        eventStreamDay.addTimeWindow(windowEntry);
        if (startDate != null && startDate.isBefore(earliestDate)) {
            earliestDate = startDate;
            earliestEventId = eventStreamDay.getStartEventId();
        }
        if (endDate != null && endDate.isAfter(latestDate)) {
            latestDate = endDate;
        }
        if (min > startDay) {
            min = startDay;
        }
        if (max < endDay) {
            max = endDay;
        }
    }
    DayRange dayRange = null;
    if (min <= max) {
        dayRange = new DayRange(min, max);
    }
    DateRange dateRange = null;
    if (earliestDate.isBefore(latestDate)) {
        dateRange = new DateRange(earliestDate, latestDate);
    }
    EventStreamAdherenceReport report = new EventStreamAdherenceReport();
    report.setTimestamp(state.getNow());
    report.setClientTimeZone(state.getClientTimeZone());
    report.setAdherencePercent(state.calculateAdherencePercentage());
    report.setDayRangeOfAllStreams(dayRange);
    report.setDateRangeOfAllStreams(dateRange);
    report.setEarliestEventId(earliestEventId);
    for (String eventId : state.getStreamEventIds()) {
        report.getStreams().add(state.getEventStreamById(eventId));
    }
    report.setProgression(calculateProgress(state, report.getStreams()));
    return report;
}
Also used : TimelineMetadata(org.sagebionetworks.bridge.models.schedules2.timelines.TimelineMetadata) SessionCompletionState(org.sagebionetworks.bridge.models.schedules2.adherence.SessionCompletionState) LocalDate(org.joda.time.LocalDate) DateTime(org.joda.time.DateTime) DateRange(org.sagebionetworks.bridge.models.DateRange) AdherenceRecord(org.sagebionetworks.bridge.models.schedules2.adherence.AdherenceRecord) DayRange(org.sagebionetworks.bridge.models.DayRange)

Example 2 with DateRange

use of org.sagebionetworks.bridge.models.DateRange in project BridgeServer2 by Sage-Bionetworks.

the class StudyAdherenceReportGenerator method generate.

public StudyAdherenceReport generate(AdherenceState state) {
    EventStreamAdherenceReport eventReport = EventStreamAdherenceReportGenerator.INSTANCE.generate(state);
    LocalDate studyStartDate = getStudyStartDate(state, eventReport);
    EventStream studyStream = new EventStream();
    Set<String> unsetEventIds = new HashSet<>();
    Set<String> unscheduledSessions = new HashSet<>();
    Map<String, DateTime> eventTimestamps = new HashMap<>();
    LocalDate todayLocal = state.getNow().toLocalDate();
    // Remap all the event streams to one event stream — the study event stream
    for (EventStream stream : eventReport.getStreams()) {
        for (List<EventStreamDay> days : stream.getByDayEntries().values()) {
            for (EventStreamDay oneDay : days) {
                if (oneDay.getStartDate() != null) {
                    // Map this stream into the study stream
                    Integer numDays = Days.daysBetween(studyStartDate, oneDay.getStartDate()).getDays();
                    studyStream.addEntry(numDays, oneDay);
                    String eventId = oneDay.getStartEventId();
                    eventTimestamps.put(eventId, state.getEventTimestampById(eventId));
                } else {
                    // Note for the report the events and sessions that are not applicable to this user
                    unsetEventIds.add(oneDay.getStartEventId());
                    unscheduledSessions.add(oneDay.getSessionName());
                }
            }
        }
    }
    // study-wide progress
    ParticipantStudyProgress progression = calculateProgress(state, ImmutableList.of(studyStream));
    // Break this study stream down into weeks. TreeMap sorts the weeks by week number
    Map<Integer, StudyReportWeek> weekMap = new TreeMap<>();
    for (Map.Entry<Integer, List<EventStreamDay>> entry : studyStream.getByDayEntries().entrySet()) {
        int week = entry.getKey() / 7;
        // Day of week can be negative if the week was negative... just flip it
        int dayOfWeek = Math.abs(entry.getKey() % 7);
        StudyReportWeek oneWeek = weekMap.get(week);
        if (oneWeek == null) {
            oneWeek = new StudyReportWeek();
            oneWeek.setStartDate(studyStartDate.plusDays(week * 7));
            oneWeek.setWeekInStudy(week + 1);
            weekMap.put(week, oneWeek);
        }
        List<EventStreamDay> days = oneWeek.getByDayEntries().get(dayOfWeek);
        days.addAll(entry.getValue());
    }
    ;
    Collection<StudyReportWeek> weeks = weekMap.values();
    StudyReportWeek currentWeek = null;
    for (StudyReportWeek oneWeek : weeks) {
        calculateRowsAndLabels(oneWeek, todayLocal);
        // If there’s a day in this week that is “today”, set a flag for all day entries on that day
        LocalDate firstDayOfWeek = oneWeek.getStartDate();
        LocalDate lastDayOfWeek = oneWeek.getStartDate().plusDays(7);
        if (BridgeUtils.isLocalDateInRange(firstDayOfWeek, lastDayOfWeek, todayLocal)) {
            currentWeek = oneWeek;
            for (List<EventStreamDay> days : oneWeek.getByDayEntries().values()) {
                for (EventStreamDay oneDay : days) {
                    if (oneDay.getStartDate().isEqual(todayLocal)) {
                        days.forEach(day -> day.setToday(true));
                    }
                }
            }
        }
        // current one) but not the weeks after todayLocal.
        if (BridgeUtils.isLocalDateInRange(oneWeek.getStartDate(), null, todayLocal)) {
            int weekAdh = AdherenceUtils.calculateAdherencePercentage(oneWeek.getByDayEntries());
            oneWeek.setAdherencePercent(weekAdh);
        }
    }
    Integer adherence = null;
    if (progression != ParticipantStudyProgress.NO_SCHEDULE) {
        adherence = calculateAdherencePercentage(ImmutableList.of(studyStream));
    }
    NextActivity nextActivity = null;
    if (currentWeek == null) {
        nextActivity = getNextActivity(weeks, todayLocal);
    }
    DateRange dateRange = null;
    if (eventReport.getDateRangeOfAllStreams() != null) {
        dateRange = new DateRange(studyStartDate, eventReport.getDateRangeOfAllStreams().getEndDate());
    }
    for (StudyReportWeek oneWeek : weeks) {
        for (List<EventStreamDay> days : oneWeek.getByDayEntries().values()) {
            for (EventStreamDay oneDay : days) {
                oneDay.setStudyBurstId(null);
                oneDay.setStudyBurstNum(null);
                oneDay.setSessionName(null);
                oneDay.setWeek(null);
                oneDay.setStartDay(null);
                for (EventStreamWindow window : oneDay.getTimeWindows()) {
                    window.setEndDay(null);
                // This cannot be removed, or the window will be removed from persisted collection
                // window.setTimeWindowGuid(null);
                }
            }
        }
    }
    StudyAdherenceReport report = new StudyAdherenceReport();
    report.setDateRange(dateRange);
    report.setWeeks(weeks);
    report.setCurrentWeek(currentWeek);
    report.setNextActivity(nextActivity);
    report.setProgression(progression);
    report.setAdherencePercent(adherence);
    report.setEventTimestamps(eventTimestamps);
    report.setUnsetEventIds(unsetEventIds);
    report.setUnscheduledSessions(unscheduledSessions);
    return report;
}
Also used : HashMap(java.util.HashMap) LocalDate(org.joda.time.LocalDate) DateTime(org.joda.time.DateTime) ParticipantStudyProgress(org.sagebionetworks.bridge.models.schedules2.adherence.ParticipantStudyProgress) EventStreamDay(org.sagebionetworks.bridge.models.schedules2.adherence.eventstream.EventStreamDay) DateRange(org.sagebionetworks.bridge.models.DateRange) EventStreamWindow(org.sagebionetworks.bridge.models.schedules2.adherence.eventstream.EventStreamWindow) EventStream(org.sagebionetworks.bridge.models.schedules2.adherence.eventstream.EventStream) EventStreamAdherenceReport(org.sagebionetworks.bridge.models.schedules2.adherence.eventstream.EventStreamAdherenceReport) ArrayList(java.util.ArrayList) ImmutableList(com.google.common.collect.ImmutableList) List(java.util.List) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) TreeMap(java.util.TreeMap) NextActivity(org.sagebionetworks.bridge.models.schedules2.adherence.weekly.NextActivity) HashMap(java.util.HashMap) Map(java.util.Map) TreeMap(java.util.TreeMap)

Example 3 with DateRange

use of org.sagebionetworks.bridge.models.DateRange in project BridgeServer2 by Sage-Bionetworks.

the class ParticipantScheduleGenerator method generate.

public ParticipantSchedule generate(AdherenceState state, Timeline timeline) {
    Multimap<LocalDate, ScheduledSession> chronology = LinkedHashMultimap.create();
    LocalDate earliestDate = LATEST_LOCAL_DATE;
    LocalDate latestDate = EARLIEST_LOCAL_DATE;
    Map<String, DateTime> eventTimestamps = new HashMap<>();
    for (ScheduledSession schSession : timeline.getSchedule()) {
        String eventId = schSession.getStartEventId();
        DateTime eventTimestamp = state.getEventTimestampById(eventId);
        if (eventTimestamp == null) {
            continue;
        }
        LocalDate startDate = eventTimestamp.plusDays(schSession.getStartDay()).toLocalDate();
        LocalDate endDate = eventTimestamp.plusDays(schSession.getEndDay()).toLocalDate();
        eventTimestamps.put(eventId, eventTimestamp);
        ScheduledSession.Builder builder = schSession.toBuilder();
        builder.withStartDate(startDate);
        builder.withEndDate(endDate);
        if (startDate.isBefore(earliestDate)) {
            earliestDate = startDate;
        }
        if (endDate.isAfter(latestDate)) {
            latestDate = endDate;
        }
        for (ScheduledAssessment schAssessment : schSession.getAssessments()) {
            ScheduledAssessment.Builder asmtBuilder = new ScheduledAssessment.Builder().withRefKey(schAssessment.getRefKey()).withInstanceGuid(schAssessment.getInstanceGuid());
            builder.withScheduledAssessment(asmtBuilder.build());
        }
        // null these out, not useful
        schSession.getTimeWindow().setGuid(null);
        builder.withStartDay(null);
        builder.withEndDay(null);
        chronology.put(startDate, builder.build());
    }
    // chronology.size() is the total number of pairs, not the total number of keys (and thus correct).
    List<ScheduledSession> scheduledSessions = Lists.newArrayListWithCapacity(chronology.size());
    for (LocalDate date : chronology.keySet()) {
        scheduledSessions.addAll(chronology.get(date));
    }
    scheduledSessions.sort(SCHEDULED_SESSION_COMPARATOR);
    DateRange range = null;
    if (earliestDate.isBefore(latestDate)) {
        range = new DateRange(earliestDate, latestDate);
    }
    ParticipantSchedule schedule = new ParticipantSchedule();
    schedule.setCreatedOn(state.getNow());
    schedule.setClientTimeZone(state.getClientTimeZone());
    schedule.setDateRange(range);
    schedule.setSchedule(scheduledSessions);
    schedule.setSessions(timeline.getSessions().stream().map(SessionInfo::createScheduleEntry).collect(toList()));
    schedule.setAssessments(timeline.getAssessments());
    schedule.setStudyBursts(timeline.getStudyBursts());
    schedule.setEventTimestamps(eventTimestamps);
    return schedule;
}
Also used : HashMap(java.util.HashMap) SessionInfo(org.sagebionetworks.bridge.models.schedules2.timelines.SessionInfo) LocalDate(org.joda.time.LocalDate) DateTime(org.joda.time.DateTime) ScheduledAssessment(org.sagebionetworks.bridge.models.schedules2.timelines.ScheduledAssessment) DateRange(org.sagebionetworks.bridge.models.DateRange) ScheduledSession(org.sagebionetworks.bridge.models.schedules2.timelines.ScheduledSession)

Example 4 with DateRange

use of org.sagebionetworks.bridge.models.DateRange in project BridgeServer2 by Sage-Bionetworks.

the class UserDataDownloadViaSqsServiceTest method test.

@Test
public void test() throws Exception {
    // main test strategy is to validate that the args get transformed and sent to SQS as expected
    // mock config
    BridgeConfig mockConfig = mock(BridgeConfig.class);
    when(mockConfig.getProperty(CONFIG_KEY_UDD_SQS_QUEUE_URL)).thenReturn(SQS_URL);
    // mock SQS
    AmazonSQSClient mockSqsClient = mock(AmazonSQSClient.class);
    SendMessageResult mockSqsResult = new SendMessageResult().withMessageId(SQS_MESSAGE_ID);
    ArgumentCaptor<String> sqsMessageCaptor = ArgumentCaptor.forClass(String.class);
    when(mockSqsClient.sendMessage(eq(SQS_URL), sqsMessageCaptor.capture())).thenReturn(mockSqsResult);
    // set up test service
    UserDataDownloadViaSqsService testService = new UserDataDownloadViaSqsService();
    testService.setBridgeConfig(mockConfig);
    testService.setSqsClient(mockSqsClient);
    // test inputs
    DateRange dateRange = new DateRange(LocalDate.parse(START_DATE), LocalDate.parse(END_DATE));
    // execute
    testService.requestUserData(TEST_APP_ID, USER_ID, dateRange);
    // Validate SQS args.
    String sqsMessageText = sqsMessageCaptor.getValue();
    JsonNode sqsMessageNode = JSON_OBJECT_MAPPER.readTree(sqsMessageText);
    // first assert parent node
    assertEquals(sqsMessageNode.size(), 2);
    assertEquals(sqsMessageNode.get(REQUEST_KEY_SERVICE).asText(), UDD_SERVICE_TITLE);
    // then assert body node
    JsonNode msgBody = sqsMessageNode.path(REQUEST_KEY_BODY);
    assertEquals(msgBody.size(), 5);
    assertEquals(msgBody.get(REQUEST_KEY_STUDY_ID).textValue(), TEST_APP_ID);
    assertEquals(msgBody.get(REQUEST_KEY_APP_ID).textValue(), TEST_APP_ID);
    assertEquals(msgBody.get(REQUEST_KEY_USER_ID).textValue(), USER_ID);
    assertEquals(msgBody.get(REQUEST_KEY_START_DATE).textValue(), START_DATE);
    assertEquals(msgBody.get(REQUEST_KEY_END_DATE).textValue(), END_DATE);
}
Also used : DateRange(org.sagebionetworks.bridge.models.DateRange) BridgeConfig(org.sagebionetworks.bridge.config.BridgeConfig) JsonNode(com.fasterxml.jackson.databind.JsonNode) AmazonSQSClient(com.amazonaws.services.sqs.AmazonSQSClient) SendMessageResult(com.amazonaws.services.sqs.model.SendMessageResult) Test(org.testng.annotations.Test)

Example 5 with DateRange

use of org.sagebionetworks.bridge.models.DateRange in project BridgeServer2 by Sage-Bionetworks.

the class ParticipantScheduleTest method canSerialize.

@Test
public void canSerialize() {
    Schedule2 schedule = Schedule2Test.createValidSchedule();
    Timeline timeline = Scheduler.INSTANCE.calculateTimeline(schedule);
    ScheduledSession schSession = timeline.getSchedule().get(0);
    schSession.getTimeWindow().setGuid(null);
    schSession = schSession.toBuilder().withStartDay(null).withEndDay(null).withStartEventId(null).withStartDate(LocalDate.parse("2022-01-10")).withEndDate(LocalDate.parse("2022-01-13")).withState(SessionCompletionState.ABANDONED).build();
    DateRange range = new DateRange(CREATED_ON.toLocalDate(), MODIFIED_ON.toLocalDate());
    ParticipantSchedule participantSchedule = new ParticipantSchedule();
    participantSchedule.setDateRange(range);
    participantSchedule.setCreatedOn(CREATED_ON);
    participantSchedule.setClientTimeZone(TEST_CLIENT_TIME_ZONE);
    participantSchedule.setSchedule(ImmutableList.of(schSession));
    participantSchedule.setAssessments(timeline.getAssessments());
    participantSchedule.setSessions(timeline.getSessions());
    participantSchedule.setStudyBursts(timeline.getStudyBursts());
    participantSchedule.setEventTimestamps(ImmutableMap.of("enrollment", MODIFIED_ON));
    JsonNode node = BridgeObjectMapper.get().valueToTree(participantSchedule);
    assertEquals(node.size(), 9);
    assertEquals(node.get("createdOn").textValue(), CREATED_ON.toString());
    assertEquals(node.get("clientTimeZone").textValue(), TEST_CLIENT_TIME_ZONE);
    assertEquals(node.get("dateRange").get("startDate").textValue(), CREATED_ON.toLocalDate().toString());
    assertEquals(node.get("dateRange").get("endDate").textValue(), MODIFIED_ON.toLocalDate().toString());
    assertEquals(node.get("type").textValue(), "ParticipantSchedule");
    JsonNode schNode = node.get("schedule").get(0);
    assertEquals(schNode.get("startDate").textValue(), "2022-01-10");
    assertEquals(schNode.get("endDate").textValue(), "2022-01-13");
    assertEquals(schNode.get("state").textValue(), "abandoned");
    // This is completely tested in ScheduledSessionTest
    JsonNode sessionNode = node.get("sessions").get(0);
    assertEquals(sessionNode.get("guid").textValue(), "BBBBBBBBBBBBBBBBBBBBBBBB");
    assertEquals(sessionNode.get("performanceOrder").textValue(), "randomized");
    // This is completely tested in SessionInfoTest
    JsonNode asmtNode = node.get("assessments").get(0);
    assertEquals(asmtNode.get("guid").textValue(), ASSESSMENT_1_GUID);
    // This is completely tested in AssessmentInfoTest
    JsonNode sbNode = node.get("studyBursts").get(0);
    assertEquals(sbNode.get("identifier").textValue(), "burst1");
    assertEquals(sbNode.get("originEventId").textValue(), "timeline_retrieved");
    assertEquals(sbNode.get("interval").textValue(), "P1W");
    assertEquals(sbNode.get("occurrences").intValue(), 2);
    assertEquals(sbNode.get("type").textValue(), "StudyBurstInfo");
    JsonNode etNode = node.get("eventTimestamps");
    assertEquals(etNode.get("enrollment").textValue(), MODIFIED_ON.toString());
}
Also used : Timeline(org.sagebionetworks.bridge.models.schedules2.timelines.Timeline) DateRange(org.sagebionetworks.bridge.models.DateRange) Schedule2(org.sagebionetworks.bridge.models.schedules2.Schedule2) JsonNode(com.fasterxml.jackson.databind.JsonNode) ScheduledSession(org.sagebionetworks.bridge.models.schedules2.timelines.ScheduledSession) ParticipantSchedule(org.sagebionetworks.bridge.models.schedules2.participantschedules.ParticipantSchedule) Test(org.testng.annotations.Test) Schedule2Test(org.sagebionetworks.bridge.models.schedules2.Schedule2Test)

Aggregations

DateRange (org.sagebionetworks.bridge.models.DateRange)9 Test (org.testng.annotations.Test)5 JsonNode (com.fasterxml.jackson.databind.JsonNode)3 DateTime (org.joda.time.DateTime)3 LocalDate (org.joda.time.LocalDate)3 StudyParticipant (org.sagebionetworks.bridge.models.accounts.StudyParticipant)3 HashMap (java.util.HashMap)2 StatusMessage (org.sagebionetworks.bridge.models.StatusMessage)2 EventStreamDay (org.sagebionetworks.bridge.models.schedules2.adherence.eventstream.EventStreamDay)2 NextActivity (org.sagebionetworks.bridge.models.schedules2.adherence.weekly.NextActivity)2 ScheduledSession (org.sagebionetworks.bridge.models.schedules2.timelines.ScheduledSession)2 AmazonSQSClient (com.amazonaws.services.sqs.AmazonSQSClient)1 SendMessageResult (com.amazonaws.services.sqs.model.SendMessageResult)1 ArrayNode (com.fasterxml.jackson.databind.node.ArrayNode)1 ImmutableList (com.google.common.collect.ImmutableList)1 ArrayList (java.util.ArrayList)1 HashSet (java.util.HashSet)1 LinkedHashSet (java.util.LinkedHashSet)1 List (java.util.List)1 Map (java.util.Map)1