Show
Ignore:
Timestamp:
11-05-11 18:16:26 (3 years ago)
Author:
s.h.sikkema@…
Message:

First version of study inferring in simple wizard (does not support editing yet and assumes species == Homo sapiens)

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • trunk/grails-app/controllers/dbnp/studycapturing/SimpleWizardController.groovy

    r1834 r1838  
    3737         */ 
    3838        def index = { 
    39                 if( params.id ) 
    40                         redirect( action: "simpleWizard", id: params.id ); 
    41                 else 
    42                         redirect( action: "simpleWizard" ); 
     39//              if( params.id ) 
     40//                      redirect( action: "simpleWizard", id: params.id ); 
     41//              else 
     42//                      redirect( action: "simpleWizard" ); 
     43        redirect action: 'simpleWizard', params: params 
    4344        } 
    4445 
     
    4849                                flow.study = getStudyFromRequest( params ) 
    4950                                if (!flow.study) retrievalError() 
    50                                  
     51 
     52                flow.inferDesign = params.inferDesign 
    5153                                // Search for studies 
    5254                                flow.studies = Study.giveWritableStudies( authenticationService.getLoggedInUser(), 100 ) 
     
    817819                        failedCells: failedcells 
    818820                ]; 
    819          
    820                 // loop through all entities to validate them and add them to failedcells if an error occurs 
    821                 def numInvalidEntities = 0; 
    822                 def errors = []; 
    823  
    824                 // Add all samples 
    825                 table.each { record -> 
    826                         record.each { entity -> 
    827                                 if( entity ) { 
    828                                         // Determine entity class and add a parent. Add the entity to the study 
    829                                         def preferredIdentifier = importerService.givePreferredIdentifier( entity.class ); 
    830                                         def equalClosure = { it.getIdentifier() == entity.getIdentifier() } 
    831                                         def entityName = entity.class.name[ entity.class.name.lastIndexOf( "." ) + 1 .. -1 ] 
    832  
    833                                         entity.parent = study 
    834                                          
    835                                         switch( entity.class ) { 
    836                                                 case Sample: 
    837                                                         if( !study.samples?.find( equalClosure ) ) { 
    838                                                                 study.addToSamples( entity ); 
    839                                                         } 
    840                                                          
    841                                                         // If an eventgroup is created, add it to the study 
    842                                                         // The eventgroup must have a unique name, but the user shouldn't be bothered with it 
    843                                                         // Add 'group ' + samplename and it that is not unique, add a number to it 
    844                                                         if( entity.parentEventGroup ) { 
    845                                                                 study.addToEventGroups( entity.parentEventGroup ) 
    846  
    847                                                                 entity.parentEventGroup.name = "Group " + entity.name 
    848                                                                 while( !entity.parentEventGroup.validate() ) { 
    849                                                                         //entity.parentEventGroup.getErrors().each { println it } 
    850                                                                         entity.parentEventGroup.name += "" + Math.floor( Math.random() * 100 ) 
    851                                                                 } 
    852                                                         } 
    853                                                          
    854                                                         break; 
    855                                                 case Subject: 
    856                                                         if( !study.samples?.find( equalClosure ) ) { 
    857                                                                  
    858                                                                 if( preferredIdentifier ) { 
    859                                                                         // Subjects without a name should just be called 'subject' 
    860                                                                         if( !entity.getFieldValue( preferredIdentifier.name ) ) 
    861                                                                                 entity.setFieldValue( preferredIdentifier.name, "Subject" ); 
    862                                                                  
    863                                                                         // Subjects should have unique names; if the user has entered the same name multiple times, 
    864                                                                         // the subject will be renamed 
    865                                                                         def baseName = entity.getFieldValue( preferredIdentifier.name ) 
    866                                                                         def counter = 2; 
    867                                                                          
    868                                                                         while( study.subjects?.find { it.getFieldValue( preferredIdentifier.name ) == entity.getFieldValue( preferredIdentifier.name ) } ) { 
    869                                                                                 entity.setFieldValue( preferredIdentifier.name, baseName + " (" + counter++ + ")" ) 
    870                                                                         } 
    871                                                                 } 
    872                                                                  
    873                                                                 study.addToSubjects( entity ); 
    874                                                          
    875                                                         } 
    876                                                          
    877                                                         break; 
    878                                                 case Event: 
    879                                                         if( !study.events?.find( equalClosure ) ) { 
    880                                                                 study.addToEvents( entity ); 
    881                                                         } 
    882                                                         break; 
    883                                                 case SamplingEvent: 
    884                                                         // Sampling events have a 'sampleTemplate' value, which should be filled by the 
    885                                                         // template that is chosen for samples. 
    886                                                         if( !entity.getFieldValue( 'sampleTemplate' ) ) { 
    887                                                                 entity.setFieldValue( 'sampleTemplate', flow.sampleForm.template.Sample.name ) 
    888                                                         }  
    889                                                  
    890                                                         if( !study.samplingEvents?.find( equalClosure ) ) { 
    891                                                                 study.addToSamplingEvents( entity ); 
    892                                                         } 
    893                                                         break; 
    894                                         } 
    895                                          
    896                                         if (!entity.validate()) { 
    897                                                 numInvalidEntities++; 
    898                                                  
    899                                                 // Add this field to the list of failed cells, in order to give the user feedback 
    900                                                 failedcells = addNonValidatingCells( failedcells, entity, flow ) 
    901          
    902                                                 // Also create a full list of errors 
    903                                                 def currentErrors = getHumanReadableErrors( entity ) 
    904                                                 if( currentErrors ) { 
    905                                                         currentErrors.each { 
    906                                                                 errors += "(" + entityName + ") " + it.value; 
    907                                                         } 
    908                                                 } 
    909                                         } 
    910                                 } 
    911                         } 
    912                 } 
     821 
     822        // loop through all entities to validate them and add them to failedcells if an error occurs 
     823        def numInvalidEntities = 0; 
     824        def errors = []; 
     825 
     826        if (flow.inferDesign) { 
     827 
     828            println 'Entered infer design...' 
     829 
     830            // find the indices of the classes of interest in the records 
     831            def sampleIdx           = table[0].findIndexOf{it.class.name == 'dbnp.studycapturing.Sample'} 
     832            def samplingEventIdx    = table[0].findIndexOf{it.class.name == 'dbnp.studycapturing.SamplingEvent'} 
     833            def subjectIdx          = table[0].findIndexOf{it.class.name == 'dbnp.studycapturing.Subject'} 
     834 
     835            // Check for duplicate samples 
     836            def samples = table.collect{it[sampleIdx]} 
     837 
     838            def uniques     = [] as Set 
     839            def duplicates  = [] as Set 
     840 
     841            // this approach separates the unique from the duplicate entries 
     842            samples*.name.each { 
     843                uniques.add(it) || duplicates.add(it) 
     844            } 
     845 
     846            duplicates.each{ duplicateName -> 
     847                samples.findAll{it.name == duplicateName}.each{ sample -> 
     848                    numInvalidEntities++ 
     849                    failedcells = addNonValidatingCells(failedcells, sample, flow) 
     850                    errors += "(Sample) duplicate name: $duplicateName" 
     851                } 
     852            } 
     853 
     854            // A closure that returns a sub list of entities from a list that have 
     855            // unique values of a property indicated by propertyName 
     856            def uniqueEntitiesByProperty = { entities, propertyName -> 
     857 
     858               entities*."$propertyName".unique().collect { uniquePropertyValue -> 
     859 
     860                    entities.find{ it."$propertyName" == uniquePropertyValue } 
     861 
     862                } 
     863            } 
     864 
     865            def addToCollectionIfNonexistent = { parent, collectionName, entity, propertyName -> 
     866 
     867                if (!parent[collectionName].find{it[propertyName] == entity[propertyName]}) 
     868                    parent."addTo${collectionName.capitalize()}" entity 
     869 
     870            } 
     871 
     872            // collect unique subjects and sampling events from table 
     873            def uniqueSubjects = 
     874                uniqueEntitiesByProperty(table.collect{it[subjectIdx]}, 'name') 
     875            uniqueSubjects.each{ 
     876                addToCollectionIfNonexistent study, 'subjects', it, 'name' 
     877                it.species = Term.findByName('Homo sapiens') 
     878            } 
     879 
     880            def uniqueSamplingEvents = 
     881                uniqueEntitiesByProperty(table.collect{it[samplingEventIdx]}, 'startTime') 
     882            uniqueSamplingEvents.each{ 
     883                it.setFieldValue( 'sampleTemplate', flow.sampleForm.template.Sample.name ) 
     884            } 
     885 
     886            // create an event group for each unique sampling event (not much of a group, is it ...) 
     887            def eventGroups = uniqueSamplingEvents.collect{ 
     888 
     889                def eventGroupName = "Sampling_${it.sampleTemplate.name}_${new RelTime(it.startTime).toString()}" 
     890 
     891                def eventGroup = study.eventGroups.find{it.name == eventGroupName} ?: //EventGroup.findByParentAndName(study, eventGroupName) ?: 
     892                    new EventGroup(name: eventGroupName) 
     893 
     894                eventGroup.addToSamplingEvents it 
     895 
     896                if (!study.eventGroups.find{it == eventGroup}) 
     897                    study.addToEventGroups eventGroup 
     898 
     899                if (!it.parent) study.addToSamplingEvents it 
     900 
     901                println eventGroup.name 
     902 
     903                eventGroup 
     904 
     905            } 
     906 
     907            table.each{ record -> 
     908 
     909                Sample sample = record[sampleIdx] 
     910 
     911                // gather all sample related entities 
     912                def correspondingSamplingEvent  = uniqueSamplingEvents.find {it.startTime == record[samplingEventIdx].startTime} 
     913                def correspondingSubject        = uniqueSubjects.find{it.name == record[subjectIdx].name} 
     914                def correspondingEventGroup     = eventGroups.find{correspondingSamplingEvent in it.samplingEvents} 
     915 
     916                addToCollectionIfNonexistent correspondingSamplingEvent, 'samples', sample, 'name' 
     917 
     918                sample.parentSubject = correspondingSubject 
     919 
     920                correspondingEventGroup.addToSamplingEvents correspondingSamplingEvent 
     921 
     922                if (!correspondingEventGroup.subjects.find{it.name == correspondingSubject.name}) 
     923                    correspondingEventGroup.addToSubjects correspondingSubject 
     924 
     925                addToCollectionIfNonexistent study, 'samples', sample, 'name' 
     926 
     927            } 
     928 
     929        } else { 
     930            // Add all samples 
     931            table.each { record -> 
     932                record.each { entity -> 
     933                    if( entity ) { 
     934                        // Determine entity class and add a parent. Add the entity to the study 
     935                        def preferredIdentifier = importerService.givePreferredIdentifier( entity.class ); 
     936                        def equalClosure = { it.getIdentifier() == entity.getIdentifier() } 
     937                        def entityName = entity.class.name[ entity.class.name.lastIndexOf( "." ) + 1 .. -1 ] 
     938 
     939                        entity.parent = study 
     940 
     941                        switch( entity.class ) { 
     942                            case Sample: 
     943                                if( !study.samples?.find( equalClosure ) ) { 
     944                                    study.addToSamples( entity ); 
     945                                } 
     946 
     947                                // If an eventgroup is created, add it to the study 
     948                                // The eventgroup must have a unique name, but the user shouldn't be bothered with it 
     949                                // Add 'group ' + samplename and it that is not unique, add a number to it 
     950                                if( entity.parentEventGroup ) { 
     951                                    study.addToEventGroups( entity.parentEventGroup ) 
     952 
     953                                    entity.parentEventGroup.name = "Group " + entity.name 
     954                                    while( !entity.parentEventGroup.validate() ) { 
     955                                        //entity.parentEventGroup.getErrors().each { println it } 
     956                                        entity.parentEventGroup.name += "" + Math.floor( Math.random() * 100 ) 
     957                                    } 
     958                                } 
     959 
     960                                break; 
     961                            case Subject: 
     962                                if( !study.samples?.find( equalClosure ) ) { 
     963 
     964                                    if( preferredIdentifier ) { 
     965                                        // Subjects without a name should just be called 'subject' 
     966                                        if( !entity.getFieldValue( preferredIdentifier.name ) ) 
     967                                            entity.setFieldValue( preferredIdentifier.name, "Subject" ); 
     968 
     969                                        // Subjects should have unique names; if the user has entered the same name multiple times, 
     970                                        // the subject will be renamed 
     971                                        def baseName = entity.getFieldValue( preferredIdentifier.name ) 
     972                                        def counter = 2; 
     973 
     974                                        while( study.subjects?.find { it.getFieldValue( preferredIdentifier.name ) == entity.getFieldValue( preferredIdentifier.name ) } ) { 
     975                                            entity.setFieldValue( preferredIdentifier.name, baseName + " (" + counter++ + ")" ) 
     976                                        } 
     977                                    } 
     978 
     979                                    study.addToSubjects( entity ); 
     980 
     981                                } 
     982 
     983                                break; 
     984                            case Event: 
     985                                if( !study.events?.find( equalClosure ) ) { 
     986                                    study.addToEvents( entity ); 
     987                                } 
     988                                break; 
     989                            case SamplingEvent: 
     990                                // Sampling events have a 'sampleTemplate' value, which should be filled by the 
     991                                // template that is chosen for samples. 
     992                                if( !entity.getFieldValue( 'sampleTemplate' ) ) { 
     993                                    entity.setFieldValue( 'sampleTemplate', flow.sampleForm.template.Sample.name ) 
     994                                } 
     995 
     996                                if( !study.samplingEvents?.find( equalClosure ) ) { 
     997                                    study.addToSamplingEvents( entity ); 
     998                                } 
     999                                break; 
     1000                        } 
     1001 
     1002                        if (!entity.validate()) { 
     1003                            numInvalidEntities++; 
     1004 
     1005                            // Add this field to the list of failed cells, in order to give the user feedback 
     1006                            failedcells = addNonValidatingCells( failedcells, entity, flow ) 
     1007 
     1008                            // Also create a full list of errors 
     1009                            def currentErrors = getHumanReadableErrors( entity ) 
     1010                            if( currentErrors ) { 
     1011                                currentErrors.each { 
     1012                                    errors += "(" + entityName + ") " + it.value; 
     1013                                } 
     1014                            } 
     1015                        } 
     1016                    } 
     1017                } 
     1018            } 
     1019        } 
    9131020 
    9141021                flow.imported.numInvalidEntities = numInvalidEntities + failedcells?.size(); 
     
    12311338                return errors 
    12321339        } 
    1233  
    1234     // TEMPORARY ACTION TO TEST CORRECT STUDY DESIGN INFERRING: SHOULD BE REMOVED WHEN DONE 
    1235     def testMethod = { 
    1236  
    1237         //////////////////////////////////////////////////////////////////////// 
    1238         // Functionality mimics intermediate results from simple wizard       // 
    1239         //////////////////////////////////////////////////////////////////////// 
    1240  
    1241         def data = [//['sample name',         'subject',         'timepoint'], 
    1242                     [ '97___N_151_HAKA_1',    'N_151_HAKA',    '0w'], 
    1243                     [ '98___N_163_QUJO_3',    'N_163_QUJO',    '2w'], 
    1244                     [ '99___N_151_HAKA_2',    'N_151_HAKA',    '1w'], 
    1245                     ['100___N_163_QUJO_4',    'N_163_QUJO',    '3w'], 
    1246                     ['101___N_151_HAKA_3',    'N_151_HAKA',    '2w'], 
    1247                     ['102___N_163_QUJO_2',    'N_163_QUJO',    '1w'], 
    1248                     ['103___U_031_SMGI_1',    'U_031_SMGI',    '0w'], 
    1249                     ['104___U_031_SMGI_3',    'U_031_SMGI',    '2w'], 
    1250                     ['105___N_163_QUJO_1',    'N_163_QUJO',    '0w'], 
    1251                     ['106___U_031_SMGI_4',    'U_031_SMGI',    '3w'], 
    1252                     ['107___N_151_HAKA_4',    'N_151_HAKA',    '3w'], 
    1253                     ['108___U_031_SMGI_2',    'U_031_SMGI',    '1w'], 
    1254                     ['109___N_021_THAA_2',    'N_021_THAA',    '1w'], 
    1255                     ['110___U_029_DUJA_2',    'U_029_DUJA',    '1w'], 
    1256                     ['111___U_029_DUJA_3',    'U_029_DUJA',    '2w'], 
    1257                     ['112___N_021_THAA_3',    'N_021_THAA',    '2w'], 
    1258                     ['113___U_029_DUJA_4',    'U_029_DUJA',    '3w'], 
    1259                     ['114___N_045_SNSU_1',    'N_045_SNSU',    '0w'], 
    1260                     ['115___N_021_THAA_1',    'N_021_THAA',    '0w'], 
    1261                     ['116___N_045_SNSU_2',    'N_045_SNSU',    '1w'], 
    1262                     ['117___N_045_SNSU_3',    'N_045_SNSU',    '2w'], 
    1263                     ['118___N_045_SNSU_4',    'N_045_SNSU',    '3w'], 
    1264                     ['119___N_021_THAA_4',    'N_021_THAA',    '3w'], 
    1265                     ['120___U_029_DUJA_1',    'U_029_DUJA',    '0w'], 
    1266                     ['121___U_060_BRGE_3',    'U_060_BRGE',    '2w'], 
    1267                     ['122___N_018_WIHA_1',    'N_018_WIHA',    '0w'], 
    1268                     ['123___N_022_HUCA_3',    'N_022_HUCA',    '2w'], 
    1269                     ['124___N_022_HUCA_2',    'N_022_HUCA',    '1w']] 
    1270  
    1271         def sampleTemplate = Template.findByName ('Human blood sample') 
    1272         def subjectTemplate = Template.findByName ('Human') 
    1273         def samplingEventTemplate = Template.findByName ('Blood extraction') 
    1274 //        def eventTemplate = Template.findByName ('Diet treatment') 
    1275  
    1276  
    1277         // Table is a collection of records. A records contains entities of type 
    1278         // Sample, Subject, and SamplingEvent. This mimics the output of 
    1279         // importerService.importOrUpdateDataBySampleIdentifier 
    1280         def table = data.collect { row -> 
    1281  
    1282             [       new Sample( name: row[0], template: sampleTemplate), 
    1283                     new Subject(name: row[1], template: subjectTemplate), 
    1284                     new SamplingEvent(template: samplingEventTemplate).setFieldValue('startTime', row[2]) 
    1285 //                    new Event(template: eventTemplate) 
    1286             ] 
    1287  
    1288         } 
    1289  
    1290         //////////////////////////////////////////////////////////////////////// 
    1291         // Functionality below should be inserted into simple wizard 
    1292         // We'll assume entities with pre-existing preferred identifiers have 
    1293         // already been loaded from the db so that updating will work. 
    1294         //////////////////////////////////////////////////////////////////////// 
    1295  
    1296         def inferStudyDesign = { study -> 
    1297  
    1298             // Check for duplicate samples 
    1299             def samples = table.collect{it[0]} 
    1300  
    1301             def uniques     = [] as Set 
    1302             def duplicates  = [] as Set 
    1303  
    1304             // this approach separates the unique from the duplicate entries 
    1305             samples*.name.each { 
    1306                 uniques.add(it) || duplicates.add(it) 
    1307             } 
    1308  
    1309             duplicates.each{ duplicateName -> 
    1310                 samples.findAllByName(duplicateName).each{ sample -> 
    1311                     numInvalidEntities++ 
    1312                     failedcells = addNonValidatingCells(failedcells, sample, flow) 
    1313                     errors += "(Sample) duplicate name: $duplicateName" 
    1314                 } 
    1315             } 
    1316  
    1317             // A closure that returns a sub list of entities from a list that have 
    1318             // unique values of a property indicated by propertyName 
    1319             def uniqueEntitiesByProperty = { entities, propertyName -> 
    1320  
    1321                entities*."$propertyName".unique().collect { uniquePropertyValue -> 
    1322  
    1323                     entities.find{ it."$propertyName" == uniquePropertyValue } 
    1324  
    1325                 } 
    1326             } 
    1327  
    1328             // collect unique subjects and sampling events from table 
    1329             def uniqueSubjects = 
    1330                 uniqueEntitiesByProperty(table.collect{it[1]}, 'name') 
    1331             def uniqueSamplingEvents = 
    1332                 uniqueEntitiesByProperty(table.collect{it[2]}, 'startTime') 
    1333  
    1334             // create an event group for each unique sampling event (not much of a group, is it ...) 
    1335             uniqueSamplingEvents.each{ 
    1336                 new EventGroup(name: "Sampling_${it.name}_${it.startTime}").addToSamplingEvents(it) 
    1337                 study.addToEventGroups eventGroup 
    1338             } 
    1339  
    1340             def addToCollectionIfNecessary = { parent, collectionName, entity, propertyName -> 
    1341  
    1342                 if (!parent.'collectionName'.find{it.'propertyName' == entity.'propertyName'}) 
    1343                     parent."addTo${collectionName.toUpperCase()}" entity 
    1344  
    1345             } 
    1346  
    1347             table.each{ record -> 
    1348  
    1349                 Sample sample = record[0] 
    1350  
    1351                 // gather all sample related entities 
    1352                 def correspondingSamplingEvent  = uniqueSamplingEvents.findByStartTime(record[2].startTime) 
    1353                 def correspondingSubject        = uniqueSubjects.findByName(record[1].name) 
    1354                 def correspondingEventGroup     = correspondingSamplingEvent.eventGroup 
    1355  
    1356                 correspondingSamplingEvent.addToSamples sample 
    1357                 correspondingSubject.addToSamples       sample 
    1358                 correspondingEventGroup.addToSamples    sample 
    1359  
    1360                 if (!correspondingEventGroup.subjects.find{it.name == correspondingSubject.name}) 
    1361                     correspondingEventGroup.addToSubjects correspondingSubject 
    1362  
    1363                 study.addToSamples sample 
    1364             } 
    1365         } 
    1366  
    1367         // inferStudyDesign(study) 
    1368  
    1369         println 'hoi' 
    1370         render 'bla' 
    1371  
    1372     } 
    13731340}