All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.integratedmodelling.engine.time.functions.TIME Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 *  Copyright (C) 2007, 2015:
 *  
 *    - Ferdinando Villa 
 *    - integratedmodelling.org
 *    - any other authors listed in @author annotations
 *
 *    All rights reserved. This file is part of the k.LAB software suite,
 *    meant to enable modular, collaborative, integrated 
 *    development of interoperable data and model components. For
 *    details, see http://integratedmodelling.org.
 *    
 *    This program is free software; you can redistribute it and/or
 *    modify it under the terms of the Affero General Public License 
 *    Version 3 or any later version.
 *
 *    This program 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
 *    Affero General Public License for more details.
 *  
 *     You should have received a copy of the Affero General Public License
 *     along with this program; if not, write to the Free Software
 *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *     The license is also available at: https://www.gnu.org/licenses/agpl.html
 *******************************************************************************/
package org.integratedmodelling.engine.time.functions;

import java.util.Map;

import org.integratedmodelling.api.knowledge.IConcept;
import org.integratedmodelling.api.knowledge.IExpression;
import org.integratedmodelling.api.monitoring.IMonitor;
import org.integratedmodelling.api.services.annotations.Prototype;
import org.integratedmodelling.api.time.ITemporalExtent;
import org.integratedmodelling.common.kim.expr.CodeExpression;
import org.integratedmodelling.common.vocabulary.NS;
import org.integratedmodelling.engine.time.extents.InfiniteTemporalGrid;
import org.integratedmodelling.engine.time.extents.InfiniteTemporalGridBoundedStart;
import org.integratedmodelling.engine.time.extents.RegularTemporalGrid;
import org.integratedmodelling.engine.time.literals.DurationValue;
import org.integratedmodelling.engine.time.literals.PeriodValue;
import org.integratedmodelling.engine.time.literals.TimeValue;
import org.integratedmodelling.exceptions.KlabException;
import org.integratedmodelling.exceptions.KlabRuntimeException;
import org.integratedmodelling.exceptions.KlabValidationException;
import org.joda.time.DateTime;

@Prototype(
        id = "time",
        args = {
                "# start",
                // int allowed to mean a year
                Prototype.TEXT,
                "# end",
                // int allowed to mean a year
                Prototype.TEXT,
                "# step",
                Prototype.TEXT,
                "# duration",
                Prototype.TEXT,
                "# year",
                Prototype.INT },
        returnTypes = { NS.TIME_DOMAIN })
public class TIME extends CodeExpression implements IExpression {

    /*
     * example: observe ... over time( start=2013-01-01, end=2014-01-01, resolution="1 d"
     * );
     */
    @Override
    public ITemporalExtent eval(Map parameters, IMonitor monitor, IConcept... context)
            throws KlabException {

        ITemporalExtent result = null;
        TimeValue start = null;
        TimeValue end = null;

        /*
         * support simple year specification without start/end
         */
        if (parameters.containsKey("year")) {
            int year = (int) Double.parseDouble(parameters.get("year").toString());
            start = new TimeValue(new DateTime(year + "-01-01"));
            end = new TimeValue(new DateTime((year + 1) + "-01-01"));
        } else {
            start = getInstant("start", parameters);
            end = getInstant("end", parameters);
        }

        DurationValue duration = getDuration("duration", parameters);
        DurationValue resolution = getDuration("step", parameters);

        if (end == null && duration == null && resolution == null) {
            // just a placeholder for the notion of time. Return an undescript time
            // extent.
            return new RegularTemporalGrid();
        }

        if (end == null && duration == null && resolution != null) {
            // unbounded time period (simulation will have to set the limits)
            if (start == null) {
                // unbounded start & end
                result = new InfiniteTemporalGrid(resolution.getMilliseconds());
            } else {
                // unbounded end
                result = new InfiniteTemporalGridBoundedStart(start.getMillis(), resolution
                        .getMilliseconds());
            }
        } else {
            // guaranteed either end != null or duration != null

            if (start == null && (end == null || duration == null)) {
                // not anchored in time. Default to "starting right now"
                // TODO this doesn't make sense - most raw data will be in the past,
                // meaning this assumption
                // forces coverage == 0.
                start = new TimeValue();
            }

            // guaranteed at most one of start, end, duration are null

            if (start == null && duration != null) {
                start = new TimeValue(end.getMillis() - duration.getMilliseconds());
            } else if (end == null && duration != null) {
                end = new TimeValue(start.getMillis() + duration.getMilliseconds());
            } else if (duration == null && start != null && end != null) {
                duration = new DurationValue(end.getMillis() - start.getMillis());
            }

            // guaranteed start, end, duration are all non-null

            if (duration.getMilliseconds() != end.getMillis() - start.getMillis()) {
                throw new KlabValidationException("'start', 'end', and 'duration' were all given for time(), and their values were not compatible.");
            }

            if (start.compareTo(end) > 0) {
                throw new KlabValidationException("'start' must be before 'end' (got a negative duration) for time().");
            }

            if (resolution == null || resolution.getMilliseconds() >= duration.getMilliseconds()) {
                // only 1 period to generate, so create a PeriodValue
                result = new PeriodValue(start.getMillis(), end.getMillis());
            } else {
                // multiple periods to generate
                result = new RegularTemporalGrid(start, end, resolution.getMilliseconds());
            }
        }

        return result;
    }

    private DurationValue getDuration(String key, Map parameters) {
        DurationValue result = null;
        if (parameters.get(key) != null) {
            Object param = parameters.get(key);
            if (param instanceof Long) {
                result = new DurationValue((Long) param);
            } else if (param instanceof Double) {
                result = new DurationValue(((Double) param).longValue());
            } else {
                try {
                    result = new DurationValue(param.toString());
                } catch (KlabValidationException e) {
                    throw new KlabRuntimeException(e);
                }
            }
        }
//        String parameter = getParameterOrNull(key, parameters);
//        if (parameter != null) {
//            try {
//                result = new DurationValue(parameter);
//            } catch (KlabValidationException e) {
//                // bad formatting. leave result null.
//                /*
//                 * FIXME actually this should throw an exception (but in the client, which
//                 * is not using actual function implementations at the moment).
//                 */
//                e.printStackTrace();
//            }
//        }
        return result;
    }

    private TimeValue getInstant(String key, Map parameters)
            throws KlabValidationException {
        TimeValue result = null;
        if (parameters.get(key) != null) {
            Object param = parameters.get(key);
            if (param instanceof Long) {
                result = new TimeValue((Long) param);
            } else if (param instanceof Double) {
                result = new TimeValue(((Double) param).intValue());
            } else {
                result = new TimeValue(param.toString());
            }
        }
        return result;
    }

//    private String getParameterOrNull(String key, Map parameters) {
//        Object ret = parameters.containsKey(key) ? parameters.get(key) : null;
//        if (ret instanceof Double) {
//            // we don't need doubles anywhere, but if we have numbers (e.g. for years), we
//            // want them in int
//            // format.
//            ret = ((Double) ret).intValue();
//        }
//        return ret == null ? null : ret.toString();
//    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy