diff --git a/src/main/java/net/ipmdecisions/model/entity/LocationResult.java b/src/main/java/net/ipmdecisions/model/entity/LocationResult.java
new file mode 100644
index 0000000000000000000000000000000000000000..ef2ed6cb86e5de509f45cc912c721c693b76f5bc
--- /dev/null
+++ b/src/main/java/net/ipmdecisions/model/entity/LocationResult.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2020 NIBIO <http://www.nibio.no/>. 
+ * 
+ * This file is part of VIPSCommon.
+ * VIPSCommon is free software: you can redistribute it and/or modify
+ * it under the terms of the NIBIO Open Source License as published by 
+ * NIBIO, either version 1 of the License, or (at your option) any
+ * later version.
+ * 
+ * VIPSCommon is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * NIBIO Open Source License for more details.
+ * 
+ * You should have received a copy of the NIBIO Open Source License
+ * along with VIPSCommon.  If not, see <http://www.nibio.no/licenses/>.
+ * 
+ */
+
+package net.ipmdecisions.model.entity;
+
+/**
+ * @copyright 2020 <a href="http://www.nibio.no/">NIBIO</a>
+ * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
+ */
+public class LocationResult {
+    private Double longitude;
+    private Double latitude;
+    private Double altitude;
+    private Double[][] data;
+    
+    public LocationResult(Double longitude, Double latitude, Double altitude, int rows, int columns){
+        this.longitude = longitude;
+        this.latitude = latitude;
+        this.altitude = altitude;
+        this.data = new Double[rows][columns];
+    }
+    
+    public LocationResult(){
+        
+    }
+    
+    /**
+     * 
+     * @return The number of rows in the dataset 
+     */
+    public Integer getLength()
+    {
+        return this.data.length;
+    }
+    
+    /**
+     * 
+     * @return The number of parameters per rows in the dataset 
+     */
+    public Integer getWidth()
+    {
+        return this.data[0].length;
+    }
+    
+    public Double[][] getData()
+    {
+        return this.data;
+    }
+    
+    public void setData(Double[][] data)
+    {
+        this.data = data;
+    }
+    
+    public void setValue(Integer row, Integer column, Double value)
+    {
+        this.data[row][column] = value;
+    }
+    
+    public Double getValue(Integer row, Integer column)
+    {
+        return this.data[row][column];
+    }
+    
+    public Double[] getRow(Integer row)
+    {
+        return this.data[row];
+    }
+    
+    public Double[] getColumn(Integer column)
+    {
+        Double[] columnValues = new Double[this.data.length];
+        for(Integer i=0; i < this.data.length; i++)
+        {
+            columnValues[i] = this.data[i][column];
+        }
+        return columnValues;
+    }
+    
+    @Override
+    public String toString()
+    {
+        String retVal = "";
+        for(Integer i=0;i<this.data.length;i++)
+        {
+            retVal += i + "";
+            for(Integer j = 0; j < this.data[i].length; j++)
+            {
+                retVal += "\t" + this.data[i][j];
+            }
+            retVal += "\n";
+        }
+        return retVal;
+    }
+
+    /**
+     * @return the longitude
+     */
+    public Double getLongitude() {
+        return longitude;
+    }
+
+    /**
+     * @param longitude the longitude to set
+     */
+    public void setLongitude(Double longitude) {
+        this.longitude = longitude;
+    }
+
+    /**
+     * @return the latitude
+     */
+    public Double getLatitude() {
+        return latitude;
+    }
+
+    /**
+     * @param latitude the latitude to set
+     */
+    public void setLatitude(Double latitude) {
+        this.latitude = latitude;
+    }
+
+    /**
+     * @return the altitude
+     */
+    public Double getAltitude() {
+        return altitude;
+    }
+
+    /**
+     * @param altitude the altitude to set
+     */
+    public void setAltitude(Double altitude) {
+        this.altitude = altitude;
+    }
+}
diff --git a/src/main/java/net/ipmdecisions/model/entity/ModelOutput.java b/src/main/java/net/ipmdecisions/model/entity/ModelOutput.java
new file mode 100644
index 0000000000000000000000000000000000000000..ef76c25d08ca8c365d506b4299ff5cb53bee3d58
--- /dev/null
+++ b/src/main/java/net/ipmdecisions/model/entity/ModelOutput.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2020 NIBIO <http://www.nibio.no/>. 
+ * 
+ * This file is part of VIPSCommon.
+ * VIPSCommon is free software: you can redistribute it and/or modify
+ * it under the terms of the NIBIO Open Source License as published by 
+ * NIBIO, either version 1 of the License, or (at your option) any
+ * later version.
+ * 
+ * VIPSCommon is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * NIBIO Open Source License for more details.
+ * 
+ * You should have received a copy of the NIBIO Open Source License
+ * along with VIPSCommon.  If not, see <http://www.nibio.no/licenses/>.
+ * 
+ */
+
+package net.ipmdecisions.model.entity;
+
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 
+ * @copyright 2020 <a href="http://www.nibio.no/">NIBIO</a>
+ * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
+ */
+public class ModelOutput {
+    private Instant timeStart;
+    private Instant timeEnd;
+    private Integer interval; 
+    private String[] resultParameters;
+    private List<LocationResult> locationResult;
+
+    /**
+     * @return the timeStart
+     */
+    public Instant getTimeStart() {
+        return timeStart;
+    }
+    
+    
+    /**
+     * @param timeStart the timeStart to set
+     */
+    public void setTimeStart(Instant timeStart) {
+        this.timeStart = timeStart;
+    }
+
+    /**
+     * @return the timeEnd
+     */
+    public Instant getTimeEnd() {
+        return timeEnd;
+    }
+    
+
+    /**
+     * @param timeEnd the timeEnd to set
+     */
+    public void setTimeEnd(Instant timeEnd) {
+        this.timeEnd = timeEnd;
+    }
+
+    /**
+     * @return the interval
+     */
+    public Integer getInterval() {
+        return interval;
+    }
+
+    /**
+     * @param interval the interval to set
+     */
+    public void setInterval(Integer interval) {
+        this.interval = interval;
+    }
+
+    /**
+     * @return the resultParameters
+     */
+    public String[] getResultParameters() {
+        return resultParameters;
+    }
+
+    /**
+     * @param resultParameters the resultParameters to set
+     */
+    public void setResultParameters(String[] resultParameters) {
+        this.resultParameters = resultParameters;
+    }
+
+    /**
+     * @return the locationResult
+     */
+    public List<LocationResult> getLocationResult() {
+        return locationResult;
+    }
+
+    /**
+     * @param locationResult the locationResult to set
+     */
+    public void setLocationResult(List<LocationResult> locationResult) {
+        this.locationResult = locationResult;
+    }
+    
+    public void addLocationResult(LocationResult locationResult) {
+        if (this.locationResult == null)
+        {
+            this.locationResult = new ArrayList<>();
+        }
+        this.locationResult.add(locationResult);
+    }
+}
diff --git a/src/main/java/no/nibio/vips/ipmdecisions/DataTransformer.java b/src/main/java/no/nibio/vips/ipmdecisions/DataTransformer.java
index c4dceed1e594ef10cb8b177065258912215d8a45..189cfae0fe2a981ae82fd32b5c1bfed10a5fe034 100644
--- a/src/main/java/no/nibio/vips/ipmdecisions/DataTransformer.java
+++ b/src/main/java/no/nibio/vips/ipmdecisions/DataTransformer.java
@@ -21,10 +21,17 @@ package no.nibio.vips.ipmdecisions;
 
 import java.time.Instant;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import net.ipmdecisions.model.entity.LocationResult;
+import net.ipmdecisions.model.entity.ModelOutput;
 import net.ipmdecisions.weather.entity.LocationWeatherData;
 import net.ipmdecisions.weather.entity.WeatherData;
+import no.nibio.vips.entity.Result;
 import no.nibio.vips.entity.WeatherObservation;
 
 /**
@@ -60,4 +67,64 @@ public class DataTransformer {
         return retVal;
     }
 
+    /**
+     * Convert VIPS Result list to a IPM Decisions model output object
+     * @param VIPSResults
+     * @return 
+     */
+    public ModelOutput getIPMDecisionsModelOutput(List<Result> VIPSResults){
+        // Loop through once first to 
+        // a) Detect the max frequency between results and 
+        // b) check all possible result parameters
+        Collections.sort(VIPSResults);
+        Set<String> resultParameters = new HashSet<>();
+        resultParameters.add("WARNING_STATUS");
+        Long minSecondsBetween = null;
+        Long lastTime = null;
+        for(Result r:VIPSResults)
+        {
+            resultParameters.addAll(r.getKeys());
+            if(lastTime != null)
+            {
+                minSecondsBetween = minSecondsBetween != null ? Math.min(minSecondsBetween, (r.getValidTimeStart().getTime() - lastTime)/1000)
+                        :(r.getValidTimeStart().getTime() - lastTime)/1000;
+            }
+            lastTime = r.getValidTimeStart().getTime();
+        }
+        
+        String[] VIPSResultParameters = resultParameters.stream().toArray(String[] ::new);
+        String[] IPMResultParameters = new String[VIPSResultParameters.length];
+        for(int i=0;i<VIPSResultParameters.length;i++)
+        {
+            String[] parts = VIPSResultParameters[i].split("\\.");
+            IPMResultParameters[i] = parts[parts.length-1];
+        }
+        
+        // Build the result
+        ModelOutput retVal = new ModelOutput();
+        retVal.setInterval(minSecondsBetween.intValue());
+        retVal.setResultParameters(IPMResultParameters);
+        retVal.setTimeStart(VIPSResults.get(0).getValidTimeStart().toInstant());
+        retVal.setTimeEnd(VIPSResults.get(VIPSResults.size()-1).getValidTimeStart().toInstant());
+        LocationResult locationResult = new LocationResult();
+        Long rows = 1 + (retVal.getTimeEnd().getEpochSecond() - retVal.getTimeStart().getEpochSecond()) / retVal.getInterval();
+        Double[][] data = new Double[rows.intValue()][retVal.getResultParameters().length]; // TODO Set correct dimensions
+        for(Result r:VIPSResults)
+        {
+            // Calculate which row, based on 
+            Long row = (r.getValidTimeStart().getTime()/1000 - retVal.getTimeStart().getEpochSecond()) / retVal.getInterval();
+            // Using the ordering in the resultParameters
+            for(int i=0;i<retVal.getResultParameters().length;i++)
+            {
+                data[row.intValue()][i] = VIPSResultParameters[i].equals("WARNING_STATUS") ? 
+                        r.getWarningStatus()
+                        : VIPSResultParameters[i] != null ? 
+                            Double.valueOf(r.getAllValues().get(VIPSResultParameters[i]))
+                            : null;
+            }
+        } 
+        locationResult.setData(data);
+        retVal.addLocationResult(locationResult);
+        return retVal;
+    }
 }